使用与以前相同的值调用 glBindBuffer、glUseProgram 等是否效率低下?

Is calling glBindBuffer, glUseProgram etc with same values as before inefficient?

我读到在 OpenGL 2(尤其是 ES)中优化非透明对象渲染顺序的最佳方法是优先避免上下文更改(绑定不同的缓冲区、着色器程序等)而不是深度排序。

如果您使用已经绑定的缓冲区调用 glBindBuffer,或者使用已经是当前程序的着色器程序调用 glUseProgram,等等,它们是否仍然会导致管道刷新效率低下,或者库是否足够聪明以将它们识别为 NOOP?如果我可以在需要时绑定所有内容,而不必跟踪已经绑定的内容并检查它,这将使我的代码更简单。

我们的每个 glBindBuffer 或 glUseProgram 等调用都会在队列中创建一个命令对象。这个队列将在一段时间后在 gpu 上执行。这里有2个瓶颈。 1) 要在队列中创建命令对象,我们的代码必须转移到内核模式到驱动程序。共同点是这个操作有一些滞后。 2) GPU 将一条一条地执行我们的命令,并检查缓冲区是否已经绑定,GPU 必须读取和解码命令。

为了避免第二个驱动程序必须跟踪当前状态,我认为 opengl 驱动程序不会这样做。

也许吧。这个真的不能笼统的回答。它完全取决于实现。

driver是否应该检查冗余状态变化是一个有点哲学性的讨论,您不会就此达成共识。因此,您应该期望不同的供应商以不同的方式处理它,我什至不一定假设它在同一 driver.

中对所有状态的处理都是一致的

如果您针对特定平台,则应对其进行衡量。幸运的是,这很容易进行基准测试。如果你想涵盖广泛的 platforms/vendors,我会尽量减少冗余状态更改。至少如果你可以选择相对便宜地做到这一点。如果为此增加大量开销,可能弊大于利。

对此意见不一的主要原因是检查冗余状态变化并非完全免费。如果 driver 这样做,则开销适用于所有人。写得很好的应用程序(不会进行不必要的状态更改)为有利于写得不好的应用程序的优化付出了代价。你可以说这是非常不公平的。

实际上,通常会进行这些检查,尤其是在状态更改本身相当昂贵的情况下。当然,如果状态更改非常便宜,则不值得添加检查。这些检查通常是由重要 app/game 基准测试的性能优化驱动的。不幸的是,许多 apps/games 使用 OpenGL 的效率非常低,并且 driver 必须为重要的基准测试产生最佳结果。在这些情况下,过滤掉冗余状态更改是一种常见的优化。