正在存储OpenGL状态

Storing OpenGL state

本文关键字:状态 OpenGL 存储      更新时间:2023-10-16

假设我正试图在C++上制作某种小型的opengl图形引擎。我读到通过glGet*函数访问opengl状态可能非常昂贵(而访问opengl状态似乎是一种常见的操作),强烈建议将opengl状态的副本存储在具有快速读/写访问权限的地方。

我目前正在考虑将opengl状态存储为某种适当类型的全局thread_local变量。这个设计有多糟糕?有陷阱吗?

如果你想坚持OpenGL的设计(你的上下文指针可以被认为是"thread_local"),我想这是一个有效的选项。。。显然,您需要完全控制所有OpenGL调用,以便使状态副本与当前上下文的状态保持同步。

我个人更喜欢使用一个"OpenGLState"类来包装OpenGL感兴趣的状态,其中包含一组可设置/可获取的属性,每个属性都映射到状态的某个部分。然后也可以避免两次设置相同的状态。您可以将其设置为thread_local,但我做不到(Visual C++只支持POD类型的thread_local)。

您需要非常小心,因为一些OpenGL调用会间接更改上下文状态中看似不相关的部分。例如,glDeleteTextures会将已删除纹理的任何绑定重置为0。此外,一些工具包在背后更改OpenGL状态时非常"有用"(例如,OSX上的QtOpenGLContext会在设置为当前视口时为您更改视口)。

既然只能(合理地)将GL上下文与一个线程一起使用,为什么需要线程本地?是的,您可以在不同的时间在不同的线程中使上下文成为当前上下文,但这不是一个明智的设计。

你通常会有一个上下文和一个线程访问它。在极少数情况下,你会有两个上下文(通常是共享的)和两个线程。在这种情况下,您可以简单地将希望保存的任何其他状态放入上下文类中,其中每个实例都由一个线程所有。

但大多数时候,您不需要明确地"记住"状态。所有状态都有充分记录的初始状态,只有当更改它们时,它们才会更改("超级智能"工具包所做的更改除外,但在这种情况下,存储错误的状态也没有帮助)。

您通常会尝试将状态批处理在一起,并用一组状态进行许多"类似"的绘制调用,原因是状态更改会使管道停滞,并且需要在下一次绘制调用之前进行昂贵的验证
因此,从默认值开始,并在绘制批次之前设置所有需要为非默认值的内容。然后更改下一批需要不同的内容。

如果你不想费力地浏览默认值的规范并跟踪,你可以一直冗余地设置所有内容。然后在GDebugger中运行您的应用程序,它会告诉您哪些状态更改是多余的,这样您就可以消除它们。