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