2b89a8f4f41fa92c8c357ef4059f2e596595a40a
[mesa.git] / src / mesa / glapi / glapi_getproc.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25 /**
26 * \file glapi_getproc.c
27 *
28 * Code for implementing glXGetProcAddress(), etc.
29 * This was originally in glapi.c but refactored out.
30 */
31
32
33 #ifdef HAVE_DIX_CONFIG_H
34 #include <dix-config.h>
35 #include "glapi/mesa.h"
36 #else
37 #include "main/glheader.h"
38 #include "main/compiler.h"
39 #endif
40
41 #include "glapi/glapi.h"
42 #include "glapi/glapioffsets.h"
43 #include "glapi/glapitable.h"
44
45
46 #if defined(USE_X64_64_ASM) && defined(GLX_USE_TLS)
47 # define DISPATCH_FUNCTION_SIZE 16
48 #elif defined(USE_X86_ASM)
49 # if defined(THREADS) && !defined(GLX_USE_TLS)
50 # define DISPATCH_FUNCTION_SIZE 32
51 # else
52 # define DISPATCH_FUNCTION_SIZE 16
53 # endif
54 #endif
55
56 #if !defined(DISPATCH_FUNCTION_SIZE) && !defined(XFree86Server)
57 # define NEED_FUNCTION_POINTER
58 #endif
59
60 /* The code in this file is auto-generated with Python */
61 #include "glapi/glprocs.h"
62
63
64 /**
65 * Search the table of static entrypoint functions for the named function
66 * and return the corresponding glprocs_table_t entry.
67 */
68 static const glprocs_table_t *
69 find_entry( const char * n )
70 {
71 GLuint i;
72 for (i = 0; static_functions[i].Name_offset >= 0; i++) {
73 const char *testName = gl_string_table + static_functions[i].Name_offset;
74 #ifdef MANGLE
75 /* skip the "m" prefix on the name */
76 if (strcmp(testName, n + 1) == 0)
77 #else
78 if (strcmp(testName, n) == 0)
79 #endif
80 {
81 return &static_functions[i];
82 }
83 }
84 return NULL;
85 }
86
87
88 /**
89 * Return dispatch table offset of the named static (built-in) function.
90 * Return -1 if function not found.
91 */
92 static GLint
93 get_static_proc_offset(const char *funcName)
94 {
95 const glprocs_table_t * const f = find_entry( funcName );
96 if (f) {
97 return f->Offset;
98 }
99 return -1;
100 }
101
102
103 #ifdef USE_X86_ASM
104
105 #if defined( GLX_USE_TLS )
106 extern GLubyte gl_dispatch_functions_start[];
107 extern GLubyte gl_dispatch_functions_end[];
108 #else
109 extern const GLubyte gl_dispatch_functions_start[];
110 #endif
111
112 #endif /* USE_X86_ASM */
113
114
115 #if !defined(XFree86Server)
116
117 /**
118 * Return dispatch function address for the named static (built-in) function.
119 * Return NULL if function not found.
120 */
121 static _glapi_proc
122 get_static_proc_address(const char *funcName)
123 {
124 const glprocs_table_t * const f = find_entry( funcName );
125 if (f) {
126 #if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING)
127 return (f->Address == NULL)
128 ? (_glapi_proc) (gl_dispatch_functions_start
129 + (DISPATCH_FUNCTION_SIZE * f->Offset))
130 : f->Address;
131 #elif defined(DISPATCH_FUNCTION_SIZE)
132 return (_glapi_proc) (gl_dispatch_functions_start
133 + (DISPATCH_FUNCTION_SIZE * f->Offset));
134 #else
135 return f->Address;
136 #endif
137 }
138 else {
139 return NULL;
140 }
141 }
142
143 #endif /* !defined(XFree86Server) */
144
145
146
147 /**
148 * Return the name of the function at the given offset in the dispatch
149 * table. For debugging only.
150 */
151 static const char *
152 get_static_proc_name( GLuint offset )
153 {
154 GLuint i;
155 for (i = 0; static_functions[i].Name_offset >= 0; i++) {
156 if (static_functions[i].Offset == offset) {
157 return gl_string_table + static_functions[i].Name_offset;
158 }
159 }
160 return NULL;
161 }
162
163
164
165 #if defined(PTHREADS) || defined(GLX_USE_TLS)
166
167 /**
168 * Perform platform-specific GL API entry-point fixups.
169 */
170 static void
171 init_glapi_relocs( void )
172 {
173 #if defined(USE_X86_ASM) && defined(GLX_USE_TLS) && !defined(GLX_X86_READONLY_TEXT)
174 extern unsigned long _x86_get_dispatch(void);
175 char run_time_patch[] = {
176 0x65, 0xa1, 0, 0, 0, 0 /* movl %gs:0,%eax */
177 };
178 GLuint *offset = (GLuint *) &run_time_patch[2]; /* 32-bits for x86/32 */
179 const GLubyte * const get_disp = (const GLubyte *) run_time_patch;
180 GLubyte * curr_func = (GLubyte *) gl_dispatch_functions_start;
181
182 *offset = _x86_get_dispatch();
183 while ( curr_func != (GLubyte *) gl_dispatch_functions_end ) {
184 (void) memcpy( curr_func, get_disp, sizeof(run_time_patch));
185 curr_func += DISPATCH_FUNCTION_SIZE;
186 }
187 #endif
188 #ifdef USE_SPARC_ASM
189 extern void __glapi_sparc_icache_flush(unsigned int *);
190 static const unsigned int template[] = {
191 #ifdef GLX_USE_TLS
192 0x05000000, /* sethi %hi(_glapi_tls_Dispatch), %g2 */
193 0x8730e00a, /* srl %g3, 10, %g3 */
194 0x8410a000, /* or %g2, %lo(_glapi_tls_Dispatch), %g2 */
195 #ifdef __arch64__
196 0xc259c002, /* ldx [%g7 + %g2], %g1 */
197 0xc2584003, /* ldx [%g1 + %g3], %g1 */
198 #else
199 0xc201c002, /* ld [%g7 + %g2], %g1 */
200 0xc2004003, /* ld [%g1 + %g3], %g1 */
201 #endif
202 0x81c04000, /* jmp %g1 */
203 0x01000000, /* nop */
204 #else
205 #ifdef __arch64__
206 0x03000000, /* 64-bit 0x00 --> sethi %hh(_glapi_Dispatch), %g1 */
207 0x05000000, /* 64-bit 0x04 --> sethi %lm(_glapi_Dispatch), %g2 */
208 0x82106000, /* 64-bit 0x08 --> or %g1, %hm(_glapi_Dispatch), %g1 */
209 0x8730e00a, /* 64-bit 0x0c --> srl %g3, 10, %g3 */
210 0x83287020, /* 64-bit 0x10 --> sllx %g1, 32, %g1 */
211 0x82004002, /* 64-bit 0x14 --> add %g1, %g2, %g1 */
212 0xc2586000, /* 64-bit 0x18 --> ldx [%g1 + %lo(_glapi_Dispatch)], %g1 */
213 #else
214 0x03000000, /* 32-bit 0x00 --> sethi %hi(_glapi_Dispatch), %g1 */
215 0x8730e00a, /* 32-bit 0x04 --> srl %g3, 10, %g3 */
216 0xc2006000, /* 32-bit 0x08 --> ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
217 #endif
218 0x80a06000, /* --> cmp %g1, 0 */
219 0x02800005, /* --> be +4*5 */
220 0x01000000, /* --> nop */
221 #ifdef __arch64__
222 0xc2584003, /* 64-bit --> ldx [%g1 + %g3], %g1 */
223 #else
224 0xc2004003, /* 32-bit --> ld [%g1 + %g3], %g1 */
225 #endif
226 0x81c04000, /* --> jmp %g1 */
227 0x01000000, /* --> nop */
228 #ifdef __arch64__
229 0x9de3bf80, /* 64-bit --> save %sp, -128, %sp */
230 #else
231 0x9de3bfc0, /* 32-bit --> save %sp, -64, %sp */
232 #endif
233 0xa0100003, /* --> mov %g3, %l0 */
234 0x40000000, /* --> call _glapi_get_dispatch */
235 0x01000000, /* --> nop */
236 0x82100008, /* --> mov %o0, %g1 */
237 0x86100010, /* --> mov %l0, %g3 */
238 0x10bffff7, /* --> ba -4*9 */
239 0x81e80000, /* --> restore */
240 #endif
241 };
242 #ifdef GLX_USE_TLS
243 extern unsigned int __glapi_sparc_tls_stub;
244 extern unsigned long __glapi_sparc_get_dispatch(void);
245 unsigned int *code = &__glapi_sparc_tls_stub;
246 unsigned long dispatch = __glapi_sparc_get_dispatch();
247 #else
248 extern unsigned int __glapi_sparc_pthread_stub;
249 unsigned int *code = &__glapi_sparc_pthread_stub;
250 unsigned long dispatch = (unsigned long) &_glapi_Dispatch;
251 unsigned long call_dest = (unsigned long ) &_glapi_get_dispatch;
252 int idx;
253 #endif
254
255 #if defined(GLX_USE_TLS)
256 code[0] = template[0] | (dispatch >> 10);
257 code[1] = template[1];
258 __glapi_sparc_icache_flush(&code[0]);
259 code[2] = template[2] | (dispatch & 0x3ff);
260 code[3] = template[3];
261 __glapi_sparc_icache_flush(&code[2]);
262 code[4] = template[4];
263 code[5] = template[5];
264 __glapi_sparc_icache_flush(&code[4]);
265 code[6] = template[6];
266 __glapi_sparc_icache_flush(&code[6]);
267 #else
268 #if defined(__arch64__)
269 code[0] = template[0] | (dispatch >> (32 + 10));
270 code[1] = template[1] | ((dispatch & 0xffffffff) >> 10);
271 __glapi_sparc_icache_flush(&code[0]);
272 code[2] = template[2] | ((dispatch >> 32) & 0x3ff);
273 code[3] = template[3];
274 __glapi_sparc_icache_flush(&code[2]);
275 code[4] = template[4];
276 code[5] = template[5];
277 __glapi_sparc_icache_flush(&code[4]);
278 code[6] = template[6] | (dispatch & 0x3ff);
279 idx = 7;
280 #else
281 code[0] = template[0] | (dispatch >> 10);
282 code[1] = template[1];
283 __glapi_sparc_icache_flush(&code[0]);
284 code[2] = template[2] | (dispatch & 0x3ff);
285 idx = 3;
286 #endif
287 code[idx + 0] = template[idx + 0];
288 __glapi_sparc_icache_flush(&code[idx - 1]);
289 code[idx + 1] = template[idx + 1];
290 code[idx + 2] = template[idx + 2];
291 __glapi_sparc_icache_flush(&code[idx + 1]);
292 code[idx + 3] = template[idx + 3];
293 code[idx + 4] = template[idx + 4];
294 __glapi_sparc_icache_flush(&code[idx + 3]);
295 code[idx + 5] = template[idx + 5];
296 code[idx + 6] = template[idx + 6];
297 __glapi_sparc_icache_flush(&code[idx + 5]);
298 code[idx + 7] = template[idx + 7];
299 code[idx + 8] = template[idx + 8] |
300 (((call_dest - ((unsigned long) &code[idx + 8]))
301 >> 2) & 0x3fffffff);
302 __glapi_sparc_icache_flush(&code[idx + 7]);
303 code[idx + 9] = template[idx + 9];
304 code[idx + 10] = template[idx + 10];
305 __glapi_sparc_icache_flush(&code[idx + 9]);
306 code[idx + 11] = template[idx + 11];
307 code[idx + 12] = template[idx + 12];
308 __glapi_sparc_icache_flush(&code[idx + 11]);
309 code[idx + 13] = template[idx + 13];
310 __glapi_sparc_icache_flush(&code[idx + 13]);
311 #endif
312 #endif
313 }
314
315 void
316 init_glapi_relocs_once( void )
317 {
318 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
319 pthread_once( & once_control, init_glapi_relocs );
320 }
321
322 #else
323
324 void
325 init_glapi_relocs_once( void ) { }
326
327 #endif /* defined(PTHREADS) || defined(GLX_USE_TLS) */
328
329
330
331 /**********************************************************************
332 * Extension function management.
333 */
334
335
336 /**
337 * Track information about a function added to the GL API.
338 */
339 struct _glapi_function {
340 /**
341 * Name of the function.
342 */
343 const char * name;
344
345
346 /**
347 * Text string that describes the types of the parameters passed to the
348 * named function. Parameter types are converted to characters using the
349 * following rules:
350 * - 'i' for \c GLint, \c GLuint, and \c GLenum
351 * - 'p' for any pointer type
352 * - 'f' for \c GLfloat and \c GLclampf
353 * - 'd' for \c GLdouble and \c GLclampd
354 */
355 const char * parameter_signature;
356
357
358 /**
359 * Offset in the dispatch table where the pointer to the real function is
360 * located. If the driver has not requested that the named function be
361 * added to the dispatch table, this will have the value ~0.
362 */
363 unsigned dispatch_offset;
364
365
366 /**
367 * Pointer to the dispatch stub for the named function.
368 *
369 * \todo
370 * The semantic of this field should be changed slightly. Currently, it
371 * is always expected to be non-\c NULL. However, it would be better to
372 * only allocate the entry-point stub when the application requests the
373 * function via \c glXGetProcAddress. This would save memory for all the
374 * functions that the driver exports but that the application never wants
375 * to call.
376 */
377 _glapi_proc dispatch_stub;
378 };
379
380
381 static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
382 static GLuint NumExtEntryPoints = 0;
383
384 #ifdef USE_SPARC_ASM
385 extern void __glapi_sparc_icache_flush(unsigned int *);
386 #endif
387
388 static void
389 fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset);
390
391 /**
392 * Generate a dispatch function (entrypoint) which jumps through
393 * the given slot number (offset) in the current dispatch table.
394 * We need assembly language in order to accomplish this.
395 */
396 static _glapi_proc
397 generate_entrypoint(GLuint functionOffset)
398 {
399 #if defined(USE_X86_ASM)
400 /* 32 is chosen as something of a magic offset. For x86, the dispatch
401 * at offset 32 is the first one where the offset in the
402 * "jmp OFFSET*4(%eax)" can't be encoded in a single byte.
403 */
404 const GLubyte * const template_func = gl_dispatch_functions_start
405 + (DISPATCH_FUNCTION_SIZE * 32);
406 GLubyte * const code = (GLubyte *) malloc(DISPATCH_FUNCTION_SIZE);
407
408
409 if ( code != NULL ) {
410 (void) memcpy(code, template_func, DISPATCH_FUNCTION_SIZE);
411 fill_in_entrypoint_offset( (_glapi_proc) code, functionOffset );
412 }
413
414 return (_glapi_proc) code;
415 #elif defined(USE_SPARC_ASM)
416
417 #if defined(PTHREADS) || defined(GLX_USE_TLS)
418 static const unsigned int template[] = {
419 0x07000000, /* sethi %hi(0), %g3 */
420 0x8210000f, /* mov %o7, %g1 */
421 0x40000000, /* call */
422 0x9e100001, /* mov %g1, %o7 */
423 };
424 #ifdef GLX_USE_TLS
425 extern unsigned int __glapi_sparc_tls_stub;
426 unsigned long call_dest = (unsigned long ) &__glapi_sparc_tls_stub;
427 #else
428 extern unsigned int __glapi_sparc_pthread_stub;
429 unsigned long call_dest = (unsigned long ) &__glapi_sparc_pthread_stub;
430 #endif
431 unsigned int *code = (unsigned int *) malloc(sizeof(template));
432 if (code) {
433 code[0] = template[0] | (functionOffset & 0x3fffff);
434 code[1] = template[1];
435 __glapi_sparc_icache_flush(&code[0]);
436 code[2] = template[2] |
437 (((call_dest - ((unsigned long) &code[2]))
438 >> 2) & 0x3fffffff);
439 code[3] = template[3];
440 __glapi_sparc_icache_flush(&code[2]);
441 }
442 return (_glapi_proc) code;
443 #endif
444
445 #else
446 (void) functionOffset;
447 return NULL;
448 #endif /* USE_*_ASM */
449 }
450
451
452 /**
453 * This function inserts a new dispatch offset into the assembly language
454 * stub that was generated with the preceeding function.
455 */
456 static void
457 fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset)
458 {
459 #if defined(USE_X86_ASM)
460 GLubyte * const code = (GLubyte *) entrypoint;
461
462 #if DISPATCH_FUNCTION_SIZE == 32
463 *((unsigned int *)(code + 11)) = 4 * offset;
464 *((unsigned int *)(code + 22)) = 4 * offset;
465 #elif DISPATCH_FUNCTION_SIZE == 16 && defined( GLX_USE_TLS )
466 *((unsigned int *)(code + 8)) = 4 * offset;
467 #elif DISPATCH_FUNCTION_SIZE == 16
468 *((unsigned int *)(code + 7)) = 4 * offset;
469 #else
470 # error Invalid DISPATCH_FUNCTION_SIZE!
471 #endif
472
473 #elif defined(USE_SPARC_ASM)
474 unsigned int *code = (unsigned int *) entrypoint;
475 code[0] &= ~0x3fffff;
476 code[0] |= (offset * sizeof(void *)) & 0x3fffff;
477 __glapi_sparc_icache_flush(&code[0]);
478 #else
479
480 /* an unimplemented architecture */
481 (void) entrypoint;
482 (void) offset;
483
484 #endif /* USE_*_ASM */
485 }
486
487
488 /**
489 * strdup() is actually not a standard ANSI C or POSIX routine.
490 * Irix will not define it if ANSI mode is in effect.
491 */
492 static char *
493 str_dup(const char *str)
494 {
495 char *copy;
496 copy = (char*) malloc(strlen(str) + 1);
497 if (!copy)
498 return NULL;
499 strcpy(copy, str);
500 return copy;
501 }
502
503
504 /**
505 * Generate new entrypoint
506 *
507 * Use a temporary dispatch offset of ~0 (i.e. -1). Later, when the driver
508 * calls \c _glapi_add_dispatch we'll put in the proper offset. If that
509 * never happens, and the user calls this function, he'll segfault. That's
510 * what you get when you try calling a GL function that doesn't really exist.
511 *
512 * \param funcName Name of the function to create an entry-point for.
513 *
514 * \sa _glapi_add_entrypoint
515 */
516
517 static struct _glapi_function *
518 add_function_name( const char * funcName )
519 {
520 struct _glapi_function * entry = NULL;
521
522 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
523 _glapi_proc entrypoint = generate_entrypoint(~0);
524 if (entrypoint != NULL) {
525 entry = & ExtEntryTable[NumExtEntryPoints];
526
527 ExtEntryTable[NumExtEntryPoints].name = str_dup(funcName);
528 ExtEntryTable[NumExtEntryPoints].parameter_signature = NULL;
529 ExtEntryTable[NumExtEntryPoints].dispatch_offset = ~0;
530 ExtEntryTable[NumExtEntryPoints].dispatch_stub = entrypoint;
531 NumExtEntryPoints++;
532 }
533 }
534
535 return entry;
536 }
537
538
539 /**
540 * Fill-in the dispatch stub for the named function.
541 *
542 * This function is intended to be called by a hardware driver. When called,
543 * a dispatch stub may be created created for the function. A pointer to this
544 * dispatch function will be returned by glXGetProcAddress.
545 *
546 * \param function_names Array of pointers to function names that should
547 * share a common dispatch offset.
548 * \param parameter_signature String representing the types of the parameters
549 * passed to the named function. Parameter types
550 * are converted to characters using the following
551 * rules:
552 * - 'i' for \c GLint, \c GLuint, and \c GLenum
553 * - 'p' for any pointer type
554 * - 'f' for \c GLfloat and \c GLclampf
555 * - 'd' for \c GLdouble and \c GLclampd
556 *
557 * \returns
558 * The offset in the dispatch table of the named function. A pointer to the
559 * driver's implementation of the named function should be stored at
560 * \c dispatch_table[\c offset]. Return -1 if error/problem.
561 *
562 * \sa glXGetProcAddress
563 *
564 * \warning
565 * This function can only handle up to 8 names at a time. As far as I know,
566 * the maximum number of names ever associated with an existing GL function is
567 * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
568 * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
569 * too painful of a limitation.
570 *
571 * \todo
572 * Determine whether or not \c parameter_signature should be allowed to be
573 * \c NULL. It doesn't seem like much of a hardship for drivers to have to
574 * pass in an empty string.
575 *
576 * \todo
577 * Determine if code should be added to reject function names that start with
578 * 'glX'.
579 *
580 * \bug
581 * Add code to compare \c parameter_signature with the parameter signature of
582 * a static function. In order to do that, we need to find a way to \b get
583 * the parameter signature of a static function.
584 */
585
586 PUBLIC int
587 _glapi_add_dispatch( const char * const * function_names,
588 const char * parameter_signature )
589 {
590 static int next_dynamic_offset = _gloffset_FIRST_DYNAMIC;
591 const char * const real_sig = (parameter_signature != NULL)
592 ? parameter_signature : "";
593 struct _glapi_function * entry[8];
594 GLboolean is_static[8];
595 unsigned i;
596 unsigned j;
597 int offset = ~0;
598 int new_offset;
599
600
601 (void) memset( is_static, 0, sizeof( is_static ) );
602 (void) memset( entry, 0, sizeof( entry ) );
603
604 for ( i = 0 ; function_names[i] != NULL ; i++ ) {
605 /* Do some trivial validation on the name of the function.
606 */
607
608 if (!function_names[i] || function_names[i][0] != 'g' || function_names[i][1] != 'l')
609 return -1;
610
611 /* Determine if the named function already exists. If the function does
612 * exist, it must have the same parameter signature as the function
613 * being added.
614 */
615
616 new_offset = get_static_proc_offset(function_names[i]);
617 if (new_offset >= 0) {
618 /* FIXME: Make sure the parameter signatures match! How do we get
619 * FIXME: the parameter signature for static functions?
620 */
621
622 if ( (offset != ~0) && (new_offset != offset) ) {
623 return -1;
624 }
625
626 is_static[i] = GL_TRUE;
627 offset = new_offset;
628 }
629
630
631 for ( j = 0 ; j < NumExtEntryPoints ; j++ ) {
632 if (strcmp(ExtEntryTable[j].name, function_names[i]) == 0) {
633 /* The offset may be ~0 if the function name was added by
634 * glXGetProcAddress but never filled in by the driver.
635 */
636
637 if (ExtEntryTable[j].dispatch_offset != ~0) {
638 if (strcmp(real_sig, ExtEntryTable[j].parameter_signature)
639 != 0) {
640 return -1;
641 }
642
643 if ( (offset != ~0) && (ExtEntryTable[j].dispatch_offset != offset) ) {
644 return -1;
645 }
646
647 offset = ExtEntryTable[j].dispatch_offset;
648 }
649
650 entry[i] = & ExtEntryTable[j];
651 break;
652 }
653 }
654 }
655
656 if (offset == ~0) {
657 offset = next_dynamic_offset;
658 next_dynamic_offset++;
659 }
660
661 for ( i = 0 ; function_names[i] != NULL ; i++ ) {
662 if (! is_static[i] ) {
663 if (entry[i] == NULL) {
664 entry[i] = add_function_name( function_names[i] );
665 if (entry[i] == NULL) {
666 /* FIXME: Possible memory leak here.
667 */
668 return -1;
669 }
670 }
671
672 entry[i]->parameter_signature = str_dup(real_sig);
673 fill_in_entrypoint_offset(entry[i]->dispatch_stub, offset);
674 entry[i]->dispatch_offset = offset;
675 }
676 }
677
678 return offset;
679 }
680
681
682 /**
683 * Return offset of entrypoint for named function within dispatch table.
684 */
685 PUBLIC GLint
686 _glapi_get_proc_offset(const char *funcName)
687 {
688 /* search extension functions first */
689 GLuint i;
690 for (i = 0; i < NumExtEntryPoints; i++) {
691 if (strcmp(ExtEntryTable[i].name, funcName) == 0) {
692 return ExtEntryTable[i].dispatch_offset;
693 }
694 }
695 /* search static functions */
696 return get_static_proc_offset(funcName);
697 }
698
699
700
701 /**
702 * Return pointer to the named function. If the function name isn't found
703 * in the name of static functions, try generating a new API entrypoint on
704 * the fly with assembly language.
705 */
706 PUBLIC _glapi_proc
707 _glapi_get_proc_address(const char *funcName)
708 {
709 struct _glapi_function * entry;
710 GLuint i;
711
712 #ifdef MANGLE
713 if (funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
714 return NULL;
715 #else
716 if (funcName[0] != 'g' || funcName[1] != 'l')
717 return NULL;
718 #endif
719
720 /* search extension functions first */
721 for (i = 0; i < NumExtEntryPoints; i++) {
722 if (strcmp(ExtEntryTable[i].name, funcName) == 0) {
723 return ExtEntryTable[i].dispatch_stub;
724 }
725 }
726
727 #if !defined( XFree86Server )
728 /* search static functions */
729 {
730 const _glapi_proc func = get_static_proc_address(funcName);
731 if (func)
732 return func;
733 }
734 #endif /* !defined( XFree86Server ) */
735
736 entry = add_function_name(funcName);
737 return (entry == NULL) ? NULL : entry->dispatch_stub;
738 }
739
740
741
742 /**
743 * Return the name of the function at the given dispatch offset.
744 * This is only intended for debugging.
745 */
746 const char *
747 _glapi_get_proc_name(GLuint offset)
748 {
749 GLuint i;
750 const char * n;
751
752 /* search built-in functions */
753 n = get_static_proc_name(offset);
754 if ( n != NULL ) {
755 return n;
756 }
757
758 /* search added extension functions */
759 for (i = 0; i < NumExtEntryPoints; i++) {
760 if (ExtEntryTable[i].dispatch_offset == offset) {
761 return ExtEntryTable[i].name;
762 }
763 }
764 return NULL;
765 }
766
767
768
769 /**
770 * Do some spot checks to be sure that the dispatch table
771 * slots are assigned correctly. For debugging only.
772 */
773 void
774 _glapi_check_table(const struct _glapi_table *table)
775 {
776 #if 0 /* enable this for extra DEBUG */
777 {
778 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
779 char *BeginFunc = (char*) &table->Begin;
780 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
781 assert(BeginOffset == _gloffset_Begin);
782 assert(BeginOffset == offset);
783 }
784 {
785 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
786 char *viewportFunc = (char*) &table->Viewport;
787 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
788 assert(viewportOffset == _gloffset_Viewport);
789 assert(viewportOffset == offset);
790 }
791 {
792 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
793 char *VertexPointerFunc = (char*) &table->VertexPointer;
794 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
795 assert(VertexPointerOffset == _gloffset_VertexPointer);
796 assert(VertexPointerOffset == offset);
797 }
798 {
799 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
800 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
801 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
802 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
803 assert(ResetMinMaxOffset == offset);
804 }
805 {
806 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
807 char *blendColorFunc = (char*) &table->BlendColor;
808 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
809 assert(blendColorOffset == _gloffset_BlendColor);
810 assert(blendColorOffset == offset);
811 }
812 {
813 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
814 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
815 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
816 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
817 assert(secondaryColor3fOffset == offset);
818 }
819 {
820 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
821 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
822 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
823 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
824 assert(pointParameterivOffset == offset);
825 }
826 {
827 GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
828 char *setFenceFunc = (char*) &table->SetFenceNV;
829 GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
830 assert(setFenceOffset == _gloffset_SetFenceNV);
831 assert(setFenceOffset == offset);
832 }
833 #else
834 (void) table;
835 #endif
836 }