Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 1
/*
2
 * Mesa 3-D graphics library
3
 * Version:  7.1
4
 *
5
 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included
15
 * in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
 */
24
 
25
/**
26
 * \file glapi_getproc.c
27
 *
28
 * Code for implementing glXGetProcAddress(), etc.
29
 * This was originally in glapi.c but refactored out.
30
 */
31
 
32
 
33
#include "glapi/glapi_priv.h"
34
#include "glapi/glapitable.h"
35
 
36
 
37
#define FIRST_DYNAMIC_OFFSET (sizeof(struct _glapi_table) / sizeof(void *))
38
 
39
 
40
/**********************************************************************
41
 * Static function management.
42
 */
43
 
44
 
45
#if !defined(DISPATCH_FUNCTION_SIZE)
46
# define NEED_FUNCTION_POINTER
47
#endif
48
#include "glapi/glprocs.h"
49
 
50
 
51
/**
52
 * Search the table of static entrypoint functions for the named function
53
 * and return the corresponding glprocs_table_t entry.
54
 */
55
static const glprocs_table_t *
56
get_static_proc( const char * n )
57
{
58
   GLuint i;
59
   for (i = 0; static_functions[i].Name_offset >= 0; i++) {
60
      const char *testName = gl_string_table + static_functions[i].Name_offset;
61
#ifdef MANGLE
62
      /* skip the prefix on the name */
63
      if (strcmp(testName, n + 1) == 0)
64
#else
65
      if (strcmp(testName, n) == 0)
66
#endif
67
      {
68
	 return &static_functions[i];
69
      }
70
   }
71
   return NULL;
72
}
73
 
74
 
75
/**
76
 * Return dispatch table offset of the named static (built-in) function.
77
 * Return -1 if function not found.
78
 */
79
static GLint
80
get_static_proc_offset(const char *funcName)
81
{
82
   const glprocs_table_t * const f = get_static_proc( funcName );
83
   if (f == NULL) {
84
      return -1;
85
   }
86
 
87
   return f->Offset;
88
}
89
 
90
 
91
 
92
/**
93
 * Return dispatch function address for the named static (built-in) function.
94
 * Return NULL if function not found.
95
 */
96
static _glapi_proc
97
get_static_proc_address(const char *funcName)
98
{
99
   const glprocs_table_t * const f = get_static_proc( funcName );
100
   if (f == NULL) {
101
      return NULL;
102
   }
103
 
104
#if defined(DISPATCH_FUNCTION_SIZE) && defined(GLX_INDIRECT_RENDERING)
105
   return (f->Address == NULL)
106
      ? get_entrypoint_address(f->Offset)
107
      : f->Address;
108
#elif defined(DISPATCH_FUNCTION_SIZE)
109
   return get_entrypoint_address(f->Offset);
110
#else
111
   return f->Address;
112
#endif
113
}
114
 
115
 
116
 
117
/**
118
 * Return the name of the function at the given offset in the dispatch
119
 * table.  For debugging only.
120
 */
121
static const char *
122
get_static_proc_name( GLuint offset )
123
{
124
   GLuint i;
125
   for (i = 0; static_functions[i].Name_offset >= 0; i++) {
126
      if (static_functions[i].Offset == offset) {
127
	 return gl_string_table + static_functions[i].Name_offset;
128
      }
129
   }
130
   return NULL;
131
}
132
 
133
 
134
 
135
/**********************************************************************
136
 * Extension function management.
137
 */
138
 
139
 
140
/**
141
 * Track information about a function added to the GL API.
142
 */
