Vulkan,为什么验证层(以及扩展规范)禁止管道不写入某些附件?
Vulkan, why do validation layers (and by extension the spec) forbid pipelines from not writing to certain attachments?
在 vulkan 中,如果在单个渲染通道的生命周期内,您天真地渲染到包含多个附件的帧缓冲区,并使用一个管道渲染所有附件,然后再次使用仅渲染其中一个的管道进行渲染你会得到一个错误。
举个例子
考虑下图,这是多通道效果中的中间步骤。
这是通过在反照率之上写一个线框获得的:
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) out vec4 color_out;
layout(location = 1) out vec4 color_out1;
layout(location = 2) out vec4 color_out2;
layout(location = 3) out vec4 color_out3;
layout(location = 4) out vec4 color_out4;
void main()
{
color_out = vec4(1,1,1,1);
color_out1 = vec4(0,0,0,0);
color_out2 = vec4(0,0,0,0);
color_out3 = vec4(0,0,0,0);
color_out4 = vec4(0,0,0,0);
}
4 "noop" 输出并不是必需的,它们的存在只是为了防止 vulkan 错误。
让我们假设我们改为这样做(并且我们也修改了我们的 pieline):
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) out vec4 color_out;
void main()
{
color_out = vec4(1,1,1,1);
}
然后我们得到相同的图像。
但是存在一个关键的区别:
第二张图片产生多个错误,每个附件一个,如下所示:
Message ID name: UNASSIGNED-CoreValidation-Shader-InputNotProduced
Message: Attachment 1 not written by fragment shader; undefined values will be written to attachment
Severity: VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
为什么不明确写入帧缓冲区的附件根据规范无效?即,为什么规范没有规定如果您不写入附件,内容将被保留?
why isn't the spec that if you do not write to an attachment, the contents are preserved?
因为Vulkan是底层渲染API.
在 OpenGL 中,就像在 Vulkan 中一样,写入的内容始终由 write mask 状态控制,而不是片段着色器所做的任何事情。如果您有一定数量的附件,再次在 OpenGL 和 Vulkan 中,任何渲染操作都会写入所有附件(假设通过了各种测试),除非使用写入掩码(或混合)来防止这些写入。
请注意,这种区别很可能是硬件问题。如果 GPU 使用专门的硬件来解释片段数据并执行 blending/write masking/etc,那么考虑着色器可能没有机制来直接传达片段中的哪些值有效以及哪些值是有效的,这几乎是不合理的不是。
它appears that some hardware does handle this as you would prefer。或者至少在某些情况下。但是,当我们查看未指定的行为时,无法知道是什么触发了它,或者在哪些情况下它可能不起作用。
现在,有人可能会说,鉴于 Vulkan 管道对象包含所有这些状态,构建内部管道状态数据的代码可以检测哪些值被 FS 写入并写屏蔽掉其余的.但这有点违背了低级API.
在 vulkan 中,如果在单个渲染通道的生命周期内,您天真地渲染到包含多个附件的帧缓冲区,并使用一个管道渲染所有附件,然后再次使用仅渲染其中一个的管道进行渲染你会得到一个错误。
举个例子
考虑下图,这是多通道效果中的中间步骤。
这是通过在反照率之上写一个线框获得的:
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) out vec4 color_out;
layout(location = 1) out vec4 color_out1;
layout(location = 2) out vec4 color_out2;
layout(location = 3) out vec4 color_out3;
layout(location = 4) out vec4 color_out4;
void main()
{
color_out = vec4(1,1,1,1);
color_out1 = vec4(0,0,0,0);
color_out2 = vec4(0,0,0,0);
color_out3 = vec4(0,0,0,0);
color_out4 = vec4(0,0,0,0);
}
4 "noop" 输出并不是必需的,它们的存在只是为了防止 vulkan 错误。
让我们假设我们改为这样做(并且我们也修改了我们的 pieline):
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) out vec4 color_out;
void main()
{
color_out = vec4(1,1,1,1);
}
然后我们得到相同的图像。
但是存在一个关键的区别:
第二张图片产生多个错误,每个附件一个,如下所示:
Message ID name: UNASSIGNED-CoreValidation-Shader-InputNotProduced
Message: Attachment 1 not written by fragment shader; undefined values will be written to attachment
Severity: VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
为什么不明确写入帧缓冲区的附件根据规范无效?即,为什么规范没有规定如果您不写入附件,内容将被保留?
why isn't the spec that if you do not write to an attachment, the contents are preserved?
因为Vulkan是底层渲染API.
在 OpenGL 中,就像在 Vulkan 中一样,写入的内容始终由 write mask 状态控制,而不是片段着色器所做的任何事情。如果您有一定数量的附件,再次在 OpenGL 和 Vulkan 中,任何渲染操作都会写入所有附件(假设通过了各种测试),除非使用写入掩码(或混合)来防止这些写入。
请注意,这种区别很可能是硬件问题。如果 GPU 使用专门的硬件来解释片段数据并执行 blending/write masking/etc,那么考虑着色器可能没有机制来直接传达片段中的哪些值有效以及哪些值是有效的,这几乎是不合理的不是。
它appears that some hardware does handle this as you would prefer。或者至少在某些情况下。但是,当我们查看未指定的行为时,无法知道是什么触发了它,或者在哪些情况下它可能不起作用。
现在,有人可能会说,鉴于 Vulkan 管道对象包含所有这些状态,构建内部管道状态数据的代码可以检测哪些值被 FS 写入并写屏蔽掉其余的.但这有点违背了低级API.