Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
55 pj 1
/* $Id: glapi.c,v 1.1 2003-02-28 11:42:01 pj 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
}