143
struct _glapi_function {
144
   /**
145
    * Name of the function.
146
    */
147
   const char * name;
148
 
149
 
150
   /**
151
    * Text string that describes the types of the parameters passed to the
152
    * named function.   Parameter types are converted to characters using the
153
    * following rules:
154
    *   - 'i' for \c GLint, \c GLuint, and \c GLenum
155
    *   - 'p' for any pointer type
156
    *   - 'f' for \c GLfloat and \c GLclampf
157
    *   - 'd' for \c GLdouble and \c GLclampd
158
    */
159
   const char * parameter_signature;
160
 
161
 
162
   /**
163
    * Offset in the dispatch table where the pointer to the real function is
164
    * located.  If the driver has not requested that the named function be
165
    * added to the dispatch table, this will have the value ~0.
166
    */
167
   unsigned dispatch_offset;
168
 
169
 
170
   /**
171
    * Pointer to the dispatch stub for the named function.
172
    *
173
    * \todo
174
    * The semantic of this field should be changed slightly.  Currently, it
175
    * is always expected to be non-\c NULL.  However, it would be better to
176
    * only allocate the entry-point stub when the application requests the
177
    * function via \c glXGetProcAddress.  This would save memory for all the
178
    * functions that the driver exports but that the application never wants
179
    * to call.
180
    */
181
   _glapi_proc dispatch_stub;
182
};
183
 
184
 
185
static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
186
static GLuint NumExtEntryPoints = 0;
187
 
188
 
189
static struct _glapi_function *
190
get_extension_proc(const char *funcName)
191
{
192
   GLuint i;
193
   for (i = 0; i < NumExtEntryPoints; i++) {
194
      if (strcmp(ExtEntryTable[i].name, funcName) == 0) {
195
         return & ExtEntryTable[i];
196
      }
197
   }
198
   return NULL;
199
}
200
 
201
 
202
static GLint
203
get_extension_proc_offset(const char *funcName)
204
{
205
   const struct _glapi_function * const f = get_extension_proc( funcName );
206
   if (f == NULL) {
207
      return -1;
208
   }
209
 
210
   return f->dispatch_offset;
211
}
212
 
213
 
214
static _glapi_proc
215
get_extension_proc_address(const char *funcName)
216
{
217
   const struct _glapi_function * const f = get_extension_proc( funcName );
218
   if (f == NULL) {
219
      return NULL;
220
   }
221
 
222
   return f->dispatch_stub;
223
}
224
 
225
 
226
static const char *
227
get_extension_proc_name(GLuint offset)
228
{
229
   GLuint i;
230
   for (i = 0; i < NumExtEntryPoints; i++) {
231
      if (ExtEntryTable[i].dispatch_offset == offset) {
232
         return ExtEntryTable[i].name;
233
      }
234
   }
235
   return NULL;
236
}
237
 
238
 
239
/**
240
 * strdup() is actually not a standard ANSI C or POSIX routine.
241
 * Irix will not define it if ANSI mode is in effect.
242
 */
243
static char *
244
str_dup(const char *str)
245
{
246
   char *copy;
247
   copy = (char*) malloc(strlen(str) + 1);
248
   if (!copy)
249
      return NULL;
250
   strcpy(copy, str);
251
   return copy;
252
}
253
 
254
 
255
/**
256
 * Generate new entrypoint
257
 *
258
 * Use a temporary dispatch offset of ~0 (i.e. -1).  Later, when the driver
259
 * calls \c _glapi_add_dispatch we'll put in the proper offset.  If that
260
 * never happens, and the user calls this function, he'll segfault.  That's
261
 * what you get when you try calling a GL function that doesn't really exist.
262
 *
263
 * \param funcName  Name of the function to create an entry-point for.
264
 *
265
 * \sa _glapi_add_entrypoint
266
 */
267
 
268
static struct _glapi_function *
269
add_function_name( const char * funcName )
270
{
271
   struct _glapi_function * entry = NULL;
272
   _glapi_proc entrypoint = NULL;
273
   char * name_dup = NULL;
274
 
275
   if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS)
276
      return NULL;
277
 
278
   if (funcName == NULL)
279
      return NULL;
280
 
281
   name_dup = str_dup(funcName);
282
   if (name_dup == NULL)
283
      return NULL;
284
 
285
   entrypoint = generate_entrypoint(~0);
286
 
287
   if (entrypoint == NULL) {
288
      free(name_dup);
289
      return NULL;
290
   }
291
 
292
   entry = & ExtEntryTable[NumExtEntryPoints];
293
   NumExtEntryPoints++;
294
 
295
   entry->name = name_dup;
296
   entry->parameter_signature = NULL;
297
   entry->dispatch_offset = ~0;
298
   entry->dispatch_stub = entrypoint;
299
 
300
   return entry;
301
}
302
 
303
 
