5

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

  • 调用glXGetProcAddressARB而不是glXGetProcAddress.
  • 有一个活跃的 GL 上下文,使用 GLFW 创建。
  • 使用 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

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

资源

这是文档的摘录glXGetProcAddress

笔记

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

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

完整文件

有关此主题的更多信息

4

1 回答 1

8

好吧,从正确性的角度来看,您观察到的行为是合规的。您不能断定(或其他)的非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;
}

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

于 2016-01-31T20:45:00.667 回答