Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

glXGetProcAddress returns non-null for any procName starting with "gl"

I was very surprised when I discovered that the following code, and a lot of its variations, produce a non-null memory address. The variations that I tried include:

  • Calling glXGetProcAddressARB instead of glXGetProcAddress.
  • Having an active GL context, created with GLFW.
  • Using the cross-platform alternative provided with GLFW: glfwGetProcAddress.

    #include <GL/glx.h>
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
        void *ptr;
    
        ptr = glXGetProcAddress((const GLubyte *)"glottis");
    
        printf("ptr: %x\n", ptr);
    
        return 0;
    }
    

The programs is compiled with -lGL (and -lglfw when required) and there are no warnings nor errors.

The only way to obtain a 0 output, the NULL pointer, is by asking the address of a function whose name does not start with gl, for instance manny.

I am quite surprised by this behaviour because glottis and manny should be equally non-existing, and I would have expected both to produce a NULL pointer.

Resources

This is an excerpt from glXGetProcAddress documentation.

Notes

A NULL pointer is returned if function requested is not suported in the implementation being queried.

GLU functions are not queryable due to the fact that the library may not be loaded at the time of the query.

Full document

More info on this topic

like image 447
damix911 Avatar asked Jan 31 '16 19:01

damix911


1 Answers

Well, from a correctness point of view, the behaviour you observe is compliant. You cannot conclude that a non-NULL return value of glXGetProcAddress (or the others) implies that the function is there or can be used. You must always query the extension string. Trying to get function pointers for function not advertised by the extension string (or its presence implied by the core GL version of your context) will conceptually be undefined behavior.

You did quote from the reference page on glXGetProcAddress. Unfortunately, those reference pages are notorioulsy imprecise, incomplete, and sometimes even flat-out wrong. In this case, the wording is at least unfortunate.

I generally recommend using the official specifications for looking up such details. In this case, the GLX 1.4 specification will be the relevant document. Section 3.3.12 "Obtaining Extension Function Pointers" states this about glXGetProcAddress (emphasis mine):

A return value of NULL indicates that the specified function does not exist for the implementation.

A non-NULL return value for glXGetProcAddress does not guarantee that an extension function is actually supported at runtime. The client must also query glGetString(GL_EXTENSIONS) or glXQueryExtensionsString to determine if an extension is supported by a particular context. [...]

glXGetProcAddress may be queried for all of the following functions:

  • All GL and GLX extension functions supported by the implementation (whether those extensions are supported by the current context or not).
  • All core (non-extension) functions in GL and GLX from version 1.0 up to and including the versions of those specifications supported by the implementation, as determined by glGetString(GL_VERSION) and glXQueryVersion queries.

It looks like the Mesa3D implementation is actually capable of generating some stubs dynamically for every queried function starting with gl.

Looking at the current version of /src/mapi/glapi/glapi_getproc.c reveals the function _glapi_get_proc_address() doing this:

/**
 * Return pointer to the named function.  If the function name isn't found
 * in the name of static functions, try generating a new API entrypoint on
 * the fly with assembly language.
 */
_glapi_proc
_glapi_get_proc_address(const char *funcName)
{
   _glapi_proc func;
   struct _glapi_function * entry;

   init_glapi_relocs_once();

#ifdef MANGLE
   /* skip the prefix on the name */
   if (funcName[1] != 'g' || funcName[2] != 'l')
      return NULL;
#else
   if (funcName[0] != 'g' || funcName[1] != 'l')
      return NULL;
#endif

   /* search extension functions first */
   func = get_extension_proc_address(funcName);
   if (func)
      return func;

   /* search static functions */
   func = get_static_proc_address(funcName);
   if (func)
      return func;

   /* generate entrypoint, dispatch offset must be filled in by the driver */
   entry = add_function_name(funcName);
   if (entry == NULL)
      return NULL;

   return entry->dispatch_stub;
}

So it actually checks for the gl prefix, and if the function is then not known, it dynamically creates a stub for it. Later, when a hw backend driver is loaded, it might register the gl functions, and the stub code will forward the call to the driver, if it provides an implementation for it.

like image 154
derhass Avatar answered Oct 18 '22 02:10

derhass