304
static struct _glapi_function *
305
set_entry_info( struct _glapi_function * entry, const char * signature, unsigned offset )
306
{
307
   char * sig_dup = NULL;
308
 
309
   if (signature == NULL)
310
      return NULL;
311
 
312
   sig_dup = str_dup(signature);
313
   if (sig_dup == NULL)
314
      return NULL;
315
 
316
   fill_in_entrypoint_offset(entry->dispatch_stub, offset);
317
 
318
   entry->parameter_signature = sig_dup;
319
   entry->dispatch_offset = offset;
320
 
321
   return entry;
322
}
323
 
324
 
325
/**
326
 * Fill-in the dispatch stub for the named function.
327
 *
328
 * This function is intended to be called by a hardware driver.  When called,
329
 * a dispatch stub may be created created for the function.  A pointer to this
330
 * dispatch function will be returned by glXGetProcAddress.
331
 *
332
 * \param function_names       Array of pointers to function names that should
333
 *                             share a common dispatch offset.
334
 * \param parameter_signature  String representing the types of the parameters
335
 *                             passed to the named function.  Parameter types
336
 *                             are converted to characters using the following
337
 *                             rules:
338
 *                               - 'i' for \c GLint, \c GLuint, and \c GLenum
339
 *                               - 'p' for any pointer type
340
 *                               - 'f' for \c GLfloat and \c GLclampf
341
 *                               - 'd' for \c GLdouble and \c GLclampd
342
 *
343
 * \returns
344
 * The offset in the dispatch table of the named function.  A pointer to the
345
 * driver's implementation of the named function should be stored at
346
 * \c dispatch_table[\c offset].  Return -1 if error/problem.
347
 *
348
 * \sa glXGetProcAddress
349
 *
350
 * \warning
351
 * This function can only handle up to 8 names at a time.  As far as I know,
352
 * the maximum number of names ever associated with an existing GL function is
353
 * 4 (\c glPointParameterfSGIS, \c glPointParameterfEXT,
354
 * \c glPointParameterfARB, and \c glPointParameterf), so this should not be
355
 * too painful of a limitation.
356
 *
357
 * \todo
358
 * Determine whether or not \c parameter_signature should be allowed to be
359
 * \c NULL.  It doesn't seem like much of a hardship for drivers to have to
360
 * pass in an empty string.
361
 *
362
 * \todo
363
 * Determine if code should be added to reject function names that start with
364
 * 'glX'.
365
 *
366
 * \bug
367
 * Add code to compare \c parameter_signature with the parameter signature of
368
 * a static function.  In order to do that, we need to find a way to \b get
369
 * the parameter signature of a static function.
370
 */
371
 
372
int
373
_glapi_add_dispatch( const char * const * function_names,
374
		     const char * parameter_signature )
