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.
28 * Code for implementing glXGetProcAddress(), etc.
29 * This was originally in glapi.c but refactored out.
35 #include "main/glheader.h"
37 #include "glapioffsets.h"
38 #include "glapitable.h"
42 fill_in_entrypoint_offset(_glapi_proc entrypoint
, GLuint offset
);
46 * strdup() is actually not a standard ANSI C or POSIX routine.
47 * Irix will not define it if ANSI mode is in effect.
50 str_dup(const char *str
)
53 copy
= (char*) malloc(strlen(str
) + 1);
62 #if defined(USE_X64_64_ASM) && defined(GLX_USE_TLS)
63 # define DISPATCH_FUNCTION_SIZE 16
64 #elif defined(USE_X86_ASM)
65 # if defined(THREADS) && !defined(GLX_USE_TLS)
66 # define DISPATCH_FUNCTION_SIZE 32
68 # define DISPATCH_FUNCTION_SIZE 16
72 #if !defined(DISPATCH_FUNCTION_SIZE) && !defined(XFree86Server) && !defined(XGLServer)
73 # define NEED_FUNCTION_POINTER
76 /* The code in this file is auto-generated with Python */
81 * Search the table of static entrypoint functions for the named function
82 * and return the corresponding glprocs_table_t entry.
84 static const glprocs_table_t
*
85 find_entry( const char * n
)
88 for (i
= 0; static_functions
[i
].Name_offset
>= 0; i
++) {
89 const char *testName
= gl_string_table
+ static_functions
[i
].Name_offset
;
90 if (strcmp(testName
, n
) == 0) {
91 return &static_functions
[i
];
99 * Return dispatch table offset of the named static (built-in) function.
100 * Return -1 if function not found.
103 get_static_proc_offset(const char *funcName
)
105 const glprocs_table_t
* const f
= find_entry( funcName
);
113 #if !defined(XFree86Server) && !defined(XGLServer)
116 #if defined( GLX_USE_TLS )
117 extern GLubyte gl_dispatch_functions_start
[];
118 extern GLubyte gl_dispatch_functions_end
[];
120 extern const GLubyte gl_dispatch_functions_start
[];
123 #endif /* USE_X86_ASM */
127 * Return dispatch function address for the named static (built-in) function.
128 * Return NULL if function not found.
131 get_static_proc_address(const char *funcName
)
133 const glprocs_table_t
* const f
= find_entry( funcName
);
135 #if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING)
136 return (f
->Address
== NULL
)
137 ? (_glapi_proc
) (gl_dispatch_functions_start
138 + (DISPATCH_FUNCTION_SIZE
* f
->Offset
))
140 #elif defined(DISPATCH_FUNCTION_SIZE)
141 return (_glapi_proc
) (gl_dispatch_functions_start
142 + (DISPATCH_FUNCTION_SIZE
* f
->Offset
));
152 #endif /* !defined(XFree86Server) && !defined(XGLServer) */
157 * Return the name of the function at the given offset in the dispatch
158 * table. For debugging only.
161 get_static_proc_name( GLuint offset
)
164 for (i
= 0; static_functions
[i
].Name_offset
>= 0; i
++) {
165 if (static_functions
[i
].Offset
== offset
) {
166 return gl_string_table
+ static_functions
[i
].Name_offset
;
174 /**********************************************************************
175 * Extension function management.
180 * Track information about a function added to the GL API.
182 struct _glapi_function
{
184 * Name of the function.
190 * Text string that describes the types of the parameters passed to the
191 * named function. Parameter types are converted to characters using the
193 * - 'i' for \c GLint, \c GLuint, and \c GLenum
194 * - 'p' for any pointer type
195 * - 'f' for \c GLfloat and \c GLclampf
196 * - 'd' for \c GLdouble and \c GLclampd
198 const char * parameter_signature
;
202 * Offset in the dispatch table where the pointer to the real function is
203 * located. If the driver has not requested that the named function be
204 * added to the dispatch table, this will have the value ~0.
206 unsigned dispatch_offset
;
210 * Pointer to the dispatch stub for the named function.
213 * The semantic of this field should be changed slightly. Currently, it
214 * is always expected to be non-\c NULL. However, it would be better to
215 * only allocate the entry-point stub when the application requests the
216 * function via \c glXGetProcAddress. This would save memory for all the
217 * functions that the driver exports but that the application never wants
220 _glapi_proc dispatch_stub
;
224 static struct _glapi_function ExtEntryTable
[MAX_EXTENSION_FUNCS
];
225 static GLuint NumExtEntryPoints
= 0;
228 extern void __glapi_sparc_icache_flush(unsigned int *);
232 * Generate a dispatch function (entrypoint) which jumps through
233 * the given slot number (offset) in the current dispatch table.
234 * We need assembly language in order to accomplish this.
237 generate_entrypoint(GLuint functionOffset
)
239 #if defined(USE_X86_ASM)
240 /* 32 is chosen as something of a magic offset. For x86, the dispatch
241 * at offset 32 is the first one where the offset in the
242 * "jmp OFFSET*4(%eax)" can't be encoded in a single byte.
244 const GLubyte
* const template_func
= gl_dispatch_functions_start
245 + (DISPATCH_FUNCTION_SIZE
* 32);
246 GLubyte
* const code
= (GLubyte
*) malloc(DISPATCH_FUNCTION_SIZE
);
249 if ( code
!= NULL
) {
250 (void) memcpy(code
, template_func
, DISPATCH_FUNCTION_SIZE
);
251 fill_in_entrypoint_offset( (_glapi_proc
) code
, functionOffset
);
254 return (_glapi_proc
) code
;
255 #elif defined(USE_SPARC_ASM)
258 static const unsigned int insn_template
[] = {
259 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
260 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
261 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
262 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
263 0x8528b020, /* sllx %g2, 32, %g2 */
264 0xc2584002, /* ldx [%g1 + %g2], %g1 */
265 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
266 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
267 0xc6584002, /* ldx [%g1 + %g2], %g3 */
268 0x81c0c000, /* jmpl %g3, %g0 */
272 static const unsigned int insn_template
[] = {
273 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
274 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
275 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
276 0x81c0c000, /* jmpl %g3, %g0 */
279 #endif /* __arch64__ */
280 unsigned int *code
= (unsigned int *) malloc(sizeof(insn_template
));
281 unsigned long glapi_addr
= (unsigned long) &_glapi_Dispatch
;
283 memcpy(code
, insn_template
, sizeof(insn_template
));
286 code
[0] |= (glapi_addr
>> (32 + 10));
287 code
[1] |= ((glapi_addr
& 0xffffffff) >> 10);
288 __glapi_sparc_icache_flush(&code
[0]);
289 code
[2] |= ((glapi_addr
>> 32) & ((1 << 10) - 1));
290 code
[3] |= (glapi_addr
& ((1 << 10) - 1));
291 __glapi_sparc_icache_flush(&code
[2]);
292 code
[6] |= ((functionOffset
* 8) >> 10);
293 code
[7] |= ((functionOffset
* 8) & ((1 << 10) - 1));
294 __glapi_sparc_icache_flush(&code
[6]);
296 code
[0] |= (glapi_addr
>> 10);
297 code
[1] |= (glapi_addr
& ((1 << 10) - 1));
298 __glapi_sparc_icache_flush(&code
[0]);
299 code
[2] |= (functionOffset
* 4);
300 __glapi_sparc_icache_flush(&code
[2]);
301 #endif /* __arch64__ */
303 return (_glapi_proc
) code
;
305 (void) functionOffset
;
307 #endif /* USE_*_ASM */
312 * This function inserts a new dispatch offset into the assembly language
313 * stub that was generated with the preceeding function.
316 fill_in_entrypoint_offset(_glapi_proc entrypoint
, GLuint offset
)
318 #if defined(USE_X86_ASM)
319 GLubyte
* const code
= (GLubyte
*) entrypoint
;
321 #if DISPATCH_FUNCTION_SIZE == 32
322 *((unsigned int *)(code
+ 11)) = 4 * offset
;
323 *((unsigned int *)(code
+ 22)) = 4 * offset
;
324 #elif DISPATCH_FUNCTION_SIZE == 16 && defined( GLX_USE_TLS )
325 *((unsigned int *)(code
+ 8)) = 4 * offset
;
326 #elif DISPATCH_FUNCTION_SIZE == 16
327 *((unsigned int *)(code
+ 7)) = 4 * offset
;
329 # error Invalid DISPATCH_FUNCTION_SIZE!
332 #elif defined(USE_SPARC_ASM)
334 /* XXX this hasn't been tested! */
335 unsigned int *code
= (unsigned int *) entrypoint
;
337 code
[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
338 code
[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
339 code
[6] |= ((offset
* 8) >> 10);
340 code
[7] |= ((offset
* 8) & ((1 << 10) - 1));
341 __glapi_sparc_icache_flush(&code
[6]);
342 #else /* __arch64__ */
343 code
[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
344 code
[2] |= (offset
* 4);
345 __glapi_sparc_icache_flush(&code
[2]);
346 #endif /* __arch64__ */
350 /* an unimplemented architecture */
354 #endif /* USE_*_ASM */
359 * Generate new entrypoint
361 * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver
362 * calls \c _glapi_add_dispatch we'll put in the proper offset. If that
363 * never happens, and the user calls this function, he'll segfault. That's
364 * what you get when you try calling a GL function that doesn't really exist.
366 * \param funcName Name of the function to create an entry-point for.
368 * \sa _glapi_add_entrypoint
371 static struct _glapi_function
*
372 add_function_name( const char * funcName
)
374 struct _glapi_function
* entry
= NULL
;
376 if (NumExtEntryPoints
< MAX_EXTENSION_FUNCS
) {
377 _glapi_proc entrypoint
= generate_entrypoint(~0);
378 if (entrypoint
!= NULL
) {
379 entry
= & ExtEntryTable
[NumExtEntryPoints
];
381 ExtEntryTable
[NumExtEntryPoints
].name
= str_dup(funcName
);
382 ExtEntryTable
[NumExtEntryPoints
].parameter_signature
= NULL
;
383 ExtEntryTable
[NumExtEntryPoints
].dispatch_offset
= ~0;
384 ExtEntryTable
[NumExtEntryPoints
].dispatch_stub
= entrypoint
;
394 * Fill-in the dispatch stub for the named function.
396 * This function is intended to be called by a hardware driver. When called,
397 * a dispatch stub may be created created for the function. A pointer to this
398 * dispatch function will be returned by glXGetProcAddress.
400 * \param function_names Array of pointers to function names that should
401 * share a common dispatch offset.
402 * \param parameter_signature String representing the types of the parameters
403 * passed to the named function. Parameter types
404 * are converted to characters using the following
406 * - 'i' for \c GLint, \c GLuint, and \c GLenum
407 * - 'p' for any pointer type
408 * - 'f' for \c GLfloat and \c GLclampf
409 * - 'd' for \c GLdouble and \c GLclampd
412 * The offset in the dispatch table of the named function. A pointer to the
413 * driver's implementation of the named function should be stored at
414 * \c dispatch_table[\c offset]. Return -1 if error/problem.
416 * \sa glXGetProcAddress
419 * This function can only handle up to 8 names at a time. As far as I know,
420 * the maximum number of names ever associated with an existing GL function is
421 * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
422 * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
423 * too painful of a limitation.
426 * Determine whether or not \c parameter_signature should be allowed to be
427 * \c NULL. It doesn't seem like much of a hardship for drivers to have to
428 * pass in an empty string.
431 * Determine if code should be added to reject function names that start with
435 * Add code to compare \c parameter_signature with the parameter signature of
436 * a static function. In order to do that, we need to find a way to \b get
437 * the parameter signature of a static function.
441 _glapi_add_dispatch( const char * const * function_names
,
442 const char * parameter_signature
)
444 static int next_dynamic_offset
= _gloffset_FIRST_DYNAMIC
;
445 const char * const real_sig
= (parameter_signature
!= NULL
)
446 ? parameter_signature
: "";
447 struct _glapi_function
* entry
[8];
448 GLboolean is_static
[8];
455 (void) memset( is_static
, 0, sizeof( is_static
) );
456 (void) memset( entry
, 0, sizeof( entry
) );
458 for ( i
= 0 ; function_names
[i
] != NULL
; i
++ ) {
459 /* Do some trivial validation on the name of the function.
462 if (!function_names
[i
] || function_names
[i
][0] != 'g' || function_names
[i
][1] != 'l')
465 /* Determine if the named function already exists. If the function does
466 * exist, it must have the same parameter signature as the function
470 new_offset
= get_static_proc_offset(function_names
[i
]);
471 if (new_offset
>= 0) {
472 /* FIXME: Make sure the parameter signatures match! How do we get
473 * FIXME: the parameter signature for static functions?
476 if ( (offset
!= ~0) && (new_offset
!= offset
) ) {
480 is_static
[i
] = GL_TRUE
;
485 for ( j
= 0 ; j
< NumExtEntryPoints
; j
++ ) {
486 if (strcmp(ExtEntryTable
[j
].name
, function_names
[i
]) == 0) {
487 /* The offset may be ~0 if the function name was added by
488 * glXGetProcAddress but never filled in by the driver.
491 if (ExtEntryTable
[j
].dispatch_offset
!= ~0) {
492 if (strcmp(real_sig
, ExtEntryTable
[j
].parameter_signature
)
497 if ( (offset
!= ~0) && (ExtEntryTable
[j
].dispatch_offset
!= offset
) ) {
501 offset
= ExtEntryTable
[j
].dispatch_offset
;
504 entry
[i
] = & ExtEntryTable
[j
];
511 offset
= next_dynamic_offset
;
512 next_dynamic_offset
++;
515 for ( i
= 0 ; function_names
[i
] != NULL
; i
++ ) {
516 if (! is_static
[i
] ) {
517 if (entry
[i
] == NULL
) {
518 entry
[i
] = add_function_name( function_names
[i
] );
519 if (entry
[i
] == NULL
) {
520 /* FIXME: Possible memory leak here.
526 entry
[i
]->parameter_signature
= str_dup(real_sig
);
527 fill_in_entrypoint_offset(entry
[i
]->dispatch_stub
, offset
);
528 entry
[i
]->dispatch_offset
= offset
;
537 * Return offset of entrypoint for named function within dispatch table.
540 _glapi_get_proc_offset(const char *funcName
)
542 /* search extension functions first */
544 for (i
= 0; i
< NumExtEntryPoints
; i
++) {
545 if (strcmp(ExtEntryTable
[i
].name
, funcName
) == 0) {
546 return ExtEntryTable
[i
].dispatch_offset
;
549 /* search static functions */
550 return get_static_proc_offset(funcName
);
556 * Return pointer to the named function. If the function name isn't found
557 * in the name of static functions, try generating a new API entrypoint on
558 * the fly with assembly language.
561 _glapi_get_proc_address(const char *funcName
)
563 struct _glapi_function
* entry
;
567 if (funcName
[0] != 'm' || funcName
[1] != 'g' || funcName
[2] != 'l')
570 if (funcName
[0] != 'g' || funcName
[1] != 'l')
574 /* search extension functions first */
575 for (i
= 0; i
< NumExtEntryPoints
; i
++) {
576 if (strcmp(ExtEntryTable
[i
].name
, funcName
) == 0) {
577 return ExtEntryTable
[i
].dispatch_stub
;
581 #if !defined( XFree86Server ) && !defined( XGLServer )
582 /* search static functions */
584 const _glapi_proc func
= get_static_proc_address(funcName
);
588 #endif /* !defined( XFree86Server ) */
590 entry
= add_function_name(funcName
);
591 return (entry
== NULL
) ? NULL
: entry
->dispatch_stub
;
597 * Return the name of the function at the given dispatch offset.
598 * This is only intended for debugging.
601 _glapi_get_proc_name(GLuint offset
)
606 /* search built-in functions */
607 n
= get_static_proc_name(offset
);
612 /* search added extension functions */
613 for (i
= 0; i
< NumExtEntryPoints
; i
++) {
614 if (ExtEntryTable
[i
].dispatch_offset
== offset
) {
615 return ExtEntryTable
[i
].name
;