I have a render pass with two subpasses. The first subpass renders the scene to an image, the second renders a fullscreen quad to a swapchain image using the initial image as an input attachment in the fragment shader.
When I call subpassLoad, it is only giving me black. The fragment shader is working, because I can render a static colour with it. Hopefully the code below gives you an idea of how I’ve set things up. Let me know if you need more. Thanks.
This is the fragment shader used in the second subpass:
#version 440
layout(set = 0, binding = 2, input_attachment_index=0) uniform subpassInput renderImage;
layout(location = 0) out vec4 fragColour;
void main()
{
fragColour = subpassLoad(renderImage);
}
This is how the render pass is set up:
VkAttachmentDescription akAttachments[3];
// Initial render image
akAttachments[0].flags = 0;
akAttachments[0].format = VK_FORMAT_R8G8B8A8_UNORM;
akAttachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
akAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
akAttachments[0].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
akAttachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
akAttachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
akAttachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
akAttachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
// Depth/stencil
akAttachments[1].flags = 0;
akAttachments[1].format = VK_FORMAT_D24_UNORM_S8_UINT;
akAttachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
akAttachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
akAttachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
akAttachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
akAttachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
akAttachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
akAttachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
// Output image
akAttachments[2].flags = 0;
akAttachments[2].format = VK_FORMAT_R8G8B8A8_UNORM;
akAttachments[2].samples = VK_SAMPLE_COUNT_1_BIT;
akAttachments[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
akAttachments[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // TODO: DONT CARE
akAttachments[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
akAttachments[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
akAttachments[2].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
akAttachments[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference kInitalColourRefSub1;
kInitalColourRefSub1.attachment = 0;
kInitalColourRefSub1.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference kInitalColourRefSub2;
kInitalColourRefSub2.attachment = 0;
kInitalColourRefSub2.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference kDepthStencilRef;
kDepthStencilRef.attachment = 1;
kDepthStencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference kFinalColourRef;
kFinalColourRef.attachment = 2;
kFinalColourRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription akSubpasses[2];
akSubpasses[0].flags = 0;
akSubpasses[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
akSubpasses[0].inputAttachmentCount = 0;
akSubpasses[0].pInputAttachments = nullptr;
akSubpasses[0].colorAttachmentCount = 1;
akSubpasses[0].pColorAttachments = &kInitalColourRefSub1;
akSubpasses[0].pResolveAttachments = nullptr;
akSubpasses[0].pDepthStencilAttachment = &kDepthStencilRef;
akSubpasses[0].preserveAttachmentCount = 0;
akSubpasses[0].pPreserveAttachments = nullptr;
akSubpasses[1].flags = 0;
akSubpasses[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
akSubpasses[1].inputAttachmentCount = 1;
akSubpasses[1].pInputAttachments = &kInitalColourRefSub2;
akSubpasses[1].colorAttachmentCount = 1;
akSubpasses[1].pColorAttachments = &kFinalColourRef;
akSubpasses[1].pResolveAttachments = nullptr;
akSubpasses[1].pDepthStencilAttachment = nullptr;
akSubpasses[1].preserveAttachmentCount = 0;
akSubpasses[1].pPreserveAttachments = nullptr;
VkSubpassDependency kDependency;
kDependency.srcSubpass = 0;
kDependency.dstSubpass = 1;
kDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
kDependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
kDependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
kDependency.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
kDependency.dependencyFlags = 0;
VkRenderPassCreateInfo kRenderPassInfo;
kRenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
kRenderPassInfo.pNext = nullptr;
kRenderPassInfo.flags = 0;
kRenderPassInfo.attachmentCount = 3;
kRenderPassInfo.pAttachments = akAttachments;
kRenderPassInfo.subpassCount = 2;
kRenderPassInfo.pSubpasses = akSubpasses;
kRenderPassInfo.dependencyCount = 1;
kRenderPassInfo.pDependencies = &kDependency;
I am using two pipelines, both using the same single descriptor set layout that has 3 descriptors. The first two descriptors are only used in the first pipeline, and the third is the input attachment used in the second pipeline. This is how the input attachment descriptor is set up:
...
kDescSetLayoutBind[2].binding = 2;
kDescSetLayoutBind[2].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
kDescSetLayoutBind[2].descriptorCount = 1;
kDescSetLayoutBind[2].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
kDescSetLayoutBind[2].pImmutableSamplers = nullptr;
VkDescriptorSetLayoutCreateInfo kDescSetLayoutInfo;
kDescSetLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
kDescSetLayoutInfo.pNext = nullptr;
kDescSetLayoutInfo.flags = 0;
kDescSetLayoutInfo.bindingCount = 3;
kDescSetLayoutInfo.pBindings = &kDescSetLayoutBind[0];
...
akPoolSizes[2].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
akPoolSizes[2].descriptorCount = 1;
VkDescriptorPoolCreateInfo kDescPoolInfo;
kDescPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
kDescPoolInfo.pNext = nullptr;
kDescPoolInfo.flags = 0;
kDescPoolInfo.maxSets = 1;
kDescPoolInfo.poolSizeCount = 3;
kDescPoolInfo.pPoolSizes = akPoolSizes;
...
VkDescriptorImageInfo kDescInputAttachInfo;
kDescInputAttachInfo.sampler = VK_NULL_HANDLE;
kDescInputAttachInfo.imageView = m_hInitialRenderImageView;
kDescInputAttachInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
...
akWriteSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
akWriteSets[2].pNext = nullptr;
akWriteSets[2].dstSet = m_hDescSet;
akWriteSets[2].dstBinding = 2;
akWriteSets[2].dstArrayElement = 0;
akWriteSets[2].descriptorCount = 1;
akWriteSets[2].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
akWriteSets[2].pImageInfo = &kDescInputAttachInfo;
akWriteSets[2].pBufferInfo = nullptr;
akWriteSets[2].pTexelBufferView = nullptr;
// Update sets
Currently I am not doing any draw calls in the first subpass, just clearing the image to red, so I would expect subpassLoad to return red. This is the render command:
VkClearValue kClearValues[3];
kClearValues[0].color.float32[0] = 1.0f;
kClearValues[0].color.float32[1] = 0.0f;
kClearValues[0].color.float32[2] = 0.0f;
kClearValues[0].color.float32[3] = 1.0f;
kClearValues[1].depthStencil.depth = 1.0f;
kClearValues[1].depthStencil.stencil = 0;
kClearValues[2].color.float32[0] = 0.0f;
kClearValues[2].color.float32[1] = 1.0f;
kClearValues[2].color.float32[2] = 0.0f;
kClearValues[2].color.float32[3] = 1.0f;
...
VkRenderPassBeginInfo kRenderBeginInfo;
kRenderBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
kRenderBeginInfo.pNext = nullptr;
kRenderBeginInfo.renderPass = m_hRenderPass;
kRenderBeginInfo.framebuffer = m_kFramebuffers[uiImage];
kRenderBeginInfo.renderArea = {
0, 0,
spkRenderWindow->GetWindow()->GetWidth(),
spkRenderWindow->GetWindow()->GetHeight()
};
kRenderBeginInfo.clearValueCount = 3;
kRenderBeginInfo.pClearValues = kClearValues;
vkCmdBeginRenderPass(
m_kFrameCmdBuffers[uiImage],
&kRenderBeginInfo,
VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindDescriptorSets(
m_kFrameCmdBuffers[uiImage],
VK_PIPELINE_BIND_POINT_GRAPHICS,
m_kPipelineLayouts[0],
0,
1,
&m_hDescSet,
0,
nullptr);
vkCmdBindPipeline(
m_kFrameCmdBuffers[uiImage],
VK_PIPELINE_BIND_POINT_GRAPHICS,
m_kPipelines[0]);
// Bind viewport + scissor
// Draw calls (commented out)
vkCmdNextSubpass(
m_kFrameCmdBuffers[uiImage],
VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindDescriptorSets(
m_kFrameCmdBuffers[uiImage],
VK_PIPELINE_BIND_POINT_GRAPHICS,
m_kPipelineLayouts[0],
0,
1,
&m_hDescSet,
0,
nullptr);
vkCmdBindPipeline(
m_kFrameCmdBuffers[uiImage],
VK_PIPELINE_BIND_POINT_GRAPHICS,
m_kPipelines[1]);
// Bind viewport + scissor
// (Quad hardcoded in shader)
vkCmdDraw(
m_kFrameCmdBuffers[uiImage],
6,
1,
0,
0);
vkCmdEndRenderPass(
m_kFrameCmdBuffers[uiImage]);