为什么当一个着色器经过优化而另一个着色器未优化时,我的 GLSL 程序无法链接?



我正在使用着色器工具链,从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中的某些内容正在更改着色器的链接界面,我是否应该将其视为错误并报告它?

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

因为规范是这样说的。GLSL 4.60 规范,第 4.3.9 节。"接口块"状态(强调我的(:

着色器接口(如上所述(中匹配的块名称必须匹配,具有 具有相同类型序列和相同序列的相同数量的声明 成员名称,以及具有匹配的成员布局资格(请参阅下一节(。匹配的统一或着色器存储块名称(但不是输入或输出块名称(还必须 要么都缺少实例名称,要么都有实例名称,将其成员放在 相同的范围级别。当实例名称出现在匹配的块名称上时,允许 实例名称不同;它们不需要匹配块即可匹配。[...].

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

另外,如果glslangValidator->spirv-opt->spirv-cross中的某些内容正在更改着色器的链接界面,我是否应该将其视为错误并报告它?

我不知道他们对程序的各个部分做了什么保证。我不会直观地期望您组合未优化和优化部分的工作流程至少可以保证工作。

最新更新