0

在 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

为什么根据规范不明确写入帧缓冲区的附件无效?即为什么不规范如果您不写入附件,则内容会被保留?

4

1 回答 1

1

为什么没有规范,如果您不写入附件,则内容会被保留?

因为 Vulkan 是一个低级的渲染 API。

在 OpenGL 中,就像在 Vulkan 中一样,写入的内容始终由写入掩码状态控制,而不是片段着色器所做的任何事情。如果您有一些附件,同样在 OpenGL 和 Vulkan 中,任何渲染操作都将写入所有附件(假设通过了各种测试),除非使用写入掩码(或混合)来防止这些写入。

请注意,这种区别很可能是硬件问题。如果 GPU 使用专门的硬件来解释片段数据并执行混合/写入掩码等,那么考虑着色器可能没有机制直接传达片段中的哪些值是有效的,哪些不是有效的,这几乎是不合理的。

似乎某些硬件确实可以按照您的意愿处理此问题。或者至少在某些情况下。但是,当我们正在查看未指定的行为时,无法知道是什么触发了它,或者在哪些情况下它可能不起作用。

现在,有人可能会说,鉴于 Vulkan 管道对象包含所有这些状态,构建内部管道状态数据的代码可以检测到哪些值被 FS 写入,并将其余值写入屏蔽。但这有点违背作为低级 API 的观点。

于 2020-02-22T23:49:17.720 回答