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 */
55static const glprocs_table_t *
56get_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 */
79static GLint
80get_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 */
96static _glapi_proc
97get_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 */
121static const char *
122get_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 */
143struct _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
185static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
186static GLuint NumExtEntryPoints = 0;
187
188
189static struct _glapi_function *
190get_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
202static GLint
203get_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
214static _glapi_proc
215get_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
226static const char *
227get_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 */
243static char *
244str_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
268static struct _glapi_function *
269add_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
304static struct _glapi_function *
305set_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
372int
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 */
486GLint
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 */
548const 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 */
574GLuint
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 */
591void
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 */
611void
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}
667