I am trying to first render some content to an R8_UNORM image view in subpass 0, and then use the result as an input attachment in subpass 1, using subpassLoad in the fragment shader. However, the final output from the render pass (which is also the swapchain image(s) that is presented) contains garbage (see https://imgur.com/a/RmNdcxg) using the following fragment shader:
#version 420
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput input_text;
layout(location=0) out vec4 color;
void main()
{
float value = subpassLoad(input_text).r;
if (value > 0.0f) {
color = vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
}
Yet, using this fragment shader:
#version 420
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput input_text;
layout(location=0) out vec4 color;
void main()
{
float value = subpassLoad(input_text).r;
if (value > 0.0f) {
color = vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
else {
color = vec4(0.0f, 1.0f, 0.0f, 1.0f);
}
}
gives me the expected results (see https://imgur.com/a/JfhuJUk), so I'm suspecting some synchronization issue that isn't present when each fragment is written to.
The clear values used for the two framebuffer attachments are as follows:
VkClearColorValue black_clear_color = { 0.0f, 0.0f, 0.0f, 0.0f };
VkClearColorValue red_clear_color = { 1.0f, 0.0f, 0.0f, 1.0f };
VkClearValue clear_value[2];
clear_value[0].color = vk_black_clear_color; // R8_UNORM attachment
clear_value[1].color = vk_red_clear_color; // Swapchain attachment
with the fragment shader for subpass 0 always writing 1.0f to each fragment it is to shade.
Here's what I deem to be the relevant code:
Command buffer recording, submission, and image presentation
// Record
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, text_graphics_pipeline);
vkCmdBindVertexBuffers(command_buffer, 0, 1, &text_vertex_buffer, &vertex_buffer_offset);
vkCmdDraw(command_buffer, 15, 1, 0, 0);
vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, final_graphics_pipeline);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, final_pipeline_layout, 0, 1, &final_descriptor_set, 0, NULL);
vkCmdBindVertexBuffers(command_buffer, 0, 1, &final_vertex_buffer, &vertex_buffer_offset);
vkCmdDraw(command_buffer, 6, 1, 0, 0);
vkCmdEndRenderPass(command_buffer);
CHECK_VK_RES(vkEndCommandBuffer(command_buffer));
// Submit
VkPipelineStageFlags pipeline_wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = NULL;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &swapchain_image_avilable_semaphore;
submit_info.pWaitDstStageMask = &pipeline_wait_stages;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &command_buffer_finished_semaphore;
CHECK_VK_RES(vkQueueSubmit(queue, 1, &submit_info, command_buffer_finished_fence));
// Present
VkPresentInfoKHR present_info;
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.pNext = NULL;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &command_buffer_finished_semaphore;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain;
present_info.pImageIndices = &image_available_idx;
present_info.pResults = NULL;
CHECK_VK_RES(vkQueuePresentKHR(queue, &present_info));
Render Pass Setup
// Render pass attachments
VkAttachmentDescription vk_render_pass_attachment_descriptions[2];
// Text attachment
render_pass_attachment_descriptions[0].flags = 0;
render_pass_attachment_descriptions[0].format = VK_FORMAT_R8_UNORM;
render_pass_attachment_descriptions[0].samples = VK_SAMPLE_COUNT_1_BIT;
render_pass_attachment_descriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
render_pass_attachment_descriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
render_pass_attachment_descriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
render_pass_attachment_descriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
render_pass_attachment_descriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
render_pass_attachment_descriptions[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// Final attachment
render_pass_attachment_descriptions[1].flags = 0;
render_pass_attachment_descriptions[1].format = swapchain_format; // BGRA8_UNORM
render_pass_attachment_descriptions[1].samples = VK_SAMPLE_COUNT_1_BIT;
render_pass_attachment_descriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
render_pass_attachment_descriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
render_pass_attachment_descriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
render_pass_attachment_descriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
render_pass_attachment_descriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
render_pass_attachment_descriptions[1].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
// Subpass descriptions
VkSubpassDescription render_pass_subpass_descriptions[2];
// Subpass 0
VkAttachmentReference text_subpass_color_attachment_reference;
text_subpass_color_attachment_reference.attachment = 0;
text_subpass_color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
render_pass_subpass_descriptions[0].flags = 0;
render_pass_subpass_descriptions[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
render_pass_subpass_descriptions[0].inputAttachmentCount = 0;
render_pass_subpass_descriptions[0].pInputAttachments = NULL;
render_pass_subpass_descriptions[0].colorAttachmentCount = 1;
render_pass_subpass_descriptions[0].pColorAttachments = &text_subpass_color_attachment_reference;
render_pass_subpass_descriptions[0].pResolveAttachments = NULL;
render_pass_subpass_descriptions[0].pDepthStencilAttachment = NULL;
render_pass_subpass_descriptions[0].preserveAttachmentCount = 0;
render_pass_subpass_descriptions[0].pPreserveAttachments = NULL;
// Subpass 1
VkAttachmentReference final_subpass_input_attachment_reference;
final_subpass_input_attachment_reference.attachment = 0;
final_subpass_input_attachment_reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference final_subpass_color_attachment_reference;
final_subpass_color_attachment_reference.attachment = 1;
final_subpass_color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
render_pass_subpass_descriptions[1].flags = 0;
render_pass_subpass_descriptions[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
render_pass_subpass_descriptions[1].inputAttachmentCount = 1;
render_pass_subpass_descriptions[1].pInputAttachments = &final_subpass_input_attachment_reference;
render_pass_subpass_descriptions[1].colorAttachmentCount = 1;
render_pass_subpass_descriptions[1].pColorAttachments = &final_subpass_color_attachment_reference;
render_pass_subpass_descriptions[1].pResolveAttachments = NULL;
render_pass_subpass_descriptions[1].pDepthStencilAttachment = NULL;
render_pass_subpass_descriptions[1].preserveAttachmentCount = 0;
render_pass_subpass_descriptions[1].pPreserveAttachments = NULL;
// Subpass dependencies
VkSubpassDependency renderpass_subpass_dependencies[2];
// Ensure subpass 1's color attachment (swapchain image) is transitioned before it's written to
// since the pWaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
renderpass_subpass_dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
renderpass_subpass_dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
renderpass_subpass_dependencies[0].srcAccessMask = 0;
renderpass_subpass_dependencies[0].dstSubpass = 1;
renderpass_subpass_dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
renderpass_subpass_dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
renderpass_subpass_dependencies[0].dependencyFlags = 0;
// Subpass 1 cannot read from its input attachment before subpass 0 finishes writing to its color attachment
renderpass_subpass_dependencies[1].srcSubpass = 0;
renderpass_subpass_dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
renderpass_subpass_dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
renderpass_subpass_dependencies[1].dstSubpass = 1;
renderpass_subpass_dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
renderpass_subpass_dependencies[1].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
renderpass_subpass_dependencies[1].dependencyFlags = 0;
// Render pass
VkRenderPassCreateInfo render_pass_info;
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_info.pNext = NULL;
render_pass_info.flags = 0;
render_pass_info.attachmentCount = 2;
render_pass_info.pAttachments = render_pass_attachment_descriptions;
render_pass_info.subpassCount = 2;
render_pass_info.pSubpasses = render_pass_subpass_descriptions;
render_pass_info.dependencyCount = 2;
render_pass_info.pDependencies = renderpass_subpass_dependencies;
VkRenderPass render_pass;
CHECK_VK_RES(vkCreateRenderPass(vk_device, &render_pass_info, NULL, &render_pass));
Any help would be greatly appreciated, as I can't seem to see what's wrong here.