我正在使用现代OpenGL(3.1及更高版本)创建渲染器,现在我正在尝试创建一种高效而灵活的方式来处理制服。我一直在阅读统一缓冲区对象以及使用这些对象的“通用”方法(不幸的是,后者没有给我带来我所希望的结果)。

为了减少OpenGL API调用并将数据存储在连续内存中,我正在考虑为应上传到GPU的每个数据结构创建多个大型缓冲区。每个缓冲区的最大大小为16kb(根据我的理解,这保证可以用于UBO)。当对象希望能够将制服上传到GPU时,它会获取待上载类型的第一个尚未满的缓冲区,并在该缓冲区中获取下一个可用索引。绘制对象时,它将绑定UBO(如果尚未绑定)并上传UBO的元素索引。

这将导致如下所示:

layout(std140) uniform ModelData { 
    mat4 model_matrix[kNumInstancesPerModelUbo]; 
}
uniform int u_ModelDataIndex;

layout(std140) uniform SkeletonData { 
    mat4 bone_transforms[kNumInstancesPerSkeletonUbo][kMaxBones]; 
}
uniform int u_SkeletonDataIndex;


,但我还在考虑以下内容:与要上传的网格相关的数据。另一方面,这可能会失控(缓冲区大小大于16kb,处理不相关的数据(例如,无骨架的网格),甚至出现同步问题,因为在上传模型矩阵时不允许访问骨骼)而且我也不知道这会如何影响GPU上的内存布局。

坦率地说,感觉就像我被困在这里,我找不到一个很好的具体示例来说明如何着手快速而灵活地处理UBO。

您对我有什么建议或资源可以帮助我吗?

#1 楼

注意,从更大的缓冲区进行子分配绝对是必经之路。我从DirectX / Vulkan的角度来看更多,但这应该同样适用于OpenGL(在此答案中,我只是没有直接的API调用)。需要考虑的事情如下:


是否需要索引到较大的缓冲区中,还是可以每次将资源绑定到偏移量吗?
是否已请注意打包在一起的制服的所有对齐限制(常见的对齐方式是256字节对齐)?间接访问缓冲区子区域的快速方法。但是,假设您是可变的三重缓冲数据,则在驱动程序中应该几乎没有争用来绑定数据(只是一些固定的开销)。内存/缓冲区并分配这些区域被认为是最佳实践。这甚至适用于具有不同着色器的对象(如果您的分配器可以处理)。

#2 楼

在您的应用程序中包括两个解决方案的基准测试阶段,然后在运行时选择胜出的解决方案。这是简单,可移植的,并且是面向未来的。我的意思是,您确实对此进行了测试,对吗? ;-)

我知道这是实现高性能的“最佳实践”的相当通用的答案,但是如果您想到它,则有成千上万种可能的目标配置,许多供应商也需要考虑。如果您需要一点额外费用,请向您的供应商付款,以针对您的应用程序优化驱动程序。