图形中的约定是,执行较少的状态更改比执行较多的状态更改(切换着色器,绑定缓冲区,绑定纹理等)更好。对于纹理,使用单个地图集(用于渲染精灵/文本)渲染多个多边形要比为每个多边形单独绑定一个新纹理要快。通过glTexSubImage2D生成纹理?我有(通过网络)传入的数据流经过处理,然后一次绘制成纹理。数据以无休止的滚动形式直观地呈现。这里的想法是,在我继续绘画的同时,在任何给定的时间绑定一个(或两个)纹理。

或者我应该绘画很多小矩形(仅在显示时显示矩形)画完了吗?我假设我会为每个矩形绑定一个纹理。

#1 楼

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

使渲染状态更改昂贵的原因是驱动程序必须进行的工作量才能验证新状态并重新排列管道。这很可能还会在CPU和图形设备之间引起一些同步。但是,用于状态更改的设备之间传输的数据量应该很小(可能只有几个命令)。另一方面,对于纹理/缓冲区更新,主要成本在于数据传输本身。从理论上讲,除非您在更新后将纹理数据读回CPU,否则不应有同步或流水线停滞。但是,应考虑另一方面:API开销。即使您要发送到图形设备的数据量很小,但如果这样做足够频繁,最终与驱动程序/设备进行通信的成本就会变得比数据传输的成本高。这就是为什么在优化渲染器时批处理如此重要的另一个原因。
因此,在您看来,最好的方法是在新数据到达时,保留更新的纹理的系统内存副本。设置一个脏标志,并针对整个纹理(或其较大的顺序部分)将尽可能多的更新合并到一个glTexSubImage中。您也可以使用“像素缓冲区对象”,尝试进行异步数据传输,以尽可能减少流水线停顿。如果可以实现某种类型的双重缓冲,则可以在渲染另一个纹理时写入纹理的一个副本。本教程探讨了这种情况。这是我的直观方法,我尝试减少API调用的次数并“分批”纹理更新。话虽这么说,但这是一种推测性的方法,您必须将其与其他方法进行比较,例如进行几次小的更新,才能确定哪种方法在您的用例中性能最高。

作为一个旁注,NVidia的本次演讲也很有意义,并且提供了很多很好的见解:在OpenGL中实现零驱动程序开销。

评论


$ \ begingroup $
我不确定,但是我肯定会怀疑在最后一帧或两帧中渲染的纹理上的glTexSubImage会使管道停滞,因为PC驱动程序经常尝试缓冲一帧或两帧,并且由于微小的更新,不太可能想要复制整个纹理。因此,我希望对纹理(或像素缓冲区对象)进行两次或三次缓冲才能获得最佳性能。
$ \ endgroup $
– John Calsbeek
15年8月5日在6:14