2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * \file glapi_getproc.c
28 * Code for implementing glXGetProcAddress(), etc.
29 * This was originally in glapi.c but refactored out.
35 #include "main/glheader.h"
36 #include "main/compiler.h"
38 #include "glapioffsets.h"
39 #include "glapitable.h"
43 fill_in_entrypoint_offset(_glapi_proc entrypoint
, GLuint offset
);
47 * strdup() is actually not a standard ANSI C or POSIX routine.
48 * Irix will not define it if ANSI mode is in effect.
51 str_dup(const char *str
)
54 copy
= (char*) malloc(strlen(str
) + 1);
63 #if defined(USE_X64_64_ASM) && defined(GLX_USE_TLS)
64 # define DISPATCH_FUNCTION_SIZE 16
65 #elif defined(USE_X86_ASM)
66 # if defined(THREADS) && !defined(GLX_USE_TLS)
67 # define DISPATCH_FUNCTION_SIZE 32
69 # define DISPATCH_FUNCTION_SIZE 16
73 #if !defined(DISPATCH_FUNCTION_SIZE) && !defined(XFree86Server) && !defined(XGLServer)
74 # define NEED_FUNCTION_POINTER
77 /* The code in this file is auto-generated with Python */
82 * Search the table of static entrypoint functions for the named function
83 * and return the corresponding glprocs_table_t entry.
85 static const glprocs_table_t
*
86 find_entry( const char * n
)
89 for (i
= 0; static_functions
[i
].Name_offset
>= 0; i
++) {
90 const char *testName
= gl_string_table
+ static_functions
[i
].Name_offset
;
92 /* skip the "m" prefix on the name */
93 if (strcmp(testName
, n
+ 1) == 0)
95 if (strcmp(testName
, n
) == 0)
98 return &static_functions
[i
];
106 * Return dispatch table offset of the named static (built-in) function.
107 * Return -1 if function not found.
110 get_static_proc_offset(const char *funcName
)
112 const glprocs_table_t
* const f
= find_entry( funcName
);
120 #if !defined(XFree86Server) && !defined(XGLServer)
123 #if defined( GLX_USE_TLS )
124 extern GLubyte gl_dispatch_functions_start
[];
125 extern GLubyte gl_dispatch_functions_end
[];
127 extern const GLubyte gl_dispatch_functions_start
[];
130 #endif /* USE_X86_ASM */
134 * Return dispatch function address for the named static (built-in) function.
135 * Return NULL if function not found.
138 get_static_proc_address(const char *funcName
)
140 const glprocs_table_t
* const f
= find_entry( funcName
);
142 #if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING)
143 return (f
->Address
== NULL
)
144 ? (_glapi_proc
) (gl_dispatch_functions_start
145 + (DISPATCH_FUNCTION_SIZE
* f
->Offset
))
147 #elif defined(DISPATCH_FUNCTION_SIZE)
148 return (_glapi_proc
) (gl_dispatch_functions_start
149 + (DISPATCH_FUNCTION_SIZE
* f
->Offset
));
159 #endif /* !defined(XFree86Server) && !defined(XGLServer) */
164 * Return the name of the function at the given offset in the dispatch
165 * table. For debugging only.
168 get_static_proc_name( GLuint offset
)
171 for (i
= 0; static_functions
[i
].Name_offset
>= 0; i
++) {
172 if (static_functions
[i
].Offset
== offset
) {
173 return gl_string_table
+ static_functions
[i
].Name_offset
;
181 /**********************************************************************
182 * Extension function management.
187 * Track information about a function added to the GL API.
189 struct _glapi_function
{
191 * Name of the function.
197 * Text string that describes the types of the parameters passed to the
198 * named function. Parameter types are converted to characters using the
200 * - 'i' for \c GLint, \c GLuint, and \c GLenum
201 * - 'p' for any pointer type
202 * - 'f' for \c GLfloat and \c GLclampf
203 * - 'd' for \c GLdouble and \c GLclampd
205 const char * parameter_signature
;
209 * Offset in the dispatch table where the pointer to the real function is
210 * located. If the driver has not requested that the named function be
211 * added to the dispatch table, this will have the value ~0.
213 unsigned dispatch_offset
;
217 * Pointer to the dispatch stub for the named function.
220 * The semantic of this field should be changed slightly. Currently, it
221 * is always expected to be non-\c NULL. However, it would be better to
222 * only allocate the entry-point stub when the application requests the
223 * function via \c glXGetProcAddress. This would save memory for all the
224 * functions that the driver exports but that the application never wants
227 _glapi_proc dispatch_stub
;
231 static struct _glapi_function ExtEntryTable
[MAX_EXTENSION_FUNCS
];
232 static GLuint NumExtEntryPoints
= 0;
235 extern void __glapi_sparc_icache_flush(unsigned int *);
239 * Generate a dispatch function (entrypoint) which jumps through
240 * the given slot number (offset) in the current dispatch table.
241 * We need assembly language in order to accomplish this.
244 generate_entrypoint(GLuint functionOffset
)
246 #if defined(USE_X86_ASM)
247 /* 32 is chosen as something of a magic offset. For x86, the dispatch
248 * at offset 32 is the first one where the offset in the
249 * "jmp OFFSET*4(%eax)" can't be encoded in a single byte.
251 const GLubyte
* const template_func
= gl_dispatch_functions_start
252 + (DISPATCH_FUNCTION_SIZE
* 32);
253 GLubyte
* const code
= (GLubyte
*) malloc(DISPATCH_FUNCTION_SIZE
);
256 if ( code
!= NULL
) {
257 (void) memcpy(code
, template_func
, DISPATCH_FUNCTION_SIZE
);
258 fill_in_entrypoint_offset( (_glapi_proc
) code
, functionOffset
);
261 return (_glapi_proc
) code
;
262 #elif defined(USE_SPARC_ASM) && (defined(PTHREADS) || defined(GLX_USE_TLS))
263 static const unsigned int template[] = {
264 0x07000000, /* sethi %hi(0), %g3 */
265 0x8210000f, /* mov %o7, %g1 */
266 0x40000000, /* call */
267 0x9e100001, /* mov %g1, %o7 */
270 extern unsigned int __glapi_sparc_tls_stub
;
271 unsigned long call_dest
= (unsigned long ) &__glapi_sparc_tls_stub
;
273 extern unsigned int __glapi_sparc_pthread_stub
;
274 unsigned long call_dest
= (unsigned long ) &__glapi_sparc_pthread_stub
;
276 unsigned int *code
= (unsigned int *) malloc(sizeof(template));
278 code
[0] = template[0] | (functionOffset
& 0x3fffff);
279 code
[1] = template[1];
280 __glapi_sparc_icache_flush(&code
[0]);
281 code
[2] = template[2] |
282 (((call_dest
- ((unsigned long) &code
[2]))
284 code
[3] = template[3];
285 __glapi_sparc_icache_flush(&code
[2]);
287 return (_glapi_proc
) code
;
289 (void) functionOffset
;
291 #endif /* USE_*_ASM */
296 * This function inserts a new dispatch offset into the assembly language
297 * stub that was generated with the preceeding function.
300 fill_in_entrypoint_offset(_glapi_proc entrypoint
, GLuint offset
)
302 #if defined(USE_X86_ASM)
303 GLubyte
* const code
= (GLubyte
*) entrypoint
;
305 #if DISPATCH_FUNCTION_SIZE == 32
306 *((unsigned int *)(code
+ 11)) = 4 * offset
;
307 *((unsigned int *)(code
+ 22)) = 4 * offset
;
308 #elif DISPATCH_FUNCTION_SIZE == 16 && defined( GLX_USE_TLS )
309 *((unsigned int *)(code
+ 8)) = 4 * offset
;
310 #elif DISPATCH_FUNCTION_SIZE == 16
311 *((unsigned int *)(code
+ 7)) = 4 * offset
;
313 # error Invalid DISPATCH_FUNCTION_SIZE!
316 #elif defined(USE_SPARC_ASM)
317 unsigned int *code
= (unsigned int *) entrypoint
;
318 code
[0] &= ~0x3fffff;
319 code
[0] |= (offset
* sizeof(void *)) & 0x3fffff;
320 __glapi_sparc_icache_flush(&code
[0]);
323 /* an unimplemented architecture */
327 #endif /* USE_*_ASM */
332 * Generate new entrypoint
334 * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver
335 * calls \c _glapi_add_dispatch we'll put in the proper offset. If that
336 * never happens, and the user calls this function, he'll segfault. That's
337 * what you get when you try calling a GL function that doesn't really exist.
339 * \param funcName Name of the function to create an entry-point for.
341 * \sa _glapi_add_entrypoint
344 static struct _glapi_function
*
345 add_function_name( const char * funcName
)
347 struct _glapi_function
* entry
= NULL
;
349 if (NumExtEntryPoints
< MAX_EXTENSION_FUNCS
) {
350 _glapi_proc entrypoint
= generate_entrypoint(~0);
351 if (entrypoint
!= NULL
) {
352 entry
= & ExtEntryTable
[NumExtEntryPoints
];
354 ExtEntryTable
[NumExtEntryPoints
].name
= str_dup(funcName
);
355 ExtEntryTable
[NumExtEntryPoints
].parameter_signature
= NULL
;
356 ExtEntryTable
[NumExtEntryPoints
].dispatch_offset
= ~0;
357 ExtEntryTable
[NumExtEntryPoints
].dispatch_stub
= entrypoint
;
367 * Fill-in the dispatch stub for the named function.
369 * This function is intended to be called by a hardware driver. When called,
370 * a dispatch stub may be created created for the function. A pointer to this
371 * dispatch function will be returned by glXGetProcAddress.
373 * \param function_names Array of pointers to function names that should
374 * share a common dispatch offset.
375 * \param parameter_signature String representing the types of the parameters
376 * passed to the named function. Parameter types
377 * are converted to characters using the following
379 * - 'i' for \c GLint, \c GLuint, and \c GLenum
380 * - 'p' for any pointer type
381 * - 'f' for \c GLfloat and \c GLclampf
382 * - 'd' for \c GLdouble and \c GLclampd
385 * The offset in the dispatch table of the named function. A pointer to the
386 * driver's implementation of the named function should be stored at
387 * \c dispatch_table[\c offset]. Return -1 if error/problem.
389 * \sa glXGetProcAddress
392 * This function can only handle up to 8 names at a time. As far as I know,
393 * the maximum number of names ever associated with an existing GL function is
394 * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
395 * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
396 * too painful of a limitation.
399 * Determine whether or not \c parameter_signature should be allowed to be
400 * \c NULL. It doesn't seem like much of a hardship for drivers to have to
401 * pass in an empty string.
404 * Determine if code should be added to reject function names that start with
408 * Add code to compare \c parameter_signature with the parameter signature of
409 * a static function. In order to do that, we need to find a way to \b get
410 * the parameter signature of a static function.
414 _glapi_add_dispatch( const char * const * function_names
,
415 const char * parameter_signature
)
417 static int next_dynamic_offset
= _gloffset_FIRST_DYNAMIC
;
418 const char * const real_sig
= (parameter_signature
!= NULL
)
419 ? parameter_signature
: "";
420 struct _glapi_function
* entry
[8];
421 GLboolean is_static
[8];
428 (void) memset( is_static
, 0, sizeof( is_static
) );
429 (void) memset( entry
, 0, sizeof( entry
) );
431 for ( i
= 0 ; function_names
[i
] != NULL
; i
++ ) {
432 /* Do some trivial validation on the name of the function.
435 if (!function_names
[i
] || function_names
[i
][0] != 'g' || function_names
[i
][1] != 'l')
438 /* Determine if the named function already exists. If the function does
439 * exist, it must have the same parameter signature as the function
443 new_offset
= get_static_proc_offset(function_names
[i
]);
444 if (new_offset
>= 0) {
445 /* FIXME: Make sure the parameter signatures match! How do we get
446 * FIXME: the parameter signature for static functions?
449 if ( (offset
!= ~0) && (new_offset
!= offset
) ) {
453 is_static
[i
] = GL_TRUE
;
458 for ( j
= 0 ; j
< NumExtEntryPoints
; j
++ ) {
459 if (strcmp(ExtEntryTable
[j
].name
, function_names
[i
]) == 0) {
460 /* The offset may be ~0 if the function name was added by
461 * glXGetProcAddress but never filled in by the driver.
464 if (ExtEntryTable
[j
].dispatch_offset
!= ~0) {
465 if (strcmp(real_sig
, ExtEntryTable
[j
].parameter_signature
)
470 if ( (offset
!= ~0) && (ExtEntryTable
[j
].dispatch_offset
!= offset
) ) {
474 offset
= ExtEntryTable
[j
].dispatch_offset
;
477 entry
[i
] = & ExtEntryTable
[j
];
484 offset
= next_dynamic_offset
;
485 next_dynamic_offset
++;
488 for ( i
= 0 ; function_names
[i
] != NULL
; i
++ ) {
489 if (! is_static
[i
] ) {
490 if (entry
[i
] == NULL
) {
491 entry
[i
] = add_function_name( function_names
[i
] );
492 if (entry
[i
] == NULL
) {
493 /* FIXME: Possible memory leak here.
499 entry
[i
]->parameter_signature
= str_dup(real_sig
);
500 fill_in_entrypoint_offset(entry
[i
]->dispatch_stub
, offset
);
501 entry
[i
]->dispatch_offset
= offset
;
510 * Return offset of entrypoint for named function within dispatch table.
513 _glapi_get_proc_offset(const char *funcName
)
515 /* search extension functions first */
517 for (i
= 0; i
< NumExtEntryPoints
; i
++) {
518 if (strcmp(ExtEntryTable
[i
].name
, funcName
) == 0) {
519 return ExtEntryTable
[i
].dispatch_offset
;
522 /* search static functions */
523 return get_static_proc_offset(funcName
);
529 * Return pointer to the named function. If the function name isn't found
530 * in the name of static functions, try generating a new API entrypoint on
531 * the fly with assembly language.
534 _glapi_get_proc_address(const char *funcName
)
536 struct _glapi_function
* entry
;
540 if (funcName
[0] != 'm' || funcName
[1] != 'g' || funcName
[2] != 'l')
543 if (funcName
[0] != 'g' || funcName
[1] != 'l')
547 /* search extension functions first */
548 for (i
= 0; i
< NumExtEntryPoints
; i
++) {
549 if (strcmp(ExtEntryTable
[i
].name
, funcName
) == 0) {
550 return ExtEntryTable
[i
].dispatch_stub
;
554 #if !defined( XFree86Server ) && !defined( XGLServer )
555 /* search static functions */
557 const _glapi_proc func
= get_static_proc_address(funcName
);
561 #endif /* !defined( XFree86Server ) */
563 entry
= add_function_name(funcName
);
564 return (entry
== NULL
) ? NULL
: entry
->dispatch_stub
;
570 * Return the name of the function at the given dispatch offset.
571 * This is only intended for debugging.
574 _glapi_get_proc_name(GLuint offset
)
579 /* search built-in functions */
580 n
= get_static_proc_name(offset
);
585 /* search added extension functions */
586 for (i
= 0; i
< NumExtEntryPoints
; i
++) {
587 if (ExtEntryTable
[i
].dispatch_offset
== offset
) {
588 return ExtEntryTable
[i
].name
;