Another "if it ain't broke, don't fix it" moment. Revert some more
[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
137 #if defined(THREADS)
138
139 /**
140 * \name Multi-threaded control support variables
141 *
142 * If thread-safety is supported, there are two potential mechanisms that can
143 * be used. The old-style mechanism would set \c _glapi_Dispatch to a special
144 * thread-safe dispatch table. These dispatch routines would call
145 * \c _glapi_get_dispatch to get the actual dispatch pointer. In this
146 * setup \c _glapi_Dispatch could never be \c NULL. This dual layered
147 * dispatch setup performed great for single-threaded apps, but didn't
148 * perform well for multithreaded apps.
149 *
150 * In the new mechansim, there are two variables. The first is
151 * \c _glapi_DispatchTSD. In the single-threaded case, this variable points
152 * to the dispatch table. In the multi-threaded case, this variable is
153 * \c NULL, and thread-specific variable \c _gl_DispatchTSD points to the
154 * actual dispatch table. \c _glapi_DispatchTSD is used to signal to the
155 * static dispatch functions to call \c _glapi_get_dispatch to get the real
156 * dispatch table.
157 *
158 * There is a race condition in setting \c _glapi_DispatchTSD to \c NULL.
159 * It is possible for the original thread to be setting it at the same instant
160 * a new thread, perhaps running on a different processor, is clearing it.
161 * Because of that, \c ThreadSafe, which can only ever be changed to
162 * \c GL_FALSE, is used to determin whether or not the application is
163 * multithreaded.
164 */
165 /*@{*/
166 static GLboolean ThreadSafe = GL_FALSE; /**< In thread-safe mode? */
167 _glthread_TSD _gl_DispatchTSD; /**< Per-thread dispatch pointer */
168 static _glthread_TSD RealDispatchTSD; /**< only when using override */
169 static _glthread_TSD ContextTSD; /**< Per-thread context pointer */
170 /*@}*/
171
172
173 #define DISPATCH_TABLE_NAME __glapi_threadsafe_table
174 #define UNUSED_TABLE_NAME __usused_threadsafe_functions
175
176 #define TABLE_ENTRY(name) (void *) gl##name
177
178 static int glUnused(void)
179 {
180 return 0;
181 }
182
183 #include "glapitemp.h"
184
185 #endif
186
187 /***** END THREAD-SAFE DISPATCH *****/
188
189
190
191 struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
192 #if defined( THREADS )
193 struct _glapi_table *_glapi_DispatchTSD = (struct _glapi_table *) __glapi_noop_table;
194 #endif
195 struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
196
197
198 /* Used when thread safety disabled */
199 void *_glapi_Context = NULL;
200
201
202 static GLboolean DispatchOverride = GL_FALSE;
203
204
205
206 /* strdup() is actually not a standard ANSI C or POSIX routine.
207 * Irix will not define it if ANSI mode is in effect.
208 */
209 static char *
210 str_dup(const char *str)
211 {
212 char *copy;
213 copy = (char*) malloc(strlen(str) + 1);
214 if (!copy)
215 return NULL;
216 strcpy(copy, str);
217 return copy;
218 }
219
220
221
222 /*
223 * We should call this periodically from a function such as glXMakeCurrent
224 * in order to test if multiple threads are being used.
225 */
226 void
227 _glapi_check_multithread(void)
228 {
229 #if defined(THREADS)
230 if (!ThreadSafe) {
231 static unsigned long knownID;
232 static GLboolean firstCall = GL_TRUE;
233 if (firstCall) {
234 knownID = _glthread_GetID();
235 firstCall = GL_FALSE;
236 }
237 else if (knownID != _glthread_GetID()) {
238 ThreadSafe = GL_TRUE;
239 _glapi_set_dispatch(NULL);
240 }
241 }
242 else if (!_glapi_get_dispatch()) {
243 /* make sure that this thread's dispatch pointer isn't null */
244 _glapi_set_dispatch(NULL);
245 }
246 #endif
247 }
248
249
250
251 /*
252 * Set the current context pointer for this thread.
253 * The context pointer is an opaque type which should be cast to
254 * void from the real context pointer type.
255 */
256 void
257 _glapi_set_context(void *context)
258 {
259 #if defined(THREADS)
260 _glthread_SetTSD(&ContextTSD, context);
261 _glapi_Context = (ThreadSafe) ? NULL : context;
262 #else
263 _glapi_Context = context;
264 #endif
265 }
266
267
268
269 /*
270 * Get the current context pointer for this thread.
271 * The context pointer is an opaque type which should be cast from
272 * void to the real context pointer type.
273 */
274 void *
275 _glapi_get_context(void)
276 {
277 #if defined(THREADS)
278 if (ThreadSafe) {
279 return _glthread_GetTSD(&ContextTSD);
280 }
281 else {
282 return _glapi_Context;
283 }
284 #else
285 return _glapi_Context;
286 #endif
287 }
288
289
290
291 /*
292 * Set the global or per-thread dispatch table pointer.
293 */
294 void
295 _glapi_set_dispatch(struct _glapi_table *dispatch)
296 {
297 if (!dispatch) {
298 /* use the no-op functions */
299 dispatch = (struct _glapi_table *) __glapi_noop_table;
300 }
301 #ifdef DEBUG
302 else {
303 _glapi_check_table(dispatch);
304 }
305 #endif
306
307 #if defined(THREADS)
308 if (DispatchOverride) {
309 _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
310 if (ThreadSafe)
311 _glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
312 else
313 _glapi_RealDispatch = dispatch;
314 }
315 else {
316 /* normal operation */
317 _glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch);
318 if (ThreadSafe) {
319 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
320 _glapi_DispatchTSD = NULL;
321 }
322 else {
323 _glapi_Dispatch = dispatch;
324 _glapi_DispatchTSD = dispatch;
325 }
326 }
327 #else /*THREADS*/
328 if (DispatchOverride) {
329 _glapi_RealDispatch = dispatch;
330 }
331 else {
332 _glapi_Dispatch = dispatch;
333 }
334 #endif /*THREADS*/
335 }
336
337
338
339 /*
340 * Return pointer to current dispatch table for calling thread.
341 */
342 struct _glapi_table *
343 _glapi_get_dispatch(void)
344 {
345 #if defined(THREADS)
346 if (ThreadSafe) {
347 if (DispatchOverride) {
348 return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
349 }
350 else {
351 return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD);
352 }
353 }
354 else {
355 if (DispatchOverride) {
356 assert(_glapi_RealDispatch);
357 return _glapi_RealDispatch;
358 }
359 else {
360 assert(_glapi_DispatchTSD);
361 return _glapi_DispatchTSD;
362 }
363 }
364 #else
365 return _glapi_Dispatch;
366 #endif
367 }
368
369
370 /*
371 * Notes on dispatch overrride:
372 *
373 * Dispatch override allows an external agent to hook into the GL dispatch
374 * mechanism before execution goes into the core rendering library. For
375 * example, a trace mechanism would insert itself as an overrider, print
376 * logging info for each GL function, then dispatch to the real GL function.
377 *
378 * libGLS (GL Stream library) is another agent that might use override.
379 *
380 * We don't allow more than one layer of overriding at this time.
381 * In the future we may allow nested/layered override. In that case
382 * _glapi_begin_dispatch_override() will return an override layer,
383 * _glapi_end_dispatch_override(layer) will remove an override layer
384 * and _glapi_get_override_dispatch(layer) will return the dispatch
385 * table for a given override layer. layer = 0 will be the "real"
386 * dispatch table.
387 */
388
389 /*
390 * Return: dispatch override layer number.
391 */
392 int
393 _glapi_begin_dispatch_override(struct _glapi_table *override)
394 {
395 struct _glapi_table *real = _glapi_get_dispatch();
396
397 assert(!DispatchOverride); /* can't nest at this time */
398 DispatchOverride = GL_TRUE;
399
400 _glapi_set_dispatch(real);
401
402 #if defined(THREADS)
403 _glthread_SetTSD(&_gl_DispatchTSD, (void *) override);
404 if ( ThreadSafe ) {
405 _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
406 _glapi_DispatchTSD = NULL;
407 }
408 else {
409 _glapi_Dispatch = override;
410 _glapi_DispatchTSD = override;
411 }
412 #else
413 _glapi_Dispatch = override;
414 #endif
415 return 1;
416 }
417
418
419 void
420 _glapi_end_dispatch_override(int layer)
421 {
422 struct _glapi_table *real = _glapi_get_dispatch();
423 (void) layer;
424 DispatchOverride = GL_FALSE;
425 _glapi_set_dispatch(real);
426 /* the rest of this isn't needed, just play it safe */
427 #if defined(THREADS)
428 _glthread_SetTSD(&RealDispatchTSD, NULL);
429 #endif
430 _glapi_RealDispatch = NULL;
431 }
432
433
434 struct _glapi_table *
435 _glapi_get_override_dispatch(int layer)
436 {
437 if (layer == 0) {
438 return _glapi_get_dispatch();
439 }
440 else {
441 if (DispatchOverride) {
442 #if defined(THREADS)
443 return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD);
444 #else
445 return _glapi_Dispatch;
446 #endif
447 }
448 else {
449 return NULL;
450 }
451 }
452 }
453
454
455 struct name_address_offset {
456 const char *Name;
457 GLvoid *Address;
458 GLuint Offset;
459 };
460
461
462 #if !defined( USE_X86_ASM )
463 #define NEED_FUNCTION_POINTER
464 #endif
465
466 /* The code in this file is auto-generated with Python */
467 #include "glprocs.h"
468
469
470 static const glprocs_table_t *
471 find_entry( const char * n )
472 {
473 unsigned i;
474
475 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
476 const char * test_name;
477
478 test_name = gl_string_table + static_functions[i].Name_offset;
479 if (strcmp(test_name, n) == 0) {
480 return & static_functions[i];
481 }
482 }
483 return NULL;
484 }
485
486 /*
487 * Return dispatch table offset of the named static (built-in) function.
488 * Return -1 if function not found.
489 */
490 static GLint
491 get_static_proc_offset(const char *funcName)
492 {
493 const glprocs_table_t * const f = find_entry( funcName );
494
495 if ( f != NULL ) {
496 return f->Offset;
497 }
498 return -1;
499 }
500
501
502 #ifdef USE_X86_ASM
503 extern const GLubyte gl_dispatch_functions_start[];
504
505 # if defined(PTHREADS)
506 # define X86_DISPATCH_FUNCTION_SIZE 32
507 # else
508 # define X86_DISPATCH_FUNCTION_SIZE 16
509 # endif
510
511
512 /*
513 * Return dispatch function address the named static (built-in) function.
514 * Return NULL if function not found.
515 */
516 static const GLvoid *
517 get_static_proc_address(const char *funcName)
518 {
519 const glprocs_table_t * const f = find_entry( funcName );
520
521 if ( f != NULL ) {
522 return gl_dispatch_functions_start
523 + (X86_DISPATCH_FUNCTION_SIZE * f->Offset);
524 }
525 else {
526 return NULL;
527 }
528 }
529
530 #else
531
532
533 /*
534 * Return dispatch function address the named static (built-in) function.
535 * Return NULL if function not found.
536 */
537 static const GLvoid *
538 get_static_proc_address(const char *funcName)
539 {
540 const glprocs_table_t * const f = find_entry( funcName );
541 return ( f != NULL ) ? f->Address : NULL;
542 }
543
544 #endif /* USE_X86_ASM */
545
546
547 static const char *
548 get_static_proc_name( GLuint offset )
549 {
550 unsigned i;
551
552 for ( i = 0 ; static_functions[i].Name_offset >= 0 ; i++ ) {
553 if (static_functions[i].Offset == offset) {
554 return gl_string_table + static_functions[i].Name_offset;
555 }
556 }
557 return NULL;
558 }
559
560
561
562 /**********************************************************************
563 * Extension function management.
564 */
565
566 /*
567 * Number of extension functions which we can dynamically add at runtime.
568 */
569 #define MAX_EXTENSION_FUNCS 300
570
571
572 /*
573 * The disptach table size (number of entries) is the sizeof the
574 * _glapi_table struct plus the number of dynamic entries we can add.
575 * The extra slots can be filled in by DRI drivers that register new extension
576 * functions.
577 */
578 #define DISPATCH_TABLE_SIZE (sizeof(struct _glapi_table) / sizeof(void *) + MAX_EXTENSION_FUNCS)
579
580
581 static struct name_address_offset ExtEntryTable[MAX_EXTENSION_FUNCS];
582 static GLuint NumExtEntryPoints = 0;
583
584 #ifdef USE_SPARC_ASM
585 extern void __glapi_sparc_icache_flush(unsigned int *);
586 #endif
587
588 /*
589 * Generate a dispatch function (entrypoint) which jumps through
590 * the given slot number (offset) in the current dispatch table.
591 * We need assembly language in order to accomplish this.
592 */
593 static void *
594 generate_entrypoint(GLuint functionOffset)
595 {
596 #if defined(USE_X86_ASM)
597 /*
598 * This x86 code contributed by Josh Vanderhoof.
599 *
600 * 0: a1 10 32 54 76 movl __glapi_Dispatch,%eax
601 * 00 01 02 03 04
602 * 5: 85 c0 testl %eax,%eax
603 * 05 06
604 * 7: 74 06 je f <entrypoint+0xf>
605 * 07 08
606 * 9: ff a0 10 32 54 76 jmp *0x76543210(%eax)
607 * 09 0a 0b 0c 0d 0e
608 * f: e8 fc ff ff ff call __glapi_get_dispatch
609 * 0f 10 11 12 13
610 * 14: ff a0 10 32 54 76 jmp *0x76543210(%eax)
611 * 14 15 16 17 18 19
612 */
613 static const unsigned char insn_template[] = {
614 0xa1, 0x00, 0x00, 0x00, 0x00,
615 0x85, 0xc0,
616 0x74, 0x06,
617 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00,
618 0xe8, 0x00, 0x00, 0x00, 0x00,
619 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00
620 };
621 unsigned char *code = (unsigned char *) malloc(sizeof(insn_template));
622 unsigned int next_insn;
623 if (code) {
624 memcpy(code, insn_template, sizeof(insn_template));
625
626 #if defined( THREADS )
627 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_DispatchTSD;
628 #else
629 *(unsigned int *)(code + 0x01) = (unsigned int)&_glapi_Dispatch;
630 #endif
631 *(unsigned int *)(code + 0x0b) = (unsigned int)functionOffset * 4;
632 next_insn = (unsigned int)(code + 0x14);
633 *(unsigned int *)(code + 0x10) = (unsigned int)_glapi_get_dispatch - next_insn;
634 *(unsigned int *)(code + 0x16) = (unsigned int)functionOffset * 4;
635 }
636 return code;
637 #elif defined(USE_SPARC_ASM)
638
639 #if defined(__sparc_v9__) && !defined(__linux__)
640 static const unsigned int insn_template[] = {
641 0x05000000, /* sethi %uhi(_glapi_Dispatch), %g2 */
642 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
643 0x8410a000, /* or %g2, %ulo(_glapi_Dispatch), %g2 */
644 0x82106000, /* or %g1, %lo(_glapi_Dispatch), %g1 */
645 0x8528b020, /* sllx %g2, 32, %g2 */
646 0xc2584002, /* ldx [%g1 + %g2], %g1 */
647 0x05000000, /* sethi %hi(8 * glapioffset), %g2 */
648 0x8410a000, /* or %g2, %lo(8 * glapioffset), %g2 */
649 0xc6584002, /* ldx [%g1 + %g2], %g3 */
650 0x81c0c000, /* jmpl %g3, %g0 */
651 0x01000000 /* nop */
652 };
653 #else
654 static const unsigned int insn_template[] = {
655 0x03000000, /* sethi %hi(_glapi_Dispatch), %g1 */
656 0xc2006000, /* ld [%g1 + %lo(_glapi_Dispatch)], %g1 */
657 0xc6006000, /* ld [%g1 + %lo(4*glapioffset)], %g3 */
658 0x81c0c000, /* jmpl %g3, %g0 */
659 0x01000000 /* nop */
660 };
661 #endif
662 unsigned int *code = (unsigned int *) malloc(sizeof(insn_template));
663 unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
664 if (code) {
665 memcpy(code, insn_template, sizeof(insn_template));
666
667 #if defined(__sparc_v9__) && !defined(__linux__)
668 code[0] |= (glapi_addr >> (32 + 10));
669 code[1] |= ((glapi_addr & 0xffffffff) >> 10);
670 __glapi_sparc_icache_flush(&code[0]);
671 code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
672 code[3] |= (glapi_addr & ((1 << 10) - 1));
673 __glapi_sparc_icache_flush(&code[2]);
674 code[6] |= ((functionOffset * 8) >> 10);
675 code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
676 __glapi_sparc_icache_flush(&code[6]);
677 #else
678 code[0] |= (glapi_addr >> 10);
679 code[1] |= (glapi_addr & ((1 << 10) - 1));
680 __glapi_sparc_icache_flush(&code[0]);
681 code[2] |= (functionOffset * 4);
682 __glapi_sparc_icache_flush(&code[2]);
683 #endif
684 }
685 return code;
686 #else
687 return NULL;
688 #endif /* USE_*_ASM */
689 }
690
691
692 /*
693 * This function inserts a new dispatch offset into the assembly language
694 * stub that was generated with the preceeding function.
695 */
696 static void
697 fill_in_entrypoint_offset(void *entrypoint, GLuint offset)
698 {
699 #if defined(USE_X86_ASM)
700
701 unsigned char *code = (unsigned char *) entrypoint;
702 *(unsigned int *)(code + 0x0b) = offset * 4;
703 *(unsigned int *)(code + 0x16) = offset * 4;
704
705 #elif defined(USE_SPARC_ASM)
706
707 /* XXX this hasn't been tested! */
708 unsigned int *code = (unsigned int *) entrypoint;
709 #if defined(__sparc_v9__) && !defined(__linux__)
710 code[6] = 0x05000000; /* sethi %hi(8 * glapioffset), %g2 */
711 code[7] = 0x8410a000; /* or %g2, %lo(8 * glapioffset), %g2 */
712 code[6] |= ((offset * 8) >> 10);
713 code[7] |= ((offset * 8) & ((1 << 10) - 1));
714 __glapi_sparc_icache_flush(&code[6]);
715 #else /* __sparc_v9__ && !linux */
716 code[2] = 0xc6006000; /* ld [%g1 + %lo(4*glapioffset)], %g3 */
717 code[2] |= (offset * 4);
718 __glapi_sparc_icache_flush(&code[2]);
719 #endif /* __sparc_v9__ && !linux */
720
721 #endif /* USE_*_ASM */
722 }
723
724
725 /*
726 * Add a new extension function entrypoint.
727 * Return: GL_TRUE = success or GL_FALSE = failure
728 */
729 GLboolean
730 _glapi_add_entrypoint(const char *funcName, GLuint offset)
731 {
732 /* trivial rejection test */
733 #ifdef MANGLE
734 if (!funcName || funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
735 return NULL;
736 #else
737 if (!funcName || funcName[0] != 'g' || funcName[1] != 'l')
738 return GL_FALSE;
739 #endif
740
741 /* first check if the named function is already statically present */
742 {
743 GLint index = get_static_proc_offset(funcName);
744 if (index >= 0) {
745 return (GLboolean) ((GLuint) index == offset); /* bad offset! */
746 }
747 }
748
749 /* See if this function has already been dynamically added */
750 {
751 GLuint i;
752 for (i = 0; i < NumExtEntryPoints; i++) {
753 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
754 /* function already registered */
755 if (ExtEntryTable[i].Offset == offset) {
756 return GL_TRUE; /* offsets match */
757 }
758 else if (ExtEntryTable[i].Offset == (GLuint) ~0
759 && offset < DISPATCH_TABLE_SIZE) {
760 /* need to patch-up the dispatch code */
761 if (offset != (GLuint) ~0) {
762 fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset);
763 ExtEntryTable[i].Offset = offset;
764 }
765 return GL_TRUE;
766 }
767 else {
768 return GL_FALSE; /* bad offset! */
769 }
770 }
771 }
772 }
773
774 /* This is a new function, try to add it. */
775 if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS ||
776 offset >= DISPATCH_TABLE_SIZE) {
777 /* No space left */
778 return GL_FALSE;
779 }
780 else {
781 void *entrypoint = generate_entrypoint(offset);
782 if (!entrypoint)
783 return GL_FALSE; /* couldn't generate assembly */
784
785 /* OK! */
786 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
787 ExtEntryTable[NumExtEntryPoints].Offset = offset;
788 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
789 NumExtEntryPoints++;
790
791 return GL_TRUE; /* success */
792 }
793
794 /* should never get here, silence compiler warnings */
795 return GL_FALSE;
796 }
797
798
799 /*
800 * Return offset of entrypoint for named function within dispatch table.
801 */
802 GLint
803 _glapi_get_proc_offset(const char *funcName)
804 {
805 /* search extension functions first */
806 GLuint i;
807 for (i = 0; i < NumExtEntryPoints; i++) {
808 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
809 return ExtEntryTable[i].Offset;
810 }
811 }
812
813 /* search static functions */
814 return get_static_proc_offset(funcName);
815 }
816
817
818
819 /*
820 * Return entrypoint for named function.
821 */
822 const GLvoid *
823 _glapi_get_proc_address(const char *funcName)
824 {
825 GLuint i;
826
827 #ifdef MANGLE
828 if (funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l')
829 return NULL;
830 #else
831 if (funcName[0] != 'g' || funcName[1] != 'l')
832 return NULL;
833 #endif
834
835 /* search extension functions first */
836 for (i = 0; i < NumExtEntryPoints; i++) {
837 if (strcmp(ExtEntryTable[i].Name, funcName) == 0) {
838 return ExtEntryTable[i].Address;
839 }
840 }
841
842 /* search static functions */
843 {
844 const GLvoid *func = get_static_proc_address(funcName);
845 if (func)
846 return func;
847 }
848
849 /* generate new entrypoint - use a temporary dispatch offset of
850 * ~0 (i.e. -1). Later, when the driver calls _glapi_add_entrypoint()
851 * we'll put in the proper offset. If that never happens, and the
852 * user calls this function, he'll segfault. That's what you get
853 * when you try calling a GL function that doesn't really exist.
854 */
855 if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
856 GLvoid *entrypoint = generate_entrypoint(~0);
857 if (!entrypoint)
858 return GL_FALSE;
859
860 ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName);
861 ExtEntryTable[NumExtEntryPoints].Offset = ~0;
862 ExtEntryTable[NumExtEntryPoints].Address = entrypoint;
863 NumExtEntryPoints++;
864
865 return entrypoint;
866 }
867 else {
868 /* no space for new functions! */
869 return NULL;
870 }
871 }
872
873
874
875 /*
876 * Return the name of the function at the given dispatch offset.
877 * This is only intended for debugging.
878 */
879 const char *
880 _glapi_get_proc_name(GLuint offset)
881 {
882 GLuint i;
883 const char * n;
884
885 /* search built-in functions */
886 n = get_static_proc_name(offset);
887 if ( n != NULL ) {
888 return n;
889 }
890
891 /* search added extension functions */
892 for (i = 0; i < NumExtEntryPoints; i++) {
893 if (ExtEntryTable[i].Offset == offset) {
894 return ExtEntryTable[i].Name;
895 }
896 }
897 return NULL;
898 }
899
900
901
902 /*
903 * Return size of dispatch table struct as number of functions (or
904 * slots).
905 */
906 GLuint
907 _glapi_get_dispatch_table_size(void)
908 {
909 return DISPATCH_TABLE_SIZE;
910 }
911
912
913
914 /*
915 * Get API dispatcher version string.
916 */
917 const char *
918 _glapi_get_version(void)
919 {
920 return "20021001"; /* YYYYMMDD */
921 }
922
923
924
925 /*
926 * Make sure there are no NULL pointers in the given dispatch table.
927 * Intended for debugging purposes.
928 */
929 void
930 _glapi_check_table(const struct _glapi_table *table)
931 {
932 #ifdef DEBUG
933 const GLuint entries = _glapi_get_dispatch_table_size();
934 const void **tab = (const void **) table;
935 GLuint i;
936 for (i = 1; i < entries; i++) {
937 assert(tab[i]);
938 }
939
940 /* Do some spot checks to be sure that the dispatch table
941 * slots are assigned correctly.
942 */
943 {
944 GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
945 char *BeginFunc = (char*) &table->Begin;
946 GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
947 assert(BeginOffset == _gloffset_Begin);
948 assert(BeginOffset == offset);
949 }
950 {
951 GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
952 char *viewportFunc = (char*) &table->Viewport;
953 GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
954 assert(viewportOffset == _gloffset_Viewport);
955 assert(viewportOffset == offset);
956 }
957 {
958 GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
959 char *VertexPointerFunc = (char*) &table->VertexPointer;
960 GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
961 assert(VertexPointerOffset == _gloffset_VertexPointer);
962 assert(VertexPointerOffset == offset);
963 }
964 {
965 GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
966 char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
967 GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
968 assert(ResetMinMaxOffset == _gloffset_ResetMinmax);
969 assert(ResetMinMaxOffset == offset);
970 }
971 {
972 GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
973 char *blendColorFunc = (char*) &table->BlendColor;
974 GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
975 assert(blendColorOffset == _gloffset_BlendColor);
976 assert(blendColorOffset == offset);
977 }
978 {
979 GLuint istextureOffset = _glapi_get_proc_offset("glIsTextureEXT");
980 char *istextureFunc = (char*) &table->IsTextureEXT;
981 GLuint offset = (istextureFunc - (char *) table) / sizeof(void *);
982 assert(istextureOffset == _gloffset_IsTextureEXT);
983 assert(istextureOffset == offset);
984 }
985 {
986 GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
987 char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
988 GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
989 assert(secondaryColor3fOffset == _gloffset_SecondaryColor3fEXT);
990 assert(secondaryColor3fOffset == offset);
991 assert(_glapi_get_proc_address("glSecondaryColor3fEXT") == (void *) &glSecondaryColor3fEXT);
992 }
993 {
994 GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
995 char *pointParameterivFunc = (char*) &table->PointParameterivNV;
996 GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
997 assert(pointParameterivOffset == _gloffset_PointParameterivNV);
998 assert(pointParameterivOffset == offset);
999 assert(_glapi_get_proc_address("glPointParameterivNV") == (void *) &glPointParameterivNV);
1000 }
1001 {
1002 GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
1003 char *setFenceFunc = (char*) &table->SetFenceNV;
1004 GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
1005 assert(setFenceOffset == _gloffset_SetFenceNV);
1006 assert(setFenceOffset == offset);
1007 assert(_glapi_get_proc_address("glSetFenceNV") == (void *) &glSetFenceNV);
1008 }
1009 #endif
1010 }