Multiple render passes are pretty traditional and I thought I’d play around with that in Vulkan given the extra setup related to the VkRenderPass
object etc. I am running into an issue which looks to be synchronization related.
The artificial scenario:
- Render Pass A: Render the scene and just write a solid color to each fragment
- Render Pass B: Read result of A (using a sampler) and multiply with texture for final present output
Here’s the result I get:
First image shows where both render passes set clear color to black. Second image RenderPass_A has set clear color to green and writing cyan to fragments, and RenderPass_B has clear color red. So this kind of tells me that RenderPass_A haven’t finished writing before B is reading the result.
Both render passes use the same vertex and index buffer.
The command buffer recording looks like (semi-pseudo for brevity):
void BuildCommandBuffer()
{
vkBeginCommandBuffer(cmdBuf);
// RenderPass_A
vkCmdBeginRenderPass(cmdBuf, &RenderPass_A, VK_SUBPASS_CONTENTS_INLINE);
{
vkCmdBindPipeline(cmdBuf, ..., RenderPassA.Pipeline);
vkCmdBindVertexBuffers( ... );
vkCmdBindIndexBuffer( ... );
vkCmdBindDescriptorSets( ... , RenderPass_A.PipelineLayout, ..., RenderPass_A.DescriptorSet);
vkCmdPushConstants( ... );
vkCmdDrawIndexed( ... );
}
vkCmdEndRenderPass(cmdBuf);
// RenderPass_B
vkCmdBeginRenderPass( ..., RenderPass_B, ...);
{
vkCmdBindPipeline(... RenderPass_B.Pipeline);
vkCmdBindVertexBuffers( ... );
vkCmdBindIndexBuffers( ... );
vkCmdBindDescriptorSets( ... );
vkCmdPushConstants( ... );
vkCmdDrawIndex( ... )
}
vkCmdEndRenderPass( ... );
vkEndCommandBuffer(cmdBuf);
}
RenderPass_A’s VkRenderPass
:
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = Format;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkSubpassDependency subpassDependency = {};
subpassDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
subpassDependency.dstSubpass = 0;
subpassDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependency.srcAccessMask = 0;
subpassDependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
RenderPass_B’s VkRenderPass
:
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = Format;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkSubpassDependency subpassDependency = {};
subpassDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
subpassDependency.dstSubpass = 0;
subpassDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependency.srcAccessMask = 0;
subpassDependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
The VkImage
written to by A and read to by B is set to:
initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
My guess is that I haven’t gotten the Subpass dependencies correct. I have tried a “variety” of different stageMask and accessMasks - including FRAGMENT_BIT etc. I have also tried an explicit vkCmdPipelineBarrier
between the two render passes; but I always get the result above.
There are no validation warnings or errors.
Any pointers?