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