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

dam*_*911 4 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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

程序是用-lGL(并-lglfw在需要时)编译的,没有警告也没有错误.

获得的唯一途径0输出的NULL指针,是通过询问他的名字不启动函数的地址gl,例如manny.

我对此行为感到非常惊讶,因为glottis并且manny应该同样不存在,并且我希望两者都产生一个NULL指针.

资源

这是glXGetProcAddress文档的摘录.

笔记

如果在被查询的实现中没有支持请求的函数,则返回NULL指针.

由于在查询时可能未加载库,因此GLU函数不可查询.

完整文件

有关此主题的更多信息

der*_*ass 7

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

您确实引用了参考页面glXGetProcAddress.不幸的是,那些参考页面是不正确的,不完整的,有时甚至是错误的.在这种情况下,措辞至少是不幸的.

我一般建议使用官方规范查找此类详细信息.在这种情况下,GLX 1.4规范将是相关文档.第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;
}
Run Code Online (Sandbox Code Playgroud)

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