Index: src/mesa/glapi/glapi.c =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/glapi/glapi.c,v retrieving revision 1.92 diff -u -d -r1.92 glapi.c --- src/mesa/glapi/glapi.c 28 Apr 2005 13:16:23 -0000 1.92 +++ src/mesa/glapi/glapi.c 23 May 2005 23:04:09 -0000 @@ -815,11 +815,59 @@ /** * Add a new extension function entrypoint. - * Return: GL_TRUE = success or GL_FALSE = failure + * + * This function is used by dynamically loaded drivers to add entrypoints + * for new functions. New offsets are assigned to functions in gl_API.xml. + * If a driver needs work with libGL versions from before a function had an + * offset assigned, it must call this function with the assigned offset. + * + * If a driver wants to extend the GL API with functions that do not have + * assigned API offsets (e.g., a new vendor-specific extension), this + * function should be called with an offset of ~0. + * + * The rule is: if you know an offset from gl_API.xml, use it for the + * \c offset parameter. If you do not know an offset from gl_API.xml, use + * ~0. + * + * \param funcName Name of the function to be added + * \param offset Offset in the dispatch table for the function. If the + * function does \b not have a registered offset, then the + * value ~0 should be used. + * \returns + * On success \c GL_TRUE is returned, otherwise \c GL_FALSE is returned. + * + * \bug + * Dynamic offsets are assigned starting with the highest possible value + * working towards the lowest (i.e., working towards the statically assigned + * offsets). This is done to prevent a potential problem where a driver could + * request a dynamic offset, then request a static offset and have the two + * conflict. However, if \c _glapi_add_entrypoint is called too many times + * requesting dynamic offsets, the value of \c next_dynamic_offset can get + * down into the range of the static offsets. If the incoming offset is ~0, + * \c next_dynamic_offset needs to be validated against the largest known + * static offset. + * + * \bug + * It is possible for libGL to load two (or more) different drivers. One + * driver could call '_glapi_add_entrypoint("glFooIHV", ~0)'. Another + * driver could later call + * '_glapi_add_entrypoint("glFooIHV", _gloffset_glFooIHV)'. If the libGL + * version does not know about \c _gloffset_glFooIHV, the second call to + * \c _glapi_add_entrypoint will fail. This is an unfortunate side-effect of + * this interface. I believe that this bug will rarely, if ever, occur in the + * real world. If it does, the fix is to upgrade to a more recent libGL. + * The issue is documented here for completeness. */ + PUBLIC GLboolean _glapi_add_entrypoint(const char *funcName, GLuint offset) { + const GLint index = _glapi_get_proc_offset( funcName ); + static unsigned next_dynamic_offset = DISPATCH_TABLE_SIZE - 1; + _glapi_proc entrypoint; + GLuint i; + + /* trivial rejection test */ #ifdef MANGLE if (!funcName || funcName[0] != 'm' || funcName[1] != 'g' || funcName[2] != 'l') @@ -829,61 +877,70 @@ return GL_FALSE; #endif - /* first check if the named function is already statically present */ - { - GLint index = get_static_proc_offset(funcName); - if (index >= 0) { - return (GLboolean) ((GLuint) index == offset); /* bad offset! */ - } + + /* Check if the named function is already present. + */ + + if ( index != ~0 ) { + return (((GLuint) index == offset) || (offset == (GLuint)~0)); } - /* See if this function has already been dynamically added */ - { - GLuint i; - for (i = 0; i < NumExtEntryPoints; i++) { - if (strcmp(ExtEntryTable[i].Name, funcName) == 0) { - /* function already registered */ - if (ExtEntryTable[i].Offset == offset) { - return GL_TRUE; /* offsets match */ - } - else if (ExtEntryTable[i].Offset == (GLuint) ~0 - && offset < DISPATCH_TABLE_SIZE) { - /* need to patch-up the dispatch code */ - if (offset != (GLuint) ~0) { - fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset); - ExtEntryTable[i].Offset = offset; - } - return GL_TRUE; - } - else { - return GL_FALSE; /* bad offset! */ - } - } + + /* If the supplied offset is ~0, we need to select an appropriate offset + * to use. + */ + + if ( offset == (GLuint) ~0 ) { + offset = next_dynamic_offset; + next_dynamic_offset--; + } + else if ( offset >= next_dynamic_offset ) { + /* The requested offset has already been given to a dynamic offset + * request. + */ + return GL_FALSE; + } + + + /* See if this function has already been dynamically added via + * glXGetProcAddress (or similar funciton). If this has happened, the + * function will be listed in the ExtEntryTable, but it will have an offset + * of ~0. + */ + for (i = 0; i < NumExtEntryPoints; i++) { + if (strcmp(ExtEntryTable[i].Name, funcName) == 0) { + /* If the offset is not ~0, then this function should have already + * exited above when testing the return value of + * _glapi_get_proc_offset. + */ + assert( ExtEntryTable[i].Offset == ~0 ); + + fill_in_entrypoint_offset(ExtEntryTable[i].Address, offset); + ExtEntryTable[i].Offset = offset; + return GL_TRUE; } } - /* This is a new function, try to add it. */ - if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS || - offset >= DISPATCH_TABLE_SIZE) { - /* No space left */ + + if (NumExtEntryPoints >= MAX_EXTENSION_FUNCS) { + /* No space left in the internal extension entrypoint table. + */ return GL_FALSE; } - else { - _glapi_proc entrypoint = generate_entrypoint(offset); - if (!entrypoint) - return GL_FALSE; /* couldn't generate assembly */ - - /* OK! */ - ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName); - ExtEntryTable[NumExtEntryPoints].Offset = offset; - ExtEntryTable[NumExtEntryPoints].Address = entrypoint; - NumExtEntryPoints++; - return GL_TRUE; /* success */ + /* This is a new function, try to add it. */ + entrypoint = generate_entrypoint(offset); + if (!entrypoint) { + return GL_FALSE; /* couldn't generate assembly */ } - /* should never get here, silence compiler warnings */ - return GL_FALSE; + /* OK! */ + ExtEntryTable[NumExtEntryPoints].Name = str_dup(funcName); + ExtEntryTable[NumExtEntryPoints].Offset = offset; + ExtEntryTable[NumExtEntryPoints].Address = entrypoint; + NumExtEntryPoints++; + + return GL_TRUE; /* success */ }