1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
26 // File: vogl_entrypoints.cpp
27 #include "vogl_common.h"
28 #include "vogl_console.h"
30 //----------------------------------------------------------------------------------------------------------------------
32 //----------------------------------------------------------------------------------------------------------------------
33 static vogl_gl_get_proc_address_helper_func_ptr_t g_vogl_pGet_proc_address_helper_func;
35 actual_gl_entrypoints_t g_vogl_actual_gl_entrypoints;
36 entrypoint_name_hash_map_t g_vogl_entrypoint_hashmap;
38 // The "direct" pointers are not wrapped, they go STRAIGHT to the driver. The non-direct are wrapped with optional callbacks.
39 vogl_void_func_ptr_t g_vogl_actual_gl_entrypoint_direct_func_ptrs[VOGL_NUM_ENTRYPOINTS];
40 vogl_void_func_ptr_t g_vogl_actual_gl_entrypoint_func_ptrs[VOGL_NUM_ENTRYPOINTS];
42 static vogl_gl_func_prolog_epilog_func_t g_gl_func_prolog_func_ptr;
43 static void *g_gl_func_prolog_func_user_data;
45 static vogl_gl_func_prolog_epilog_func_t g_gl_func_epilog_func_ptr;
46 static void *g_gl_func_epilog_func_user_data;
48 //----------------------------------------------------------------------------------------------------------------------
49 // Define direct GL/GLX wrapper funcs, which allows us to intercept every GL/GLX call made be us, and optionally call
50 // a user provided prolog/epilog funcs. This is where the *actual* GL/GLX driver funcs are called.
51 //----------------------------------------------------------------------------------------------------------------------
52 #define DEF_PROTO(exported, category, ret, ret_type, num_params, func_name, args, params) \
53 static ret VOGL_GLUER(vogl_direct_wrapper_, func_name) args \
55 void *pStack_data = NULL; \
56 if (g_gl_func_prolog_func_ptr) \
57 g_gl_func_prolog_func_ptr(VOGL_ENTRYPOINT_##func_name, g_gl_func_prolog_func_user_data, &pStack_data); \
58 ret result = g_vogl_actual_gl_entrypoints.m_##func_name##_direct params; \
59 if (g_gl_func_epilog_func_ptr) \
60 g_gl_func_epilog_func_ptr(VOGL_ENTRYPOINT_##func_name, g_gl_func_epilog_func_user_data, &pStack_data); \
64 #define DEF_PROTO_VOID(exported, category, ret, ret_type, num_params, func_name, args, params) \
65 static void VOGL_GLUER(vogl_direct_wrapper_, func_name) args \
67 void *pStack_data = NULL; \
68 if (g_gl_func_prolog_func_ptr) \
69 g_gl_func_prolog_func_ptr(VOGL_ENTRYPOINT_##func_name, g_gl_func_prolog_func_user_data, &pStack_data); \
70 g_vogl_actual_gl_entrypoints.m_##func_name##_direct params; \
71 if (g_gl_func_epilog_func_ptr) \
72 g_gl_func_epilog_func_ptr(VOGL_ENTRYPOINT_##func_name, g_gl_func_epilog_func_user_data, &pStack_data); \
75 #include "gl_glx_protos.inc"
77 //----------------------------------------------------------------------------------------------------------------------
78 // Function vogl_init_actual_gl_entrypoints
79 //----------------------------------------------------------------------------------------------------------------------
80 void vogl_init_actual_gl_entrypoints(vogl_gl_get_proc_address_helper_func_ptr_t pGet_proc_address_helper_func, bool wrap_all_gl_calls)
82 VOGL_VERIFY(pGet_proc_address_helper_func);
84 g_vogl_pGet_proc_address_helper_func = pGet_proc_address_helper_func;
86 #define DEF_PROTO_UNIVERSAL(category, ret, ret_type, num_params, name, args, params) \
88 vogl_void_func_ptr_t pFunc = g_vogl_pGet_proc_address_helper_func(#name); \
89 g_vogl_actual_gl_entrypoint_direct_func_ptrs[VOGL_ENTRYPOINT_##name] = pFunc; \
90 g_vogl_actual_gl_entrypoints.m_##name##_direct = reinterpret_cast<name##_func_ptr_t>(pFunc); \
93 if (wrap_all_gl_calls) \
95 g_vogl_actual_gl_entrypoint_func_ptrs[VOGL_ENTRYPOINT_##name] = reinterpret_cast<vogl_void_func_ptr_t>(VOGL_GLUER(vogl_direct_wrapper_, name)); \
96 g_vogl_actual_gl_entrypoints.m_##name = VOGL_GLUER(vogl_direct_wrapper_, name); \
100 g_vogl_actual_gl_entrypoint_func_ptrs[VOGL_ENTRYPOINT_##name] = reinterpret_cast<vogl_void_func_ptr_t>(pFunc); \
101 g_vogl_actual_gl_entrypoints.m_##name = reinterpret_cast<name##_func_ptr_t>(pFunc); \
106 #define DEF_PROTO_EXPORTED(category, ret, ret_type, num_params, name, args, params) DEF_PROTO_UNIVERSAL(category, ret, ret_type, num_params, name, arg, params)
107 #define DEF_PROTO_EXPORTED_VOID(category, ret, ret_type, num_params, name, args, params) DEF_PROTO_UNIVERSAL(category, ret, ret_type, num_params, name, arg, params)
109 #define DEF_PROTO_INTERNAL(category, ret, ret_type, num_params, name, args, params) DEF_PROTO_UNIVERSAL(category, ret, ret_type, num_params, name, arg, params)
110 #define DEF_PROTO_INTERNAL_VOID(category, ret, ret_type, num_params, name, args, params) DEF_PROTO_UNIVERSAL(category, ret, ret_type, num_params, name, arg, params)
112 #define DEF_PROTO(exported, category, ret, ret_type, num_params, name, args, params) exported(category, ret, ret_type, num_params, name, args, params)
113 #define DEF_PROTO_VOID(exported, category, ret, ret_type, num_params, name, args, params) exported(category, ret, ret_type, num_params, name, args, params)
114 #include "gl_glx_protos.inc"
115 #undef DEF_PROTO_UNIVERSAL
118 //----------------------------------------------------------------------------------------------------------------------
119 // Define gl/glx entrypoint desc tables
120 //----------------------------------------------------------------------------------------------------------------------
121 #define DEF_PROTO_EXPORTED_VOID true
122 #define DEF_PROTO_EXPORTED true
123 #define DEF_PROTO_INTERNAL_VOID false
124 #define DEF_PROTO_INTERNAL false
125 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type, num_params, name, args, params) \
127 #name, exported, ret_type, num_params, #args, NULL,
128 #define DEF_FUNCTION_INFO(namespace_index, return_spectype, category, version, profile, deprecated, whitelisted, is_nullable, whitelisted_for_displaylists, listable) (vogl_namespace_t) namespace_index, #return_spectype, #category, #version, #profile, #deprecated, whitelisted, is_nullable, whitelisted_for_displaylists, listable
129 #define DEF_FUNCTION_BEGIN_PARAMS
130 #define DEF_FUNCTION_IN_VALUE_PARAM(namespace_index, spectype, type, ctype, name)
131 #define DEF_FUNCTION_IN_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name)
132 #define DEF_FUNCTION_IN_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size)
133 #define DEF_FUNCTION_OUT_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name)
134 #define DEF_FUNCTION_OUT_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size)
135 #define DEF_FUNCTION_END_PARAMS
136 #define DEF_FUNCTION_RETURN(spectype, type, ctype)
137 #define DEF_FUNCTION_END(exported, category, ret, ret_type, num_params, name, args, params) \
138 , false, false, false, 0, 0, NULL \
142 //$ TODO mikesart: backtrace code...
143 gl_entrypoint_desc_t g_vogl_entrypoint_descs[VOGL_NUM_ENTRYPOINTS] =
145 #include "gl_glx_func_descs.inc"
148 //----------------------------------------------------------------------------------------------------------------------
149 // Define gl/glx entrypoint parameter desc tables
150 //----------------------------------------------------------------------------------------------------------------------
151 gl_entrypoint_param_desc_t g_vogl_entrypoint_param_descs[VOGL_NUM_ENTRYPOINTS][VOGL_MAX_ENTRYPOINT_PARAMETERS];
153 static uint g_custom_array_size_macro_indices[] =
155 #include "gl_glx_array_size_macro_func_param_indices.inc"
158 //----------------------------------------------------------------------------------------------------------------------
159 // Function vogl_init_gl_entrypoint_descs
160 //----------------------------------------------------------------------------------------------------------------------
161 void vogl_init_gl_entrypoint_descs()
163 gl_entrypoint_param_desc_t *pDst = &g_vogl_entrypoint_param_descs[0][0];
165 #define DEF_FUNCTION_BEGIN(exported, category, ret, ret_type, num_params, name, args, params)
166 #define DEF_FUNCTION_INFO(namespace_index, return_spectype, category, version, profile, deprecated, is_whitelisted, is_nullable, whitelisted_for_displaylists, listable)
167 #define DEF_FUNCTION_BEGIN_PARAMS \
169 gl_entrypoint_param_desc_t *pCur = pDst;
170 #define DEF_FUNCTION_IN_VALUE_PARAM(namespace_index, spectype, type, ctype, name) \
172 pCur->m_pSpec_type = #spectype; \
173 pCur->m_pName = #name; \
174 pCur->m_ctype = ctype; \
175 pCur->m_class = VOGL_VALUE_PARAM; \
176 pCur->m_input = true; \
177 pCur->m_namespace = (vogl_namespace_t)namespace_index; \
180 #define DEF_FUNCTION_IN_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name) \
182 pCur->m_pSpec_type = #spectype; \
183 pCur->m_pName = #name; \
184 pCur->m_ctype = ctype; \
185 pCur->m_class = VOGL_REF_PARAM; \
186 pCur->m_input = true; \
187 pCur->m_namespace = (vogl_namespace_t)namespace_index; \
190 #define DEF_FUNCTION_IN_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size) \
192 pCur->m_pSpec_type = #spectype; \
193 pCur->m_pName = #name; \
194 pCur->m_ctype = ctype; \
195 pCur->m_class = VOGL_ARRAY_PARAM; \
196 pCur->m_input = true; \
197 pCur->m_pSize = #size; \
198 pCur->m_namespace = (vogl_namespace_t)namespace_index; \
201 #define DEF_FUNCTION_OUT_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name) \
203 pCur->m_pSpec_type = #spectype; \
204 pCur->m_pName = #name; \
205 pCur->m_ctype = ctype; \
206 pCur->m_class = VOGL_ARRAY_PARAM; \
207 pCur->m_input = false; \
208 pCur->m_namespace = (vogl_namespace_t)namespace_index; \
211 #define DEF_FUNCTION_OUT_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size) \
213 pCur->m_pSpec_type = #spectype; \
214 pCur->m_pName = #name; \
215 pCur->m_ctype = ctype; \
216 pCur->m_class = VOGL_ARRAY_PARAM; \
217 pCur->m_input = false; \
218 pCur->m_pSize = #size; \
219 pCur->m_namespace = (vogl_namespace_t)namespace_index; \
222 #define DEF_FUNCTION_END_PARAMS \
223 VOGL_ASSERT((pCur - pDst) <= VOGL_MAX_ENTRYPOINT_PARAMETERS); \
225 #define DEF_FUNCTION_RETURN(spectype, type, ctype)
226 #define DEF_FUNCTION_END(exported, category, ret, ret_type, num_params, name, args, params) pDst += VOGL_MAX_ENTRYPOINT_PARAMETERS;
228 #include "gl_glx_func_descs.inc"
230 for (uint i = 0; i < VOGL_ARRAY_SIZE(g_custom_array_size_macro_indices); i++)
232 uint idx = g_custom_array_size_macro_indices[i];
233 uint func = idx >> 16;
234 uint param = idx & 0xFFFF;
235 VOGL_ASSERT(func < VOGL_NUM_ENTRYPOINTS);
236 VOGL_ASSERT(param < g_vogl_entrypoint_descs[func].m_num_params);
238 g_vogl_entrypoint_param_descs[func][param].m_has_custom_array_size_macro = true;
241 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
243 gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[i];
244 VOGL_ASSERT(desc.m_return_namespace >= VOGL_NAMESPACE_UNKNOWN);
245 VOGL_ASSERT(desc.m_return_namespace < VOGL_TOTAL_NAMESPACES);
247 if (strcmp(desc.m_pName, "glGenTextures") == 0)
249 if (g_vogl_entrypoint_param_descs[i][1].m_namespace != VOGL_NAMESPACE_TEXTURES)
251 vogl_error_printf("%s: vogl_namespace_t enum is bad, please rebuild", VOGL_FUNCTION_NAME);
256 if (desc.m_return_ctype != VOGL_VOID)
258 if ((size_t)g_vogl_process_gl_ctypes[desc.m_return_ctype].m_size < 1)
259 vogl_warning_printf("%s: function %s's return ctype %s is too small\n", VOGL_FUNCTION_NAME, desc.m_pName, g_vogl_process_gl_ctypes[desc.m_return_ctype].m_pName);
261 if ((size_t)g_vogl_process_gl_ctypes[desc.m_return_ctype].m_size > sizeof(uint64_t))
262 vogl_warning_printf("%s: function %s's return ctype %s is too large\n", VOGL_FUNCTION_NAME, desc.m_pName, g_vogl_process_gl_ctypes[desc.m_return_ctype].m_pName);
265 for (uint j = 0; j < desc.m_num_params; j++)
267 if ((size_t)g_vogl_process_gl_ctypes[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_size < 1)
268 vogl_warning_printf("%s: param %u of function %s ctype %s is too small\n", VOGL_FUNCTION_NAME, j, desc.m_pName, g_vogl_process_gl_ctypes[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_pName);
270 if ((size_t)g_vogl_process_gl_ctypes[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_size > sizeof(uint64_t))
271 vogl_warning_printf("%s: param %u of function %s ctype %s is too large\n", VOGL_FUNCTION_NAME, j, desc.m_pName, g_vogl_process_gl_ctypes[g_vogl_entrypoint_param_descs[i][j].m_ctype].m_pName);
274 desc.m_pAPI_prefix = "GL";
276 // FIXME: Add more prefixes as we add platforms. voglgen should probably supply this.
277 // They must correspond with the GL enum prefixes in glx_enum_desc.inc, gl_enum_desc.inc, etc.
278 if ((desc.m_pName[0] == 'w') && (desc.m_pName[1] == 'g') && (desc.m_pName[2] == 'l'))
279 desc.m_pAPI_prefix = "WGL";
280 else if ((desc.m_pName[0] == 'g') && (desc.m_pName[1] == 'l') && (desc.m_pName[2] == 'X'))
281 desc.m_pAPI_prefix = "GLX";
282 else if ((desc.m_pName[0] == 'g') && (desc.m_pName[1] == 'l'))
283 desc.m_pAPI_prefix = "GL";
286 vogl_warning_printf("%s: Unknown function prefix: %s\n", VOGL_FUNCTION_NAME, desc.m_pName);
290 for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
292 g_vogl_entrypoint_hashmap.insert(g_vogl_entrypoint_descs[i].m_pName, static_cast<gl_entrypoint_id_t>(i));
296 //----------------------------------------------------------------------------------------------------------------------
297 // Function vogl_find_entrypoint
298 //----------------------------------------------------------------------------------------------------------------------
299 gl_entrypoint_id_t vogl_find_entrypoint(const dynamic_string &name)
301 entrypoint_name_hash_map_t::const_iterator it(g_vogl_entrypoint_hashmap.find(name));
302 if (it == g_vogl_entrypoint_hashmap.end())
303 return VOGL_ENTRYPOINT_INVALID;
307 //----------------------------------------------------------------------------------------------------------------------
308 // Function vogl_does_entrypoint_refer_to_namespace
309 //----------------------------------------------------------------------------------------------------------------------
310 bool vogl_does_entrypoint_refer_to_namespace(gl_entrypoint_id_t entrypoint_id, vogl_namespace_t namespace_id)
312 VOGL_ASSERT(entrypoint_id < VOGL_NUM_ENTRYPOINTS);
313 VOGL_ASSERT(namespace_id < VOGL_TOTAL_NAMESPACES);
315 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[entrypoint_id];
316 if (desc.m_return_namespace == namespace_id)
319 for (uint i = 0; i < desc.m_num_params; i++)
320 if (g_vogl_entrypoint_param_descs[entrypoint_id][i].m_namespace == namespace_id)
326 //----------------------------------------------------------------------------------------------------------------------
327 // vogl_set_direct_gl_func_prolog
328 //----------------------------------------------------------------------------------------------------------------------
329 void vogl_set_direct_gl_func_prolog(vogl_gl_func_prolog_epilog_func_t pFunc, void *pUser_data)
331 g_gl_func_prolog_func_ptr = pFunc;
332 g_gl_func_prolog_func_user_data = pUser_data;
335 //----------------------------------------------------------------------------------------------------------------------
336 // vogl_set_direct_gl_func_epilog
337 //----------------------------------------------------------------------------------------------------------------------
338 void vogl_set_direct_gl_func_epilog(vogl_gl_func_prolog_epilog_func_t pFunc, void *pUser_data)
340 g_gl_func_epilog_func_ptr = pFunc;
341 g_gl_func_epilog_func_user_data = pUser_data;