]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_entrypoints.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_entrypoints.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_entrypoints.cpp
27 #include "vogl_common.h"
28 #include "vogl_console.h"
29
30 //----------------------------------------------------------------------------------------------------------------------
31 // Globals
32 //----------------------------------------------------------------------------------------------------------------------
33 static vogl_gl_get_proc_address_helper_func_ptr_t g_vogl_pGet_proc_address_helper_func;
34
35 actual_gl_entrypoints_t g_vogl_actual_gl_entrypoints;
36 entrypoint_name_hash_map_t g_vogl_entrypoint_hashmap;
37
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];
41
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;
44
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;
47
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                                                  \
54     {                                                                                                             \
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); \
61         return result;                                                                                            \
62     }
63
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                                                 \
66     {                                                                                                             \
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); \
73     }
74
75 #include "gl_glx_protos.inc"
76
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)
81 {
82     VOGL_VERIFY(pGet_proc_address_helper_func);
83
84     g_vogl_pGet_proc_address_helper_func = pGet_proc_address_helper_func;
85
86 #define DEF_PROTO_UNIVERSAL(category, ret, ret_type, num_params, name, args, params)                                                                          \
87     {                                                                                                                                                         \
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);                                                           \
91         if (pFunc)                                                                                                                                            \
92         {                                                                                                                                                     \
93             if (wrap_all_gl_calls)                                                                                                                            \
94             {                                                                                                                                                 \
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);                                                               \
97             }                                                                                                                                                 \
98             else                                                                                                                                              \
99             {                                                                                                                                                 \
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);                                                            \
102             }                                                                                                                                                 \
103         }                                                                                                                                                     \
104     }
105
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)
108
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)
111
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
116 }
117
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) \
126     {                                                                                         \
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                                                       \
139     }                                                                                       \
140     ,
141
142 //$ TODO mikesart: backtrace code...
143 gl_entrypoint_desc_t g_vogl_entrypoint_descs[VOGL_NUM_ENTRYPOINTS] =
144     {
145 #include "gl_glx_func_descs.inc"
146     };
147
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];
152
153 static uint g_custom_array_size_macro_indices[] =
154     {
155 #include "gl_glx_array_size_macro_func_param_indices.inc"
156     };
157
158 //----------------------------------------------------------------------------------------------------------------------
159 // Function vogl_init_gl_entrypoint_descs
160 //----------------------------------------------------------------------------------------------------------------------
161 void vogl_init_gl_entrypoint_descs()
162 {
163     gl_entrypoint_param_desc_t *pDst = &g_vogl_entrypoint_param_descs[0][0];
164
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 \
168     {                             \
169         gl_entrypoint_param_desc_t *pCur = pDst;
170 #define DEF_FUNCTION_IN_VALUE_PARAM(namespace_index, spectype, type, ctype, name) \
171     {                                                                             \
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;                     \
178         ++pCur;                                                                   \
179     }
180 #define DEF_FUNCTION_IN_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name) \
181     {                                                                                 \
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;                         \
188         ++pCur;                                                                       \
189     }
190 #define DEF_FUNCTION_IN_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size) \
191     {                                                                                   \
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;                           \
199         ++pCur;                                                                         \
200     }
201 #define DEF_FUNCTION_OUT_REFERENCE_PARAM(namespace_index, spectype, type, ctype, name) \
202     {                                                                                  \
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;                          \
209         ++pCur;                                                                        \
210     }
211 #define DEF_FUNCTION_OUT_ARRAY_PARAM(namespace_index, spectype, type, ctype, name, size) \
212     {                                                                                    \
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;                            \
220         ++pCur;                                                                          \
221     }
222 #define DEF_FUNCTION_END_PARAMS                                    \
223     VOGL_ASSERT((pCur - pDst) <= VOGL_MAX_ENTRYPOINT_PARAMETERS); \
224     }
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;
227
228 #include "gl_glx_func_descs.inc"
229
230     for (uint i = 0; i < VOGL_ARRAY_SIZE(g_custom_array_size_macro_indices); i++)
231     {
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);
237
238         g_vogl_entrypoint_param_descs[func][param].m_has_custom_array_size_macro = true;
239     }
240
241     for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
242     {
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);
246
247         if (strcmp(desc.m_pName, "glGenTextures") == 0)
248         {
249             if (g_vogl_entrypoint_param_descs[i][1].m_namespace != VOGL_NAMESPACE_TEXTURES)
250             {
251                 vogl_error_printf("%s: vogl_namespace_t enum is bad, please rebuild", VOGL_FUNCTION_NAME);
252                 exit(EXIT_FAILURE);
253             }
254         }
255
256         if (desc.m_return_ctype != VOGL_VOID)
257         {
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);
260
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);
263         }
264
265         for (uint j = 0; j < desc.m_num_params; j++)
266         {
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);
269
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);
272         }
273
274         desc.m_pAPI_prefix = "GL";
275
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";
284         else
285         {
286             vogl_warning_printf("%s: Unknown function prefix: %s\n", VOGL_FUNCTION_NAME, desc.m_pName);
287         }
288     }
289
290     for (uint i = 0; i < VOGL_NUM_ENTRYPOINTS; i++)
291     {
292         g_vogl_entrypoint_hashmap.insert(g_vogl_entrypoint_descs[i].m_pName, static_cast<gl_entrypoint_id_t>(i));
293     }
294 }
295
296 //----------------------------------------------------------------------------------------------------------------------
297 // Function vogl_find_entrypoint
298 //----------------------------------------------------------------------------------------------------------------------
299 gl_entrypoint_id_t vogl_find_entrypoint(const dynamic_string &name)
300 {
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;
304     return it->second;
305 }
306
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)
311 {
312     VOGL_ASSERT(entrypoint_id < VOGL_NUM_ENTRYPOINTS);
313     VOGL_ASSERT(namespace_id < VOGL_TOTAL_NAMESPACES);
314
315     const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[entrypoint_id];
316     if (desc.m_return_namespace == namespace_id)
317         return true;
318
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)
321             return true;
322
323     return false;
324 }
325
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)
330 {
331     g_gl_func_prolog_func_ptr = pFunc;
332     g_gl_func_prolog_func_user_data = pUser_data;
333 }
334
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)
339 {
340     g_gl_func_epilog_func_ptr = pFunc;
341     g_gl_func_epilog_func_user_data = pUser_data;
342 }