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