我正在编写一个OpenGL应用程序,对于顶点、法线和颜色,我使用单独的缓冲区,如下所示:
GLuint vertex_buffer, normal_buffer, color_buffer;
我的主管告诉我,如果我定义一个结构体,比如:
struct vertex {
glm::vec3 pos;
glm::vec3 normal;
glm::vec3 color;
};
GLuint vertex_buffer;
然后定义一个这些顶点的缓冲区,我的应用程序将变得更快,因为当位置被缓存时,法线和颜色将在缓存行中。
我认为定义这样的结构体对性能没有太大的影响,因为像结构体那样定义顶点会导致缓存行中的顶点减少,而将它们定义为单独的缓冲区,会导致缓存中有3个不同的缓存行用于位置,法线和颜色。所以,什么都没有改变。这是真的吗?
4条答案
按热度按时间tzxcd3kk1#
首先,为不同的顶点属性使用单独的缓冲区可能不是一种好的技术。
这里非常重要的因素是GPU架构。大多数(尤其是现代)GPU都有多个缓存行(输入汇编阶段的数据,统一,纹理),但从多个VBO获取输入属性无论如何都是低效的(总是配置文件!)。以交错格式定义它们有助于提高性能:
如果你使用这样的结构体,你就会得到这样的结果。
然而,这并不总是正确的(同样,总是配置文件!)-尽管交错数据更GPU友好,它需要正确对齐,并可能占用更多的内存空间。
但是,一般来说:
交叉数据格式:
Source
进一步阅读:
Best Practices for Working with Vertex Data
Vertex Specification Best Practices
bzzcjhmw2#
取决于GPU架构。
大多数GPU都有多个缓存行(一些用于统一,其他用于顶点属性,其他用于纹理采样)
当顶点着色器快完成时,GPU可以将下一组属性预取该高速缓存中,这样当顶点着色器完成时,下一组属性就已经准备好加载到寄存器中了。
tl;dr不要为这些“经验法则”而烦恼,除非你真的剖析了它或者知道GPU的实际架构。
7nbnzgx93#
告诉你的主管 “过早的优化是万恶之源” - Donald E. Knuth。但不要忘记下一句话“但这并不意味着我们不应该优化热点”。
你真的分析了这些差异吗?
无论如何,顶点数据的布局对于现代GPU的缓存效率来说并不重要。它曾经是在旧的GPU上(大约2000年),这就是为什么有交错顶点数据的函数。但现在这几乎是一个不重要的问题。
这与现代GPU访问存储器的方式有关,并且实际上现代GPU的高速缓存行不是通过存储器地址索引的,而是通过访问模式(即,着色器中的第一个不同的存储器访问获得第一个高速缓存行,第二个获得第二个高速缓存行,等等)。
wdebmtf24#
这听起来是一个很好的方法来分离位置到不同的vbo,渲染它在zprepass或shadowpass没有获取非影响属性,如紫外线,颜色或正常。