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