修改纹理(在其上绘画)是否被视为“状态变化”?


11

图形中的约定是,执行较少的状态更改比执行较多的状态更改(切换着色器,绑定缓冲区,绑定纹理等)更好。对于纹理,使用单个地图集(用于渲染精灵/文本)渲染许多多边形要比为每个多边形单独绑定一个新纹理要快。

如果我不断通过绘制纹理,这是否成立glTexSubImage2D?我有(通过网络)传入的数据流经过处理,然后一次绘制成纹理。数据以无休止的滚动形式直观呈现。

我会不会更好地在一个大矩形上绘制一种纹理(将绘制的数据滚动到视图中)?这里的想法是,在我继续绘画的同时,在任何给定的时间绑定一个(或两个)纹理。

还是我应该绘制很多小矩形(仅在绘制完成后才显示矩形)?我假设我将为每个矩形绑定一个纹理。

Answers:


11

更新图形设备中的内存区域(纹理,缓冲区等)与更改渲染状态并不完全相同。

使渲染状态更改昂贵的原因是驱动程序必须执行的工作量才能验证新状态并重新排序管道。这很可能还会在CPU和图形设备之间引起一些同步。但是,设备之间传输的数据量对于状态更改应该很小(可能只有几个命令)。

另一方面,对于纹理/缓冲区更新,主要成本在于数据传输本身。从理论上讲,除非您在更新后将纹理数据读回CPU,否则不应有同步或流水线停滞。但是,应该考虑另一方面:API开销。即使您要发送到图形设备的数据量很小,但如果这样做足够频繁,最终与驱动程序/设备进行通信的成本将变得比数据传输的成本更高。这就是为什么在优化渲染器时批处理如此重要的另一个原因。

因此,在您看来,最好的方法是在新数据到达时,保留要更新的纹理的系统内存副本。设置一个脏标志,并glTexSubImage针对整个纹理(或其较大的顺序部分)将尽可能多的更新合并为一个。您也可以使用Pixel Buffer Objects并尝试执行异步数据传输,以尽可能减少流水线停顿。如果可以实现某种形式的双缓冲,则可以在渲染纹理的一个副本时对其进行写入。本教程探索这种情况。这是我的直观方法,我将尝试减少API调用的次数并“分批”纹理更新。话虽这么说,这是非常投机的,您必须将其与其他方法(例如进行几次小的更新)进行比较并将其进行比较,以确保确定哪种情况最适合您的使用情况。

附带说明一下,NVidia的本次演讲也很有意义,并且提供了很多很好的见解:在OpenGL中实现零驱动程序开销


5
我不确定,但我肯定会怀疑在最后一帧或两帧中渲染的纹理上的glTexSubImage会使管道停滞,因为PC驱动程序经常尝试缓冲一帧或两帧,并且不太可能由于微小的更新而想要复制整个纹理。因此,我希望对纹理(或像素缓冲区对象)进行两次或三次缓冲才能获得最佳性能。
约翰·卡尔斯贝克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.