minor fixes for entrypoint name mangling
[mesa.git] / src / mesa / glapi / glapi.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 4.1
5 *
6 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 /*
28 * This file manages the OpenGL API dispatch layer.
29 * The dispatch table (struct _glapi_table) is basically just a list
30 * of function pointers.
31 * There are functions to set/get the current dispatch table for the
32 * current thread and to manage registration/dispatch of dynamically
33 * added extension functions.
34 *
35 * It's intended that this file and the other glapi*.[ch] files are
36 * flexible enough to be reused in several places: XFree86, DRI-
37 * based libGL.so, and perhaps the SGI SI.
38 *
39 * NOTE: There are no dependencies on Mesa in this code.
40 *
41 * Versions (API changes):
42 * 2000/02/23 - original version for Mesa 3.3 and XFree86 4.0
43 * 2001/01/16 - added dispatch override feature for Mesa 3.5
44 * 2002/06/28 - added _glapi_set_warning_func(), Mesa 4.1.
45 * 2002/10/01 - _glapi_get_proc_address() will now generate new entrypoints
46 * itself (using offset ~0). _glapi_add_entrypoint() can be
47 * called afterward and it'll fill in the correct dispatch
48 * offset. This allows DRI libGL to avoid probing for DRI
49 * drivers! No changes to the public glapi interface.
50 */
51
52
53
54 #include "glheader.h"
55 #include "glapi.h"
56 #include "glapioffsets.h"
57 #include "glapitable.h"
58 #include "glthread.h"
59
60 /***** BEGIN NO-OP DISPATCH *****/
61
62 static GLboolean WarnFlag = GL_FALSE;
63 static _glapi_warning_func warning_func;
64
65
66 /*
67 * Enable/disable printing of warning messages.
68 */
69 void
70 _glapi_noop_enable_warnings(GLboolean enable)
71 {
72 WarnFlag = enable;
73 }
74
75 /*
76 * Register a callback function for reporting errors.
77 */
78 void
79 _glapi_set_warning_func( _glapi_warning_func func )
80 {
81 warning_func = func;
82 }
83
84 static GLboolean
85 warn(void)
86 {
87 if ((WarnFlag || getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"))
88 && warning_func) {
89 return GL_TRUE;
90 }
91 else {
92 return GL_FALSE;
93 }
94 }
95
96
97 #define KEYWORD1 static
98 #define KEYWORD2 GLAPIENTRY
99 #define NAME(func) NoOp##func
100
101 #define F NULL
102
103 #define DISPATCH(func, args, msg) \
104 if (warn()) { \
105 warning_func(NULL, "GL User Error: called without context:"); \
106 warning_func msg; \
107 }
108
109 #define RETURN_DISPATCH(func, args, msg) \
110 if (warn()) { \
111 warning_func(NULL, "GL User Error: called without context:"); \
112 warning_func msg; \
113 } \
114 return 0
115
116 #define DISPATCH_TABLE_NAME __glapi_noop_table
117 #define UNUSED_TABLE_NAME __usused_noop_functions
118
119 #define TABLE_ENTRY(name) (void *) NoOp##name
120
121 static int NoOpUnused(void)
122 {
123 if (warn()) {
124 warning_func(NULL, "GL User Error: calling extension function without a current context\n");
125 }
126 return 0;
127 }
128
129 #include "glapitemp.h"
130
131 /***** END NO-OP DISPATCH *****/
132
133
134
135 /***** BEGIN THREAD-SAFE DISPATCH *****/
136 /* if we support thread-safety, build a special dispatch table for use
137 * in thread-safety mode (ThreadSafe == GL_TRUE). Each entry in the
138 * dispatch table will call _glthread_GetTSD() to get the actual dispatch
139 * table bound to the current thread, then jump through that table.
140 */
141
142 #if defined(THREADS)
143
144 static GLboolean ThreadSafe = GL_FALSE; /* In thread-safe mode? */
145 static _glthread_TSD DispatchTSD; /* Per-thread dispatch pointer */
146 static _glthread_TSD RealDispatchTSD; /* only when using override */
147 static _glthread_TSD ContextTSD; /* Per-thread context pointer */
148
149
150 #define KEYWORD1 static
151 #define KEYWORD2 GLAPIENTRY
152 #define NAME(func) _ts_##func
153
154 #define DISPATCH(FUNC, ARGS, MESSAGE) \
155 struct _glapi_table *dispatch; \
156 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
157 if (!dispatch) \
158 dispatch = (struct _glapi_table *) __glapi_noop_table; \
159 (dispatch->FUNC) ARGS
160
161 #define RETURN_DISPATCH(FUNC, ARGS, MESSAGE) \
162 struct _glapi_table *dispatch; \
163 dispatch = (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD); \
164 if (!dispatch) \
165 dispatch = (struct _glapi_table *) __glapi_noop_table; \
166 return (dispatch->FUNC) ARGS
167
168 #define DISPATCH_TABLE_NAME __glapi_threadsafe_table
169 #define UNUSED_TABLE_NAME __usused_threadsafe_functions
170
171 #define TABLE_ENTRY(name) (void *) _ts_##name
172
173 static int _ts_Unused(void)
174 {
175 return 0;
176 }
177
178 #include "glapitemp.h"
179
180 #endif
181
182 /***** END THREAD-SAFE DISPATCH *****/
183
184
185
186 struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
187 struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
188
189 /* Used when thread safety disabled */
190 void *_glapi_Context = NULL;
191
192
193 static GLboolean DispatchOverride = GL_FALSE;
194
195
196
197 /* strdup() is actually not a standard ANSI C or POSIX routine.
198 * Irix will not define it if ANSI mode is in effect.
199 */
200 static char *
201 str_dup(const char *str)
202 {
203 char *copy;
204 copy = (char*) malloc(strlen(str) + 1);
205 if (!copy)
206 return NULL;
207 strcpy(copy, str);
208 return copy;
209 }
210
211
212
213 /*
214 * We should call this periodically from a function such as glXMakeCurrent
215 * in order to test if multiple threads are being used.
216 */
217 void
218 _glapi_check_multithread(void)
219 {
220 #if defined(THREADS)
221 if (!ThreadSafe) {
222 static unsigned long knownID;
223 static GLboolean firstCall = GL_TRUE;
224 if (firstCall) {
225 knownID = _glthread_GetID();
226 firstCall = GL_FALSE;
227 }
228 else if (knownID != _glthread_GetID()) {
229 ThreadSafe = GL_TRUE;
230 }
231 }
232 if (ThreadSafe) {
233 /* make sure that this thread's dispatch pointer isn't null */
234 if (!_glapi_get_dispatch()) {
235 _glapi_set_dispatch(NULL);
236 }
237 }
238 #endif
239 }
240
241
242
243 /*
244 * Set the current context pointer for this thread.
245 * The context pointer is an opaque type which should be cast to
246 * void from the real context pointer type.
247 */
248 void
249 _glapi_set_context(void *context)
250 {
251 #if defined(THREADS)
252 _glthread_SetTSD(&ContextTSD, context);
253 if (ThreadSafe)
254 _glapi_Context = NULL;
255 else
256 _glapi_Context = context;
257 #else
258 _glapi_Context = context;
259 #endif
260 }
261
262
263
264 /*
265 * Get the current context pointer for this thread.
266 * The context pointer is an opaque type which should be cast from
267 * void to the real context pointer type.
268 */
269 void *
270 _glapi_get_context(void)
271 {
272 #if defined(THREADS)
273 if (ThreadSafe) {
274 return _glthread_GetTSD(&ContextTSD);
275 }
276 else {
277 return _glapi_Context;
278 }
279 #else
280 return _glapi_Context;
281 #endif
282 }
283
284
285
286 /*
287 * Set the global or per-thread dispatch table pointer.
288 */
289 void
290 _glapi_set_dispatch(struct _glapi_table *dispatch)
291 {
292 if (!dispatch) {
293 /* use the no-op functions */
294 dispatch = (struct _glapi_table *) __glapi_noop_table;
295 }
296 #ifdef DEBUG
297 else {
298 _glapi_check_table(dispatch);
299 }
300 #endif
301
302 #if defined(THREADS)
303 if (DispatchOverride) {
304 _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
305 if (ThreadSafe)
306 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
307 else
308 _glapi_RealDispatch = dispatch;
309 }
310 else {
311 /* normal operation */
312 _glthread_SetTSD(&DispatchTSD, (void *) dispatch);
313 if (ThreadSafe)
314 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
315 else
316 _glapi_Dispatch = dispatch;
317 }
318 #else /*THREADS*/
319 if (DispatchOverride) {
320 _glapi_RealDispatch = dispatch;
321 }
322 else {
323 _glapi_Dispatch = dispatch;
324 }
325 #endif /*THREADS*/
326 }
327
328
329
330 /*
331 * Return pointer to current dispatch table for calling thread.
332 */
333 struct _glapi_table *
334 _glapi_get_dispatch(void)
335 {
336 #if defined(THREADS)
337 if (ThreadSafe) {
338 if (DispatchOverride) {
339 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
340 }
341 else {
342 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
343 }
344 }
345 else {
346 if (DispatchOverride) {
347 assert(_glapi_RealDispatch);
348 return _glapi_RealDispatch;
349 }
350 else {
351 assert(_glapi_Dispatch);
352 return _glapi_Dispatch;
353 }
354 }
355 #else
356 return _glapi_Dispatch;
357 #endif
358 }
359
360
361 /*
362 * Notes on dispatch overrride:
363 *
364 * Dispatch override allows an external agent to hook into the GL dispatch
365 * mechanism before execution goes into the core rendering library. For
366 * example, a trace mechanism would insert itself as an overrider, print
367 * logging info for each GL function, then dispatch to the real GL function.
368 *
369 * libGLS (GL Stream library) is another agent that might use override.
370 *
371 * We don't allow more than one layer of overriding at this time.
372 * In the future we may allow nested/layered override. In that case
373 * _glapi_begin_dispatch_override() will return an override layer,
374 * _glapi_end_dispatch_override(layer) will remove an override layer
375 * and _glapi_get_override_dispatch(layer) will return the dispatch
376 * table for a given override layer. layer = 0 will be the "real"
377 * dispatch table.
378 */
379
380 /*
381 * Return: dispatch override layer number.
382 */
383 int
384 _glapi_begin_dispatch_override(struct _glapi_table *override)
385 {
386 struct _glapi_table *real = _glapi_get_dispatch();
387
388 assert(!DispatchOverride); /* can't nest at this time */
389 DispatchOverride = GL_TRUE;
390
391 _glapi_set_dispatch(real);
392
393 #if defined(THREADS)
394 _glthread_SetTSD(&DispatchTSD, (void *) override);
395 if (ThreadSafe)
396 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
397 else
398 _glapi_Dispatch = override;
399 #else
400 _glapi_Dispatch = override;
401 #endif
402 return 1;
403 }
404
405
406 void
407 _glapi_end_dispatch_override(int layer)
408 {
409 struct _glapi_table *real = _glapi_get_dispatch();
410 (void) layer;
411 DispatchOverride = GL_FALSE;
412 _glapi_set_dispatch(real);
413 /* the rest of this isn't needed, just play it safe */
414 #if defined(THREADS)
415 _glthread_SetTSD(&RealDispatchTSD, NULL);
416 #endif
417 _glapi_RealDispatch = NULL;
418 }
419
420
421 struct _glapi_table *
422 _glapi_get_override_dispatch(int layer)
423 {
424 if (layer == 0) {
425 return _glapi_get_dispatch();
426 }
427 else {
428 if (DispatchOverride) {
429 #if defined(THREADS)
430 return (struct _glapi_table *) _glthread_GetTSD(&DispatchTSD);
431 #else
432 return _glapi_Dispatch;
433 #endif
434 }
435 else {
436 return NULL;
437 }
438 }
439 }
440
441
442 struct name_address_offset {
443 const char *Name;
444 GLvoid *Address;
445 GLuint Offset;
446 };
447
448
449 /* The code in this file is auto-generated with Python */
450 #include "glprocs.h"
451
452
453
454 /*
455 * Return dispatch table offset of the named static (built-in) function.
456 * Return -1 if function not found.
457 */
458 static GLint
459 get_static_proc_offset(const char *funcName)
460 {
461 GLuint i;
462 for (i = 0; static_functions[i].Name; i++) {
463 if (strcmp(static_functions[i].Name, funcName) == 0) {
464 return static_functions[i].Offset;
465 }
466 }
467 return -1;
468 }
469
470
471 /*
472 * Return dispatch function address the named static (built-in) function.
473 * Return NULL if function not found.
474 */
475 static GLvoid *
476 get_static_proc_address(const char *funcName)
477 {
478 GLint i;
479 for (i = 0; static_functions[i].Name; i++) {
480 if (strcmp(static_functions[i].Name, funcName) == 0) {
481 return static_functions[i].Address;
482 }
483 }
484 return NULL;
485 }
486
487
488
489 /**********************************************************************
490 * Extension function management.
491 */
492
493 /*
494 * Number of extension functions which we can dynamically add at runtime.
495 */
496 #define MAX_EXTENSION_FUNCS 300
497
498
499 /*
500 * The disptach table size (number of entries) is the sizeof the
501 * _glapi_table struct plus the number of dynamic entries we can add.
502 * The extra slots can be filled in by DRI drivers that register new extension
503 * functions.
504 */
505 #define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
506
507
508 static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
509 static GLuint NumExtEntryPoints = 0;
510
511 #ifdef USE_SPARC_ASM
512 extern void __glapi_sparc_icache_flush(unsigned int *);
513 #endif
514
515 /*
516 * Generate a dispatch function (entrypoint) which jumps through
517 * the given slot number (offset) in the current dispatch table.
518 * We need assembly language in order to accomplish this.
519 */
520 static void *
521 generate_entrypoint(GLuint functionOffset)
522 {
523 #if defined(USE_X86_ASM)
524 /*
525 * This x86 code contributed by Josh Vanderhoof.
526 *
527 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
528 * 00 01 02 03 04
529 * 5: 85 c0 testl %eax,%eax
530 * 05 06
531 * 7: 74 06 je f <entrypoint+0xf>
532 * 07 08
533 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
534 * 09 0a 0b 0c 0d 0e
535 * f: e8 fc ff ff ff call __glapi_get_dispatch
536 * 0f 10 11 12 13
537 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
538 * 14 15 16 17 18 19
539 */
540 static const unsigned char insn_template[] = {
541 0xa1, 0x00, 0x00, 0x00, 0x00,
542 0x85, 0xc0,
543 0x74, 0x06,
544 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
545 0xe8, 0x00, 0x00, 0x00, 0x00,
546 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
547 };
548 unsigned char *code = (unsigned char *) malloc(sizeof(insn_template));
549 unsigned int next_insn;
550 if (code) {
551 memcpy(code, insn_template, sizeof(insn_template));
552
553 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
554 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
555 next_insn = (unsigned int)(code + 0x14);
556 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
557 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
558 }
559 return code;
560 #elif defined(USE_SPARC_ASM)
561
562 #if defined(__sparc_v9__) && !defined(__linux__)
563 static const unsigned int insn_template[] = {
564 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
565 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
566 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
567 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
568 0x8528b020, /* sllx %g2, 32, %g2 */
569 0xc2584002, /* ldx [%g1 + %g2], %g1 */
570 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
571 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
572 0xc6584002, /* ldx [%g1 + %g2], %g3 */
573 0x81c0c000, /* jmpl %g3, %g0 */
574 0x01000000 /* nop */
575 };
576 #else
577 static const unsigned int insn_template[] = {
578 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
579 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
580 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
581 0x81c0c000, /* jmpl %g3, %g0 */
582 0x01000000 /* nop */
583 };
584 #endif
585 unsigned int *code = (unsigned int *) malloc(sizeof(insn_template));
586 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
587 if (code) {
588 memcpy(code, insn_template, sizeof(insn_template));
589
590 #if defined(__sparc_v9__) && !defined(__linux__)
591 code[0] |= (glapi_addr >> (32 + 10));
592 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
593 __glapi_sparc_icache_flush(&code[0]);
594 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
595 code[3] |= (glapi_addr & ((1 << 10) - 1));
596 __glapi_sparc_icache_flush(&code[2]);
597 code[6] |= ((functionOffset * 8) >> 10);
598 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
599 __glapi_sparc_icache_flush(&code[6]);
600 #else
601 code[0] |= (glapi_addr >> 10);
602 code[1] |= (glapi_addr & ((1 << 10) - 1));
603 __glapi_sparc_icache_flush(&code[0]);
604 code[2] |= (functionOffset * 4);
605 __glapi_sparc_icache_flush(&code[2]);
606 #endif
607 }
608 return code;
609 #else
610 return NULL;
611 #endif /* USE_*_ASM */
612 }
613
614
615 /*
616 * This function inserts a new dispatch offset into the assembly language
617 * stub that was generated with the preceeding function.
618 */
619 static void
620 fill_in_entrypoint_offset(void *entrypoint, GLuint offset)
621 {
622 #if defined(USE_X86_ASM)
623
624 unsigned char *code = (unsigned char *) entrypoint;
625 *(unsigned int *)(code + 0x0b) = offset * 4;
626 *(unsigned int *)(code + 0x16) = offset * 4;
627
628 #elif defined(USE_SPARC_ASM)
629
630 /* XXX this hasn't been tested! */
631 unsigned int *code = (unsigned int *) entrypoint;
632 #if defined(__sparc_v9__) && !defined(__linux__)
633 code[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
634 code[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
635 code[6] |= ((offset * 8) >> 10);
636 code[7] |= ((offset * 8) & ((1 << 10) - 1));
637 __glapi_sparc_icache_flush(&code[6]);
638 #else /* __sparc_v9__ && !linux */
639 code[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
640 code[2] |= (offset * 4);
641 __glapi_sparc_icache_flush(&code[2]);
642 #endif /* __sparc_v9__ && !linux */
643
644 #endif /* USE_*_ASM */
645 }
646
647
648 /*
649 * Add a new extension function entrypoint.
650 * Return: GL_TRUE = success or GL_FALSE = failure
651 */
652 GLboolean
653 _glapi_add_entrypoint(const char *funcName, GLuint offset)
654 {
655 /* trivial rejection test */
656 #ifdef MANGLE
657 if (!funcName || funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
658 return NULL;
659 #else
660 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
661 return GL_FALSE;
662 #endif
663
664 /* first check if the named function is already statically present */
665 {
666 GLint index = get_static_proc_offset(funcName);
667 if (index >= 0) {
668 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
669 }
670 }
671
672 /* See if this function has already been dynamically added */
673 {
674 GLuint i;
675 for (i = 0; i < NumExtEntryPoints; i++) {
676 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
677 /* function already registered */
678 if (ExtEntryTable[i].Offset == offset) {
679 return GL_TRUE; /* offsets match */
680 }
681 else if (ExtEntryTable[i].Offset == (GLuint) ~0
682 && offset < DISPATCH_TABLE_SIZE) {
683 /* need to patch-up the dispatch code */
684 if (offset != (GLuint) ~0) {
685 fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset);
686 ExtEntryTable[i].Offset = offset;
687 }
688 return GL_TRUE;
689 }
690 else {
691 return GL_FALSE; /* bad offset! */
692 }
693 }
694 }
695 }
696
697 /* This is a new function, try to add it. */
698 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS ||
699 offset >= DISPATCH_TABLE_SIZE) {
700 /* No space left */
701 return GL_FALSE;
702 }
703 else {
704 void *entrypoint = generate_entrypoint(offset);
705 if (!entrypoint)
706 return GL_FALSE; /* couldn't generate assembly */
707
708 /* OK! */
709 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
710 ExtEntryTable[NumExtEntryPoints].Offset = offset;
711 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
712 NumExtEntryPoints++;
713
714 return GL_TRUE; /* success */
715 }
716
717 /* should never get here, silence compiler warnings */
718 return GL_FALSE;
719 }
720
721
722 /*
723 * Return offset of entrypoint for named function within dispatch table.
724 */
725 GLint
726 _glapi_get_proc_offset(const char *funcName)
727 {
728 /* search extension functions first */
729 GLuint i;
730 for (i = 0; i < NumExtEntryPoints; i++) {
731 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
732 return ExtEntryTable[i].Offset;
733 }
734 }
735
736 /* search static functions */
737 return get_static_proc_offset(funcName);
738 }
739
740
741
742 /*
743 * Return entrypoint for named function.
744 */
745 const GLvoid *
746 _glapi_get_proc_address(const char *funcName)
747 {
748 GLuint i;
749
750 #ifdef MANGLE
751 if (funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
752 return NULL;
753 #else
754 if (funcName[0] != 'g' || funcName[1] != 'l')
755 return NULL;
756 #endif
757
758 /* search extension functions first */
759 for (i = 0; i < NumExtEntryPoints; i++) {
760 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
761 return ExtEntryTable[i].Address;
762 }
763 }
764
765 /* search static functions */
766 {
767 const GLvoid *func = get_static_proc_address(funcName);
768 if (func)
769 return func;
770 }
771
772 /* generate new entrypoint - use a temporary dispatch offset of
773 * ~0 (i.e. -1). Later, when the driver calls _glapi_add_entrypoint()
774 * we'll put in the proper offset. If that never happens, and the
775 * user calls this function, he'll segfault. That's what you get
776 * when you try calling a GL function that doesn't really exist.
777 */
778 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
779 GLvoid *entrypoint = generate_entrypoint(~0);
780 if (!entrypoint)
781 return GL_FALSE;
782
783 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
784 ExtEntryTable[NumExtEntryPoints].Offset = ~0;
785 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
786 NumExtEntryPoints++;
787
788 return entrypoint;
789 }
790 else {
791 /* no space for new functions! */
792 return NULL;
793 }
794 }
795
796
797
798 /*
799 * Return the name of the function at the given dispatch offset.
800 * This is only intended for debugging.
801 */
802 const char *
803 _glapi_get_proc_name(GLuint offset)
804 {
805 const GLuint n = sizeof(static_functions) / sizeof(struct name_address_offset);
806 GLuint i;
807
808 /* search built-in functions */
809 for (i = 0; i < n; i++) {
810 if (static_functions[i].Offset == offset)
811 return static_functions[i].Name;
812 }
813
814 /* search added extension functions */
815 for (i = 0; i < NumExtEntryPoints; i++) {
816 if (ExtEntryTable[i].Offset == offset) {
817 return ExtEntryTable[i].Name;
818 }
819 }
820 return NULL;
821 }
822
823
824
825 /*
826 * Return size of dispatch table struct as number of functions (or
827 * slots).
828 */
829 GLuint
830 _glapi_get_dispatch_table_size(void)
831 {
832 return DISPATCH_TABLE_SIZE;
833 }
834
835
836
837 /*
838 * Get API dispatcher version string.
839 */
840 const char *
841 _glapi_get_version(void)
842 {
843 return "20021001"; /* YYYYMMDD */
844 }
845
846
847
848 /*
849 * Make sure there are no NULL pointers in the given dispatch table.
850 * Intended for debugging purposes.
851 */
852 void
853 _glapi_check_table(const struct _glapi_table *table)
854 {
855 #ifdef DEBUG
856 const GLuint entries = _glapi_get_dispatch_table_size();
857 const void **tab = (const void **) table;
858 GLuint i;
859 for (i = 1; i < entries; i++) {
860 assert(tab[i]);
861 }
862
863 /* Do some spot checks to be sure that the dispatch table
864 * slots are assigned correctly.
865 */
866 {
867 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
868 char *BeginFunc = (char*) &table->Begin;
869 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
870 assert(BeginOffset == _gloffset_Begin);
871 assert(BeginOffset == offset);
872 }
873 {
874 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
875 char *viewportFunc = (char*) &table->Viewport;
876 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
877 assert(viewportOffset == _gloffset_Viewport);
878 assert(viewportOffset == offset);
879 }
880 {
881 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
882 char *VertexPointerFunc = (char*) &table->VertexPointer;
883 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
884 assert(VertexPointerOffset == _gloffset_VertexPointer);
885 assert(VertexPointerOffset == offset);
886 }
887 {
888 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
889 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
890 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
891 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
892 assert(ResetMinMaxOffset == offset);
893 }
894 {
895 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
896 char *blendColorFunc = (char*) &table->BlendColor;
897 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
898 assert(blendColorOffset == _gloffset_BlendColor);
899 assert(blendColorOffset == offset);
900 }
901 {
902 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
903 char *istextureFunc = (char*) &table->IsTextureEXT;
904 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
905 assert(istextureOffset == _gloffset_IsTextureEXT);
906 assert(istextureOffset == offset);
907 }
908 {
909 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
910 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
911 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
912 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
913 assert(secondaryColor3fOffset == offset);
914 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
915 }
916 {
917 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
918 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
919 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
920 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
921 assert(pointParameterivOffset == offset);
922 assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
923 }
924 {
925 GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
926 char *setFenceFunc = (char*) &table->SetFenceNV;
927 GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
928 assert(setFenceOffset == _gloffset_SetFenceNV);
929 assert(setFenceOffset == offset);
930 assert(_glapi_get_proc_address("glSetFenceNV") == (void *) &glSetFenceNV);
931 }
932 #endif
933 }