我应该缓存OpenGL状态,例如当前绑定的缓冲区,还是OpenGL无论如何都要这样做?

时间:2016-08-10 21:02:18

标签: c++ opengl

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

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_SOME_BUFFER, buffer);
...

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

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

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

2 个答案:

答案 0 :(得分:4)

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

您是否会问" OpenGL是否会实施......"。您已经明白了,OpenGL是一个API规范。有许多不同的实现,它们是否检查冗余状态更改完全是一个实现决策,它可以(并且将)从实现到实现不同。

你甚至不应该期望给定的实现对所有状态都处理相同的事情。

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

  • 实际改变状态有多贵?如果它非常便宜,检查多余的更改可能就不值得了。
  • 检查多余更改的费用是多少?通常情况并不多,但我们正在研究那些每一点点都很重要的软件。
  • 重要的应用/基准是否经常冗余地改变这种状态?
  • 关于应用程序责任与OpenGL实施责任的理念是什么?

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

答案 1 :(得分:3)

状态缓存是一个坏主意的原因很简单:你做错了。你总是有做错的危险。

哦,当然,你纠正了我指出的错误,即不同的缓冲区绑定有不同的状态。也许你正在使用一个哈希表,使得查找非常快,即使你编写缓存时出现了adds a new buffer binding point的新扩展名。

但就对象绑定特性而言,这仅仅是冰山一角。

例如,您是否意识到GL_ELEMENT_ARRAY_BUFFER实际上不是上下文状态?它实际上是 VAO状态,每次绑定新的VAO时,缓冲区绑定都会发生变化。所以你的VAO缓存现在也必须改变阴影元素缓冲区绑定。

另外,您是否知道从当前绑定的任何上下文绑定点自动删除对象解除绑定?即使对于附加到绑定到上下文的另一个对象的对象也是如此;已删除的对象将自动分离。

除了某些对象类型之外,这是唯一的。即使这样,当删除对象时,当前的上下文也是如此。其他情况不会受到影响。

我的观点是:正确缓存状态真的很难。如果你弄错了,你将在你的应用程序中创建大量非常微妙的错误。然而,如果你只是让OpenGL做它的事情并构造你的代码,以便不会发生多重绑定,那么你没有问题。