Search code examples
c++graphicsrenderingvulkan

Vulkan, single render pass, 2 shaders, different number of outputs


This is my current setup:

  • Start render pass
  • Shader 1 outputs color to 5 attachments.
  • Shader 2 outputs color to the same 5 attachments
  • Finish recording commands

However that second doesn't really need to output anything to the 5 attachments, only to the first one.

Is it possible to change the number of attachments on the fly? Something like:

  • Start render pass
  • Shader 1 outputs color to 5 attachments.
  • Modify active framebuffer in the render pass
  • Shader 2 outputs color to only one the first attachment.
  • Finish recording commands

Or if that can't be done. Is it possible to switch off attachment clearing between render passes?

Edit the fragment shader in question looks like this:

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

I am trying to get rid of it.

The way I currently do My render pass is:

// Initialize the FB with 5 image attachemnts + the clear values, etc...
vk::RenderPassBeginInfo render_pass_info;
render_pass_info.renderPass = *render_pass;
render_pass_info.framebuffer = *framebuffer;
render_pass_info.renderArea = vk::Rect2D({0,0}, extent);
render_pass_info.clearValueCount = clears.size();
render_pass_info.pClearValues = clears.data();

cmd.beginRenderPass(&render_pass_info, vk::SubpassContents::eInline);

/* setup pipeline 1 info, like it's descriptor sets, samplers etc*/
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphics_pipeline);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0, 1, descriptor_set_ptr, 0, nullptr);

/* Do the same for the second pipeline */
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, *graphics_pipeline);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0, 1, descriptor_set_ptr, 0, nullptr);

The goal is to not output the additional 5 attachments in the shader. Which currently terminates my program with the following error:

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

Solution

  • You have many options for this.

    "Shader 2" can employ write masks to turn off writes to the other attachments. These are found in VkPipelineColorBlendAttachmentState::colorWriteMask, so you simply set this value to 0 to prevent writes to that attachment.

    Alternatively, you can execute "Shader 2" in a separate subpass, one which only uses the attachment of interest.

    Which to use depends on the nature of your rendering operations.