375
{
376
   static int next_dynamic_offset = FIRST_DYNAMIC_OFFSET;
377
   const char * const real_sig = (parameter_signature != NULL)
378
     ? parameter_signature : "";
379
   struct _glapi_function * entry[8];
380
   GLboolean is_static[8];
381
   unsigned i;
382
   int offset = ~0;
383
 
384
   init_glapi_relocs_once();
385
 
386
   (void) memset( is_static, 0, sizeof( is_static ) );
387
   (void) memset( entry, 0, sizeof( entry ) );
388
 
389
   /* Find the _single_ dispatch offset for all function names that already
390
    * exist (and have a dispatch offset).
391
    */
392
 
393
   for ( i = 0 ; function_names[i] != NULL ; i++ ) {
394
      const char * funcName = function_names[i];
395
      int static_offset;
396
      int extension_offset;
397
 
398
      if (funcName[0] != 'g' || funcName[1] != 'l')
399
         return -1;
400
 
401
      /* search built-in functions */
402
      static_offset = get_static_proc_offset(funcName);
403
 
404
      if (static_offset >= 0) {
405
 
406
	 is_static[i] = GL_TRUE;
407
 
408
	 /* FIXME: Make sure the parameter signatures match!  How do we get
409
	  * FIXME: the parameter signature for static functions?
410
	  */
411
 
412
	 if ( (offset != ~0) && (static_offset != offset) ) {
413
	    return -1;
414
	 }
415
 
416
	 offset = static_offset;
417
 
418
	 continue;
419
      }
420
 
421
      /* search added extension functions */
422
      entry[i] = get_extension_proc(funcName);
423
 
424
      if (entry[i] != NULL) {
425
	 extension_offset = entry[i]->dispatch_offset;
426
 
427
	 /* The offset may be ~0 if the function name was added by
428
	  * glXGetProcAddress but never filled in by the driver.
429
	  */
430
 
431
	 if (extension_offset == ~0) {
432
	    continue;
433
	 }
434
 
435
	 if (strcmp(real_sig, entry[i]->parameter_signature) != 0) {
436
	    return -1;
437
	 }
438
 
439
	 if ( (offset != ~0) && (extension_offset != offset) ) {
440
	    return -1;
441
	 }
442
 
443
	 offset = extension_offset;
444
      }
445
   }
446
 
447
   /* If all function names are either new (or with no dispatch offset),
448
    * allocate a new dispatch offset.
449
    */
450
 
451
   if (offset == ~0) {
452
      offset = next_dynamic_offset;
453
      next_dynamic_offset++;
454
   }
455
 
456
   /* Fill in the dispatch offset for the new function names (and those with
457
    * no dispatch offset).
458
    */
459
 
460
   for ( i = 0 ; function_names[i] != NULL ; i++ ) {
461
      if (is_static[i]) {
462
	 continue;
463
      }
464
 
465
      /* generate entrypoints for new function names */
466
      if (entry[i] == NULL) {
467
	 entry[i] = add_function_name( function_names[i] );
468
	 if (entry[i] == NULL) {
469
	    /* FIXME: Possible memory leak here. */
470
	    return -1;
471
	 }
472
      }
473
 
474
      if (entry[i]->dispatch_offset == ~0) {
475
	 set_entry_info( entry[i], real_sig, offset );
476
      }
477
   }
478
 
479
   return offset;
480
}
481
 
482
 
483
/**
484
 * Return offset of entrypoint for named function within dispatch table.
485
 */
486
GLint
487
_glapi_get_proc_offset(const char *funcName)
488
{
489
   GLint offset;
490
 
491
   /* search extension functions first */
492
   offset = get_extension_proc_offset(funcName);
493
   if (offset >= 0)
494
      return offset;
495
 
496
   /* search static functions */
497
   return get_static_proc_offset(funcName);
498
}
499
 
500
 
501
 
502
/**
503
 * Return pointer to the named function.  If the function name isn't found
504
 * in the name of static functions, try generating a new API entrypoint on
505
 * the fly with assembly language.
506
 */
507
_glapi_proc
508
_glapi_get_proc_address(const char *funcName)
509
{
510
   _glapi_proc func;
511
   struct _glapi_function * entry;
512
 
513
   init_glapi_relocs_once();
514
 
515
#ifdef MANGLE
516
   /* skip the prefix on the name */
517
   if (funcName[1] != 'g' || funcName[2] != 'l')
518
      return NULL;
519
#else
520
   if (funcName[0] != 'g' || funcName[1] != 'l')
521
      return NULL;
522
#endif
523
 
524
   /* search extension functions first */
525
   func = get_extension_proc_address(funcName);
526
   if (func)
527
      return func;
528
 
529
   /* search static functions */
530
   func = get_static_proc_address(funcName);
531
   if (func)
532
      return func;
533
 
534
   /* generate entrypoint, dispatch offset must be filled in by the driver */
535
   entry = add_function_name(funcName);
536
   if (entry == NULL)
537
      return NULL;
538
 
539
   return entry->dispatch_stub;
540
}
541
 
542
 
543
 
544
/**
545
 * Return the name of the function at the given dispatch offset.
546
 * This is only intended for debugging.
547
 */
548
const char *
549
_glapi_get_proc_name(GLuint offset)
550
{
551
   const char * n;
552
 
553
   /* search built-in functions */
554
   n = get_static_proc_name(offset);
555
   if ( n != NULL ) {
556
      return n;
557
   }
558
 
559
   /* search added extension functions */
560
   return get_extension_proc_name(offset);
561
}
562
 
563
 
564
 
565
/**********************************************************************
566
 * GL API table functions.
567
 */
568
 
569
 
