只为一个输出顶点设置 gl_TessLevel?

Setting gl_TessLevel only for one output vertex?

在网上找到了一些TCS代码的例子,其中gl_TessLevel*只为一个输出面片顶点设置了变量

// first code snippet
if ( gl_InvocationID == 0 ) // set tessellation level, can do only for one vertex
{
    gl_TessLevelOuter [0] = foo
    gl_TessLevelOuter [1] = bar;
}

而不只是

// second code snippet
gl_TessLevelOuter [0] = foo;
gl_TessLevelOuter [1] = bar;

无论有没有条件检查,它的工作原理都相似,但我在 OpenGL wiki 上没有找到任何关于这种用法的信息。

如果从逻辑上考虑,只在一次TCS调用中设置这些变量应该没问题,而根据gl_InvocationID将它们设置为不同的值就很奇怪了。所以我的问题是:

  1. 这种设置方式gl_TessLevel*是否正确,在某些平台上是否会导致错误或崩溃?
  2. 如果它是正确的,是否应该一直使用它?是地道的吗?
  3. 最后,这两个片段如何影响性能?第一个代码片段是否会由于分支而降低性能?第二个片段是否会导致后续管道阶段的冗余 and/or 空闲调用,同时降低性能?

您在这里看到的是着色器作者试图建立一个类似于激发其他基本类型使用的顶点的约定。

OpenGL Shading Language 4.50 - 2.2 Tessellation Control Processor - p. 7

Tessellation control shader invocations run mostly independently, with undefined relative execution order. However, the built-in function barrier() can be used to control execution order by synchronizing invocations, effectively dividing tessellation control shader execution into a set of phases.

Tessellation control shaders will get undefined results if one invocation reads a per-vertex or per-patch attribute written by another invocation at any point during the same phase, or if two invocations attempt to write different values to the same per-patch output in a single phase.

根据着色器伪代码,尚不清楚 foobar 是否在所有 TCS 调用中是统一的。如果不是,则第二个着色器代码片段会由于未定义的相对顺序而调用未定义的行为。

任意决定第一次调用是唯一允许写入每个补丁属性的调用解决了这个问题,类似于第一个顶点引发约定。由于所有调用都知道补丁顶点的数量,因此可以很容易地实现最后一个顶点约定。

None 如果您知道 foobar 是常量,那么这是必要的,但是。