当一个着色器被优化而另一个未优化时,为什么我的GLSL程序没有链接?

时间:2018-10-16 17:49:23

标签: opengl glsl shader spir-v

我使用的着色器工具链从GLSL开始,将其编译为SPIRV,优化SPIRV,然后使用spirv-cross生成优化的GLSL。在大多数情况下,这种方法运行良好。

但是,我有一种机制,可以通过文本替换将用户生成的片段注入某些片段着色器。发生这种情况时,将使用原始的未经优化的GLSL,因为用于文本替换的标记无法通过SPIRV。

但是,我发现在某些情况下,优化的顶点着色器和自定义片段着色器都可以编译,但是程序不会链接,而是出现以下错误:

WARNING: warning(#276) Symbol "_normal" usage doesn't match between two stages
ERROR: error(#277) Symbol "_16" usage doesn't match between two stages

优化的顶点着色器和优化的片段着色器链接。两个链接的未优化版本。甚至是未优化的顶点着色器和优化的片段着色器链接。

我将问题缩小为以下声明,该声明出现在片段着色器中

struct TransformCamera {
    mat4 _view;
    mat4 _viewInverse;
    mat4 _projectionViewUntranslated;
    mat4 _projection;
    mat4 _projectionInverse;
    vec4 _viewport;
    vec4 _stereoInfo;
};

layout(std140, binding=15) uniform transformCameraBuffer {
    TransformCamera _camera;
};

在着色器的优化版本中,整个UBO未被优化为未使用状态,声明变为

layout(binding = 15, std140) uniform transformCameraBuffer
{
    TransformCamera _camera;
} _16;

如果我手动修改未优化的片段着色器以使用类似的机制来命名UBO,链接错误就会消失(无论我如何命名UBO),因此,例如,对片段着色器的以下更改将成功编译并链接

layout(std140, binding=15) uniform transformCameraBuffer {
    TransformCamera _camera;
} _foo;

我显然可以解决此问题,但我不了解UBO声明的不同语法如何完全破坏程序的链接阶段。谁能提供一些见识?

此外,如果glslangValidator-> spirv-opt-> spirv-cross中的某项更改了我的着色器的链接界面,我是否应该考虑该错误并报告该错误?

1 个答案:

答案 0 :(得分:3)

  

我显然可以解决该问题,但我不了解UBO声明的不同语法如何完全破坏程序的链接阶段

因为规范是这样说的。 GLSL 4.60 specification,第4.3.9节。 “接口块”状态(强调我的意思):

  

着色器接口(如上定义)中匹配的块名称必须在以下方面匹配:   具有相同类型的序列和相同序列的相同数量的声明   成员名称,以及具有匹配的成员布局资格(请参阅下一节)。   匹配的制服或着色器存储块名称(但不能输入或输出块名称)也必须   要么全部缺少实例名称,要么全部都具有实例名称,将其成员置于   相同的作用域级别。如果实例名称出现在匹配的块名称上,则允许   实例名称不同;它们不需要匹配即可匹配块。 [...]。

因此,如果您的顶点着色器使用实例名称,则片段着色器也必须使用一个实例名称。

  

此外,如果glslangValidator-> spirv-opt-> spirv-cross中的某项更改了我的着色器的链接界面,我是否应该考虑该错误并报告该错误?

我不知道他们对程序的各个部分有何保证。我不会直觉上期望至少将组合未优化和优化零件的工作流程保证能正常工作。