Subversion Repositories Kolibri OS

Rev

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

  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. }
  667.