OSDN Git Service

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