Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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