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