opengl 缓存友好的顶点定义?

rslzwgfq  于 2023-03-22  发布在  其他
关注(0)|答案(4)|浏览(109)

我正在编写一个OpenGL应用程序,对于顶点、法线和颜色,我使用单独的缓冲区,如下所示:

GLuint vertex_buffer, normal_buffer, color_buffer;

我的主管告诉我,如果我定义一个结构体,比如:

struct vertex {
    glm::vec3 pos;
    glm::vec3 normal;
    glm::vec3 color;
};
GLuint vertex_buffer;

然后定义一个这些顶点的缓冲区,我的应用程序将变得更快,因为当位置被缓存时,法线和颜色将在缓存行中。
我认为定义这样的结构体对性能没有太大的影响,因为像结构体那样定义顶点会导致缓存行中的顶点减少,而将它们定义为单独的缓冲区,会导致缓存中有3个不同的缓存行用于位置,法线和颜色。所以,什么都没有改变。这是真的吗?

tzxcd3kk

tzxcd3kk1#

首先,为不同的顶点属性使用单独的缓冲区可能不是一种好的技术。
这里非常重要的因素是GPU架构。大多数(尤其是现代)GPU都有多个缓存行(输入汇编阶段的数据,统一,纹理),但从多个VBO获取输入属性无论如何都是低效的(总是配置文件!)。以交错格式定义它们有助于提高性能:

如果你使用这样的结构体,你就会得到这样的结果。
然而,这并不总是正确的(同样,总是配置文件!)-尽管交错数据更GPU友好,它需要正确对齐,并可能占用更多的内存空间。
但是,一般来说:

交叉数据格式:

  • 减少GPU缓存压力,因为单个顶点的顶点坐标和属性不会分散在内存中。它们连续地适合几个缓存行,而分散的属性可能会导致更多的缓存更新,从而导致回收。最坏的情况可能是由于遥远的存储器位置,每次每个高速缓存行的顶点(属性)元素的数量减少,而顶点以非确定性/非连续的方式被拉取,其中可能没有预测和预取。GPU在这方面与CPU非常相似。
  • 对于各种外部格式也非常有用,这些格式满足不推荐的交错格式,其中兼容数据源的数据集可以直接读取到Map的GPU内存中。正是出于这些原因,我最终使用当前的API重新实现了这些交错格式。
  • 应该像简单数组一样布局对齐友好。混合具有不同大小/对齐要求的各种数据类型可能需要填充才能对GPU和CPU友好。这是我所知道的唯一缺点,与更困难的实现分开。
  • 不要阻止您指向其中的单个属性数组以进行共享。

Source

进一步阅读

Best Practices for Working with Vertex Data
Vertex Specification Best Practices

bzzcjhmw

bzzcjhmw2#

取决于GPU架构。
大多数GPU都有多个缓存行(一些用于统一,其他用于顶点属性,其他用于纹理采样)
当顶点着色器快完成时,GPU可以将下一组属性预取该高速缓存中,这样当顶点着色器完成时,下一组属性就已经准备好加载到寄存器中了。
tl;dr不要为这些“经验法则”而烦恼,除非你真的剖析了它或者知道GPU的实际架构。

7nbnzgx9

7nbnzgx93#

告诉你的主管 “过早的优化是万恶之源” - Donald E. Knuth。但不要忘记下一句话“但这并不意味着我们不应该优化热点”。
你真的分析了这些差异吗?
无论如何,顶点数据的布局对于现代GPU的缓存效率来说并不重要。它曾经是在旧的GPU上(大约2000年),这就是为什么有交错顶点数据的函数。但现在这几乎是一个不重要的问题。
这与现代GPU访问存储器的方式有关,并且实际上现代GPU的高速缓存行不是通过存储器地址索引的,而是通过访问模式(即,着色器中的第一个不同的存储器访问获得第一个高速缓存行,第二个获得第二个高速缓存行,等等)。

wdebmtf2

wdebmtf24#

这听起来是一个很好的方法来分离位置到不同的vbo,渲染它在zprepass或shadowpass没有获取非影响属性,如紫外线,颜色或正常。

相关问题