c++graphicsvulkanvalidation-layers

Vulkan, why do validation layers (and by extension the spec) forbid pipelines from not writing to certain attachments?


In vulkan, if under the lifetime of a single render pass you naively render to a framebuffer that contains multiple attachemnts with a pipeline that renders to all of them and then render again with a pipeline that only renders to one of them you will get an error.

Let me give an example.

Consider the following image, which is an intermediary step in a multi pass effect. enter image description here

Which is obtained from writing a wireframe on top of an albedo:

#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);
}

The 4 "noop" outputs are not really necessary, they exist merely to prevent vulkan errors.

Let's assume we instead do this (and we modify our pieline as well):

#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);
}

Then we obtain the same image.

enter image description here

However a critical difference exists:

The second image produces multiple errors, one for each attachemnt, which look like this:

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 is not explicitely writing to the attachments of a framebuffer not valid as per the spec? i.e why isn't the spec that if you do not write to an attachment, the contents are preserved?


Solution

  • why isn't the spec that if you do not write to an attachment, the contents are preserved?

    Because Vulkan is a low-level rendering API.

    What gets written to has always, in OpenGL just as in Vulkan, been governed by the write mask state, not anything the fragment shader does. If you have some number of attachments, again in OpenGL as well as Vulkan, any rendering operation will write to all of them (assuming the various tests are passed) unless write masks (or blending) are employed to prevent those writes.

    Note that this distinction may well be a hardware issue. If a GPU uses specialized hardware to interpret fragment data and perform blending/write masking/etc, it is hardly unreasonable to consider that there may be no mechanism for the shader to directly communicate which values in the fragment are valid and which are not.

    It appears that some hardware does handle this as you would prefer. Or at least in some subset of cases. However, as we're looking at unspecified behavior, there's no way to know what triggers it or in which cases it may not function.

    Now, one might say that, given that the Vulkan pipeline object includes all of this state, the code which builds the internal pipeline state data could just detect which values get written by the FS and write-mask out the rest. But that's kind of against the point of being a low-level API.