不使用激活的Attrib会有影响吗?

时间:2014-10-01 15:47:58

标签: c++ opengl glsl

切换到使用较少(或不同位置)属性的程序着色器时,是否应禁用着色器属性?

我使用glEnableVertexAttribArray()/ glDisableVertexAttribArray()启用和禁用这些属性。

是否有任何性能影响,或者是否会带来一些错误,或者启用/禁用会比激活所有属性更慢并让它们激活?

1 个答案:

答案 0 :(得分:6)

OP很可能已经理解了第一部分,但是让我重申一些关于顶点属性的要点,以便为更有趣的部分设置基础。我假设所有顶点数据都来自缓冲区,而不是讨论像glVertexAttrib3f()这样的调用用于为属性设置“常量”值的情况。

  • glEnableVertexAttribArray()glVertexAttribPointer()调用指定启用哪些顶点属性,并描述GPU应如何检索其值。这包括它们在内存中的位置,它们有多少组件,它们的类型,步幅等。我将在这个答案的其余部分中调用由这些调用“顶点属性状态”指定的收集状态。
  • 顶点属性状态不是着色器程序状态的一部分。它存在于顶点属性对象(VAO)中,以及其他一些相关状态。因此,绑定不同的程序不会改变顶点属性状态。只绑定不同的VAO,或者当然进行上述调用之一。
  • 通过设置attribute变量的位置,顶点着色器中的顶点属性与in / in变量相关联。这指定了每个in变量的值应该来自哪个顶点属性。位置值是程序状态的一部分。

基于此,当绑定不同的程序时,必须正确设置in变量的位置以引用所需的属性。只要相同的属性始终用于着色器,在构建着色器时只需执行一次。除此之外,着色器使用的所有属性都必须使用glEnableVertexAttribArray()启用,或者通过绑定包含状态的VAO。

现在,最后讨论问题的核心:如果程序未使用的属性被启用会怎样?

我认为启用未使用的属性是完全合法的。至少我从未在规范中看到任何其他说法。我刚刚检查过,仍然没有发现任何东西。因此,启用未使用的属性不会产生任何错误。

是否会影响性能?简短的回答是它可能。让我们看看两个假设的硬件架构:

  • 架构A读取了顶点着色器代码中的顶点属性值。
  • 架构B具有固定的功能单元,用于读取顶点属性值。这个固定的功能单元由顶点属性状态控制,并将值写入片上存储器,顶点着色器实例将其拾取。

对于架构A,启用未使用的属性根本不起作用。他们根本就不会被阅读。

对于架构B,固定功能单元可能会读取未使用的属性。顶点着色器最终不会使用它们,但它们仍然可以从主/视频存储器读入片上存储器。驱动程序可以通过检查当前着色器使用哪些属性来避免这种情况,并仅使用这些属性设置固定功能单元。缺点是每次绑定新着色器时都必须检查/更新固定功能单元的状态设置,否则这是不必要的。但它阻止从内存中读取未使用的属性。

更进一步,让我们说我们最终会从内存中读取未使用的属性。一般来说,这种伤害是否以及多少是不可能回答的。直观地说,如果属性是交错的,我希望它很重要,并且未使用的属性与使用的属性在同一个缓存行中。另一方面,如果读取未使用的属性会导致额外的缓存未命中,则至少会占用内存带宽并消耗功率。

总之,我不相信有一个明确而简单的答案。有可能启用未使用的属性根本不会受到伤害,或者很少。但无论如何我会亲自禁用它们。它有可能产生重大影响,而且很容易做到。特别是如果使用VAO,通常可以通过单个glBindVertexArray()调用设置整个顶点属性状态,因此启用/禁用所需的属性不需要额外的API调用。