使用 OpenGL 编程时,应避免使用 glGet 函数,因为它们会强制 GPU 和 CPU 同步,这是否也适用于获取当前 OpenGL 上下文句柄的 wgl 函数“wglGetCurrentContext”?如果没有,wglGetCurrentContext 是否还有其他性能问题?
2 回答
您的问题暗示了一些误解:
应避免使用 glGet 函数,因为它们会强制 GPU 和 CPU 同步
第一部分是真的。第二部分不是。大多数glGet*()
调用不会强制 GPU/CPU 同步。它们只获取存储在驱动程序代码中的状态,根本不涉及 GPU。
有一些例外,其中包括glGet*()
实际获取 GPU 生成的数据的调用。典型例子包括:
glGetBufferSubData()
:如果数据是由 GPU 生成的(例如使用变换反馈),则必须阻止。glGetTexImage()
: 如果纹理数据是由 GPU 生成的(例如,如果用作渲染目标),则阻塞。glGetQueryObjectiv(..., GL_QUERY_RESULT, ...)
: 如果查询未完成则阻塞。
现在,您仍然应该glGet*()
尽可能避免打电话。主要有两个原因:
- 它们中的大多数是不必要的,因为它们会查询您自己设置的状态,因此您应该已经知道它是什么。任何不必要的电话都是浪费。
- 它们可能会导致多线程驱动程序实现中线程之间的同步。因此它们可能会导致同步,但不会与 GPU 同步。
调用当然有一些很好的用途glGet*()
,例如:
- 要获得实现限制,例如最大纹理大小等。在启动期间调用一次。
- 调用
glGetUniformLocation()
和glGetAttribLocation()
. 确保在着色器链接后只调用一次。尽管至少在最近的 GLSL 版本中,这些也可以通过在着色器代码中使用限定符来避免。 glGetError()
, 仅在调试期间。
至于wglGetCurrentContext()
,我怀疑它会非常昂贵。当前上下文通常存储在某种线程本地存储中,可以非常有效地访问。
不过,我不明白为什么有必要调用它。如果您稍后再次需要上下文,您可以在创建它时将其存储起来。如果由于某种原因无法做到这一点,您可以调用wglGetCurrentContext()
一次,然后存储结果。绝对不需要重复调用它。
根据供应商和驱动程序的不同,所有 WGL 功能对性能特征的影响差异很大。
我不认为 wglGetCurrentContext 会是一个特别占用性能的调用(除非你做了很多次)。由于 WGL 函数通常与 GL 上下文的状态向量分离。
话虽这么说,设置当前上下文将导致上下文之间的各种同步方式,通常是以非常未记录的方式。我已经处理了几个 AMD 和 Intel 驱动程序错误,其中一些应该通过其他方式同步的东西只能与每帧的冗余 MakeCurrent 调用同步。