对于以“gl”开头的任何procName,glXGetProcAddress返回非null

时间:2016-01-31 19:50:40

标签: opengl opengl-extensions

当我发现以下代码及其大量变体产生非空内存地址时,我感到非常惊讶。我尝试过的变化包括:

  • 致电glXGetProcAddressARB而非glXGetProcAddress
  • 拥有使用GLFW创建的有效GL上下文。
  • 使用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;
    }
    

程序编译时使用-lGL(并在需要时-lglfw)并且没有警告也没有错误。

获取0输出(NULL指针)的唯一方法是询问名称不以gl开头的函数的地址,例如manny }。

我对这种行为感到非常惊讶,因为glottismanny应该同样不存在,我希望两者都产生NULL指针。

资源

这是glXGetProcAddress文档的摘录。

  

注释

     

如果未支持请求的函数,则返回NULL指针   正在查询的实现。

     

由于库可能,GLU函数不可查询   在查询时不加载。

Full document

More info on this topic

1 个答案:

答案 0 :(得分:7)

嗯,从正确的角度来看,您观察到的行为是合规的。您不能断定NULL(或其他)的非glXGetProcAddress返回值意味着函数已存在或可以使用。您必须始终查询扩展字符串。尝试获取未被扩展字符串公布的函数的函数指针(或其上下文的核心GL版本暗示的存在)将在概念上是未定义的行为。

你引用了reference page on glXGetProcAddress。不幸的是,那些参考页面显然是不精确的,不完整的,有时甚至是平坦的错误的。在这种情况下,措辞至少是不幸的。

我一般建议使用官方规格查找此类详细信息。在这种情况下,GLX 1.4 specification将是相关文档。第3.3.12节“获取扩展函数指针”说明glXGetProcAddress(强调我的):

  

返回值NULL表示实现不存在指定的函数。

     

NULL的非glXGetProcAddress返回值并不保证在运行时实际支持扩展函数。客户端还必须查询   glGetString(GL_EXTENSIONS)glXQueryExtensionsString确定是否   扩展由特定上下文支持。   [...]

     可以查询

glXGetProcAddress以获取以下所有功能:

     
      
  • 实施所支持的所有GL和GLX扩展功能(当前上下文是否支持这些扩展)。
  •   
  • GL和GLX中从版本1.0到包括实现支持的那些规范版本的所有核心(非扩展)功能,   由glGetString(GL_VERSION)glXQueryVersion查询确定。
  •   

看起来Mesa3D实现实际上能够为从gl开始的每个查询函数动态生成一些存根。

查看当前版本的/src/mapi/glapi/glapi_getproc.c会显示函数_glapi_get_proc_address()执行此操作:

/**
 * 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;
}

因此它实际上会检查gl前缀,如果该函数未知,则会为其动态创建存根。稍后,当加载一个hw后端驱动程序时,它可能会注册gl函数,如果它为它提供了实现,则存根代码会将调用转发给驱动程序。