570
/**
571
 * Return size of dispatch table struct as number of functions (or
572
 * slots).
573
 */
574
GLuint
575
_glapi_get_dispatch_table_size(void)
576
{
577
   /*
578
    * The dispatch table size (number of entries) is the size of the
579
    * _glapi_table struct plus the number of dynamic entries we can add.
580
    * The extra slots can be filled in by DRI drivers that register new
581
    * extension functions.
582
    */
583
   return FIRST_DYNAMIC_OFFSET + MAX_EXTENSION_FUNCS;
584
}
585
 
586
 
587
/**
588
 * Make sure there are no NULL pointers in the given dispatch table.
589
 * Intended for debugging purposes.
590
 */
591
void
592
_glapi_check_table_not_null(const struct _glapi_table *table)
593
{
594
#ifdef EXTRA_DEBUG /* set to DEBUG for extra DEBUG */
595
   const GLuint entries = _glapi_get_dispatch_table_size();
596
   const void **tab = (const void **) table;
597
   GLuint i;
598
   for (i = 1; i < entries; i++) {
599
      assert(tab[i]);
600
   }
601
#else
602
   (void) table;
603
#endif
604
}
605
 
606
 
607
/**
608
 * Do some spot checks to be sure that the dispatch table
609
 * slots are assigned correctly. For debugging only.
610
 */
611
void
612
_glapi_check_table(const struct _glapi_table *table)
613
{
614
#ifdef EXTRA_DEBUG /* set to DEBUG for extra DEBUG */
615
   {
616
      GLuint BeginOffset = _glapi_get_proc_offset("glBegin");
617
      char *BeginFunc = (char*) &table->Begin;
618
      GLuint offset = (BeginFunc - (char *) table) / sizeof(void *);
619
      assert(BeginOffset == offset);
620
   }
621
   {
622
      GLuint viewportOffset = _glapi_get_proc_offset("glViewport");
623
      char *viewportFunc = (char*) &table->Viewport;
624
      GLuint offset = (viewportFunc - (char *) table) / sizeof(void *);
625
      assert(viewportOffset == offset);
626
   }
627
   {
628
      GLuint VertexPointerOffset = _glapi_get_proc_offset("glVertexPointer");
629
      char *VertexPointerFunc = (char*) &table->VertexPointer;
630
      GLuint offset = (VertexPointerFunc - (char *) table) / sizeof(void *);
631
      assert(VertexPointerOffset == offset);
632
   }
633
   {
634
      GLuint ResetMinMaxOffset = _glapi_get_proc_offset("glResetMinmax");
635
      char *ResetMinMaxFunc = (char*) &table->ResetMinmax;
636
      GLuint offset = (ResetMinMaxFunc - (char *) table) / sizeof(void *);
637
      assert(ResetMinMaxOffset == offset);
638
   }
639
   {
640
      GLuint blendColorOffset = _glapi_get_proc_offset("glBlendColor");
641
      char *blendColorFunc = (char*) &table->BlendColor;
642
      GLuint offset = (blendColorFunc - (char *) table) / sizeof(void *);
643
      assert(blendColorOffset == offset);
644
   }
645
   {
646
      GLuint secondaryColor3fOffset = _glapi_get_proc_offset("glSecondaryColor3fEXT");
647
      char *secondaryColor3fFunc = (char*) &table->SecondaryColor3fEXT;
648
      GLuint offset = (secondaryColor3fFunc - (char *) table) / sizeof(void *);
649
      assert(secondaryColor3fOffset == offset);
650
   }
651
   {
652
      GLuint pointParameterivOffset = _glapi_get_proc_offset("glPointParameterivNV");
653
      char *pointParameterivFunc = (char*) &table->PointParameterivNV;
654
      GLuint offset = (pointParameterivFunc - (char *) table) / sizeof(void *);
655
      assert(pointParameterivOffset == offset);
656
   }
657
   {
658
      GLuint setFenceOffset = _glapi_get_proc_offset("glSetFenceNV");
659
      char *setFenceFunc = (char*) &table->SetFenceNV;
660
      GLuint offset = (setFenceFunc - (char *) table) / sizeof(void *);
661
      assert(setFenceOffset == offset);
662
   }
663
#else
664
   (void) table;
665
#endif
666
}