我应该使用多个 glBufferSubData() 调用更新多个 VBO 还是使用一个 glBufferSubData() 调用更新单个 VBO?



我有38个具有不同着色器的粒子系统,每个粒子系统最多可以在世界上不同的地方(发射器)渲染200次。我唯一需要更新(上传到GPU)每帧的是发射器位置(可能还有一些系统中的其他属性),当且仅当任何粒子系统在视锥体内是活动的和可见的。

我应该这样分配和更新一切吗:-为每个粒子系统分配一个VBO,最多可以处理200个发射器。使用glBufferSubData()为每个粒子系统的每帧更新0到200个发射器。对每个粒子系统执行一次绘制调用。

在最坏的情况下,我们需要使用此方法执行38个glBufferSubData()调用!

或者,我应该这样做吗(共享VBO):-分配一个非常大的VBO,最多可以处理38个(粒子系统)*200个(每个粒子系统的发射器)。使用单个粒子系统更新所有粒子系统调用glBufferSubData()。在这种情况下,我们需要对每个粒子系统的所有发射器进行分组,因为每个绘制调用都必须知道每个粒子系统及其发射器的开始偏移。对每个粒子系统执行一次绘制调用。

我们只需要调用glBufferSubData()一次!

很明显,第2号案例是赢家,但我有一些疑虑。我们知道38个粒子系统共享一个VBO,但是拖延GPU管道呢?图形驱动程序只能在所有38个粒子系统完成渲染(即不从VBO读取任何数据)的情况下执行VBO更新。

我发现:考虑使用多个缓冲区对象,以避免在数据存储更新期间暂停渲染管道。如果管道中的任何渲染引用了glBufferSubData正在更新的缓冲区对象中的数据,特别是来自正在更新的特定区域的数据,则在更新数据存储之前,该渲染必须从管道中排出

此处:https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml

对于案例2,我应该使用双倍甚至三倍的缓冲吗?

与图形方面的许多优化一样,这是一种权衡。通过将所有缓冲区合并为一个缓冲区,可以减少为平均情况绘制粒子系统所需的状态更改次数。但是,如果系统不在截头体中时跳过glBufferSubData(),则会错过减少的总线带宽。

除非整个缓冲区超过几MB(想想高分辨率视频流中的一两帧大小),否则我不会担心GPU管道的停滞。更改VBO是比更改着色器或帧缓冲区便宜得多的状态更改。

这主要取决于你还有更多的空闲时间:GPU处理/同步时间(以状态变化的形式)或PCI-e总线带宽。

最新更新