Home | History | Annotate | Download | only in glapi
      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 *
     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
     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
     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 *
    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 *
    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
    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
    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 *
    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 *
    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 *
    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 *
    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
    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
    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
    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 *
    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
    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