我读到,在OpenGL 2(尤其是ES)中优化非透明对象渲染顺序的最佳方法是优先考虑避免上下文更改(绑定不同的缓冲区,着色器程序等)而不是深度排序。
如果您使用已经绑定的缓冲区调用 glBindBuffer,或者使用已经是当前程序的着色器程序调用 glUseProgram,等等,它们是否仍会导致低效的管道刷新,或者库是否足够聪明地将它们识别为 NOOP?如果我可以在需要的时候绑定所有内容,而不必跟踪已经绑定的内容并检查它,这将使我的代码更简单。
也许吧。这真的一般无法回答。它完全依赖于实现。
驱动程序是否应该检查冗余状态更改是一个有点哲学讨论的问题,你不会就此达成共识。因此,您应该期望不同的供应商以不同的方式处理它,我什至不一定假设它在同一驱动程序中的所有状态中都一致地处理。
如果您针对特定平台,则应对其进行衡量。幸运的是,这很容易进行基准测试。如果您想涵盖广泛的平台/供应商,我会尽量减少冗余的状态更改。至少如果你可以选择相对便宜地做到这一点。如果您为此增加大量开销,则可能弊大于利。
对此意见不一的主要原因是检查冗余状态更改并非完全免费。如果驱动程序执行此操作,则开销适用于所有人。因此,编写良好的应用程序(不会进行不必要的状态更改)为有利于编写不佳的应用程序的优化付出了代价。你可以说这是非常不公平的。
实际上,这些检查经常进行,特别是如果状态变化本身相当昂贵。当然,如果状态更改非常便宜,则不值得添加检查。检查通常由重要应用/游戏基准的性能优化驱动。不幸的是,许多应用程序/游戏使用OpenGL的效率非常低,驱动程序必须为重要的基准测试产生最佳结果。在这些情况下,筛选出冗余状态更改是一种常见的优化。
我们的每个 glBindBuffer 或 glUseProgram 等调用都会在队列中创建一个命令对象。此队列将在一段时间后在 GPU 上执行。这里有 2 个瓶颈。1) 要在队列中创建命令对象,我们的代码必须转移到内核模式到驱动程序。通常,此操作有一些滞后。2)GPU将逐个执行我们的命令,并且要检查缓冲区是否已绑定,GPU必须读取和解码命令。
为了避免第二个驱动程序必须跟踪当前状态,我认为 opengl 驱动程序不会这样做。