【问题标题】:glXGetProcAddress returns non-null for any procName starting with "gl"glXGetProcAddress 为以“gl”开头的任何 procName 返回非 null
【发布时间】:2016-01-31 19:50:40
【问题描述】:

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

  • 调用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

【问题讨论】:

  • 嗯,从正确性的角度来看,您观察到的行为是合规的。您不能断定glXGetProcAddress(或其他)的非空返回值意味着该函数存在或可以使用。您必须始终查询扩展字符串。尝试获取扩展未公布(或核心 GL 版本隐含)的函数的函数指针在概念上将是未定义的行为。但是,我确实发现观察到的行为对于现实世界的实现来说仍然有点奇怪。您正在尝试使用哪种实现方式?我在 nvidia 和 mesa (llvmpipe) 上得到 0。
  • @derhass:你应该把这个作为答案。
  • @derhass:谢谢。我担心是这种情况。我在 Arch Linux 上使用 Mesa(mesa 11.0.3-1,mesa-libgl 11.0.3-1)。升级到 mesa 11.1.1-1 似乎无法解决问题。事实上,在我的生产代码中,我使用glfwExtensionSupported 来检查扩展支持;然而,一个错字让我注意到了这种行为,我决定召集 StackOverflow 的 GL 专家。请把评论变成答案,我会接受的。

标签: opengl opengl-extensions


【解决方案1】:

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

您确实引用了reference page on glXGetProcAddress。不幸的是,这些参考页面出了名的不精确、不完整,有时甚至完全错误。在这种情况下,措辞至少是不幸的。

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

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

glXGetProcAddress 的非NULL 返回值并不能保证在运行时实际支持扩展函数。客户还必须查询 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 函数,如果它提供了实现,存根代码会将调用转发给驱动程序。

【讨论】:

  • 太棒了,如果可能的话,我会为你的答案投票两次!
  • @damix911:由于您编辑了您的问题并引用了 GL 参考页面,因此我也更新了我的答案。就像我正在对那些参考页面进行神圣的追求......;)
猜你喜欢
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-02
相关资源
最近更新 更多