切换到使用较少(或不同位置)属性的程序着色器时,是否应禁用着色器属性?
我使用glEnableVertexAttribArray()/ glDisableVertexAttribArray()启用和禁用这些属性。
是否有任何性能影响,或者是否会带来一些错误,或者启用/禁用会比激活所有属性更慢并让它们激活?
答案 0 :(得分:6)
OP很可能已经理解了第一部分,但是让我重申一些关于顶点属性的要点,以便为更有趣的部分设置基础。我假设所有顶点数据都来自缓冲区,而不是讨论像glVertexAttrib3f()
这样的调用用于为属性设置“常量”值的情况。
glEnableVertexAttribArray()
和glVertexAttribPointer()
调用指定启用哪些顶点属性,并描述GPU应如何检索其值。这包括它们在内存中的位置,它们有多少组件,它们的类型,步幅等。我将在这个答案的其余部分中调用由这些调用“顶点属性状态”指定的收集状态。attribute
变量的位置,顶点着色器中的顶点属性与in
/ in
变量相关联。这指定了每个in
变量的值应该来自哪个顶点属性。位置值是程序状态的一部分。基于此,当绑定不同的程序时,必须正确设置in
变量的位置以引用所需的属性。只要相同的属性始终用于着色器,在构建着色器时只需执行一次。除此之外,着色器使用的所有属性都必须使用glEnableVertexAttribArray()
启用,或者通过绑定包含状态的VAO。
现在,最后讨论问题的核心:如果程序未使用的属性被启用会怎样?
我认为启用未使用的属性是完全合法的。至少我从未在规范中看到任何其他说法。我刚刚检查过,仍然没有发现任何东西。因此,启用未使用的属性不会产生任何错误。
是否会影响性能?简短的回答是它可能。让我们看看两个假设的硬件架构:
对于架构A,启用未使用的属性根本不起作用。他们根本就不会被阅读。
对于架构B,固定功能单元可能会读取未使用的属性。顶点着色器最终不会使用它们,但它们仍然可以从主/视频存储器读入片上存储器。驱动程序可以通过检查当前着色器使用哪些属性来避免这种情况,并仅使用这些属性设置固定功能单元。缺点是每次绑定新着色器时都必须检查/更新固定功能单元的状态设置,否则这是不必要的。但它阻止从内存中读取未使用的属性。
更进一步,让我们说我们最终会从内存中读取未使用的属性。一般来说,这种伤害是否以及多少是不可能回答的。直观地说,如果属性是交错的,我希望它很重要,并且未使用的属性与使用的属性在同一个缓存行中。另一方面,如果读取未使用的属性会导致额外的缓存未命中,则至少会占用内存带宽并消耗功率。
总之,我不相信有一个明确而简单的答案。有可能启用未使用的属性根本不会受到伤害,或者很少。但无论如何我会亲自禁用它们。它有可能产生重大影响,而且很容易做到。特别是如果使用VAO,通常可以通过单个glBindVertexArray()
调用设置整个顶点属性状态,因此启用/禁用所需的属性不需要额外的API调用。