我应该缓存 OpenGL 状态(例如当前绑定的缓冲区),还是 OpenGL 确实会这样做?

Hex*_*der 4 c++ opengl

典型的 OpenGL 调用可能如下所示:

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_SOME_BUFFER, buffer);
...
Run Code Online (Sandbox Code Playgroud)

我读到缓冲区和其他类似函数的绑定可能非常昂贵。是否值得保存当前绑定的缓冲区并在绑定之前检查它?比如这样:

void StateManager::bindBuffer(GLenum bufType, GLuint bufID) {
    if (this->m_currentBuffer[bufType] != bufID) {
        glBindBuffer(bufType, bufID);
        this->m_currentBuffer[bufType] = bufID;
    }
}
Run Code Online (Sandbox Code Playgroud)

这背后的想法是,如果bufID已经绑定,那么昂贵的调用glBindBuffer就会被错过。这是一个值得的方法吗?我认为 OpenGL 可能已经实现了这样的优化,但我现在已经在一些项目中看到了这种模式,所以我有疑问。我只是感兴趣,因为实现起来非常简单,但如果它没有太大/任何区别,那么我会跳过它(避免过早优化)。

Ret*_*adi 5

这高度依赖于平台和供应商。

你问“OpenGL是否会实现......”。正如您已经了解的那样,OpenGL 是一个 API 规范。有许多不同的实现,它们是否检查冗余状态更改完全是一个实现决策,这可能(并且将会)因实现而异。

您甚至不应该期望给定的实现对所有状态都以相同的方式处理此问题。

由于根据过去的经验,这个话题有点贴近我的心,所以我很想写一篇小文章,其中包括一些咆哮。但我决定它不属于这里,所以这里只是一个考虑因素列表,这些考虑因素可能会影响给定的 OpenGL 实现在特定情况下测试冗余状态变化:

  • 实际改变状态的成本有多大?如果成本非常低,那么检查冗余更改可能根本不值得。
  • 检查冗余更改的成本有多高?通常情况下不多,但我们正在研究每一点都很重要的软件。
  • 重要的应用程序/基准是否频繁地重复更改此状态?
  • 应用程序的责任与 OpenGL 实现的责任的理念是什么?

是的,这对每个人来说都是不幸的。对于想要跨供应商/平台获得理想性能的应用程序编写者来说,确实没有简单的解决方案。如果您在代码中添加检查,那么在 OpenGL 实现中具有相同检查的平台上,它们将毫无用处,并且会增加额外的开销。如果您没有在代码中进行检查,并且一开始就无法轻松避免这些冗余状态更改,则可能会在 OpenGL 实现不进行检查的平台上将性能留在桌面上。