我正在编写一个opengl应用程序,对于顶点,法线和颜色,我使用的是单独的缓冲区,如下所示:
GLuint vertex_buffer, normal_buffer, color_buffer;
我的主管告诉我,如果我定义一个结构:
struct vertex {
glm::vec3 pos;
glm::vec3 normal;
glm::vec3 color;
};
GLuint vertex_buffer;
然后定义这些顶点的缓冲区,我的应用程序将变得更快,因为当缓存位置时,法线和颜色将位于缓存行中。
我认为定义这样的结构并没有对性能产生太大影响,因为像结构一样定义顶点会在将它们定义为单独的缓冲区时在缓存行中产生更少的顶点,这将导致有3个不同的缓存行缓存中的位置,法线和颜色。所以,没有任何改变。真的吗?
答案 0 :(得分:4)
首先,对不同的顶点属性使用单独的缓冲区可能不是一个好方法。
非常重要的因素是GPU架构。大多数(特别是现代的)GPU有多个缓存行(输入汇编程序阶段,制服,纹理的数据),但从多个VBO获取输入属性无论如何都可能效率低下(总是配置文件!)。以交错格式定义它们有助于提高性能:
如果你使用过这样的结构,你会得到什么。
然而,这并不总是正确的(同样,总是配置文件!) - 尽管交错数据对GPU更友好,但它需要正确对齐并且可以在内存中占用更多空间。
但是,总的来说:
交错数据格式:
导致较少的GPU缓存压力,因为顶点坐标和单个顶点的属性并未遍布内存。 它们连续适应几个缓存行,而分散 属性可能会导致更多缓存更新,从而导致驱逐。该 最糟糕的情况可能是每个缓存行的一个(属性)元素 一段时间因为远处的记忆位置,而顶点被拉 以非确定性/非连续方式,可能没有 预测和预取踢.GPU非常类似于CPU 这件事。
对于各种外部格式也非常有用,这些格式满足不推荐使用的交错格式,其中兼容数据的数据集 源可以直接读入映射的GPU内存。我结束了 使用当前的API重新实现这些交错格式 正是这些原因。
应该像简单数组一样对齐友好。混合具有不同大小/对齐要求的各种数据类型 可能需要填充GPU和CPU友好。这是唯一的缺点 我知道,从更困难的实施中得知。
不要阻止您指向其中的单个attrib数组进行共享。
进一步阅读:
答案 1 :(得分:3)
取决于GPU架构。
大多数GPU都有多个缓存行(一些用于制服,另一些用于顶点属性,其他用于纹理采样)
此外,当顶点着色器快要完成时,GPU可以预先将下一组属性提取到缓存中。因此,到顶点着色器完成时,下一个属性就在那里准备加载到寄存器中。
tl; dr不要为这些"拇指规则而烦恼"除非您实际剖析它或了解GPU的实际架构。
答案 2 :(得分:2)
告诉你的主管"过早的优化是所有邪恶的根源" - Donald E. Knuth。但是不要忘记下一句话#34;但这并不意味着我们不应该优化热点"。
你是否真的描述了这些差异?
无论如何,顶点数据的布局对于现代GPU的缓存效率并不重要。它曾经是旧的GPU(约2000年),这就是为什么有交错顶点数据的功能。但是现在这几乎不是问题。
这与现代GPU访问内存的方式有关,实际上是现代GPU'缓存行不是按内存地址索引,而是按访问模式索引(即着色器中的第一个不同的内存访问获取第一个缓存行,第二个缓存行获取第二个缓存行,等等。)