Search code examples
c++vulkan

The last attachment from the second render pass is wrongly considered an input attachment


I have 2 render passes, each one with 1 subpass. The first render pass contains 3 attachments (depthAttachment, colorAttachment, colorResolveAttachment). The second render pass contains 1 attachment (finalColorAttachment). The second render pass reads in the fragment shader from colorResolveAttachment.

Problem: The validation layers output a warning apparently saying that the attachment in the last render pass is an input attachment, but I don't know why it says so because it is obvious to me that it is not.

vkCreateRenderPass(): pSubpasses[0].pColorAttachments[0] is also an input attachment so the layout (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) must not be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL or VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR. 
The Vulkan spec states: Each attachment must follow the image layout requirements specified for its attachment type

The code where I create both render passes is the following:

    // First render pass -------------------------

    // Final color attachment
    VkAttachmentDescription colorAttachmentResolve{};
    colorAttachmentResolve.format = swapChainImageFormat;
    colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
    colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;  

    VkAttachmentReference colorAttachmentResolveRef{};
    colorAttachmentResolveRef.attachment = 0;
    colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

    // Depth attachment
    VkAttachmentDescription depthAttachment{};
    depthAttachment.format = findDepthFormat(); 
    depthAttachment.samples = msaaSamples;
    depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
    depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 
    depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;  
    depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

    VkAttachmentReference depthAttachmentRef{};
    depthAttachmentRef.attachment = 1;
    depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

    // Color attachment
    VkAttachmentDescription colorAttachment{};
    colorAttachment.format = swapChainImageFormat;
    colorAttachment.samples = msaaSamples;
    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_COLOR_ATTACHMENT_OPTIMAL;

    VkAttachmentReference colorAttachmentRef{};
    colorAttachmentRef.attachment = 2;
    colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

    std::vector<VkAttachmentDescription> attachments  = std::vector<VkAttachmentDescription>{ colorAttachmentResolve, depthAttachment, colorAttachment };

    // Subpass 1:

    VkSubpassDescription subpass{};
    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
    subpass.colorAttachmentCount = 1;
    subpass.pColorAttachments = &colorAttachmentRef;
    subpass.pDepthStencilAttachment = &depthAttachmentRef;
    subpass.pResolveAttachments = &colorAttachmentResolveRef;
    subpass.inputAttachmentCount;
    subpass.pInputAttachments;
    subpass.preserveAttachmentCount;
    subpass.pPreserveAttachments;
    
    VkSubpassDependency dependency{};
    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
    dependency.srcAccessMask = 0;   
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;

    // Create Render Pass 1:
    VkRenderPassCreateInfo renderPassInfo{};
    renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
    renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
    renderPassInfo.pAttachments = attachments.data();
    renderPassInfo.subpassCount = 1;
    renderPassInfo.pSubpasses = &subpass;   
    renderPassInfo.dependencyCount = 1;
    renderPassInfo.pDependencies = &dependency; 

    vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass[0]);

    // Second render pass (Post processing) -------------------------
    
    // Final color attachment (from previous render pass)
    colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

    // Final color Post-Processed attachment
    VkAttachmentDescription colorAttachmentPP{};
    colorAttachmentPP.format = swapChainImageFormat;
    colorAttachmentPP.samples = VK_SAMPLE_COUNT_1_BIT;
    colorAttachmentPP.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachmentPP.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    colorAttachmentPP.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachmentPP.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    colorAttachmentPP.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    colorAttachmentPP.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

    VkAttachmentReference colorAttachmentPPRef{};
    colorAttachmentPPRef.attachment = 0;
    colorAttachmentPPRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

    // Subpass 2
    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
    subpass.colorAttachmentCount = 1;
    subpass.pColorAttachments = &colorAttachmentPPRef;
    subpass.pDepthStencilAttachment = nullptr;
    subpass.pResolveAttachments = nullptr;
    VkAttachmentReference inputAttachments[1] = { colorAttachmentResolveRef };
    subpass.inputAttachmentCount = 1;
    subpass.pInputAttachments = inputAttachments;   // <<< Set input attachments
    subpass.preserveAttachmentCount;
    subpass.pPreserveAttachments;

    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
    dependency.srcAccessMask = 0;
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;

    // Create Render Pass 2:
    renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
    renderPassInfo.attachmentCount = static_cast<uint32_t>(1);
    renderPassInfo.pAttachments = &colorAttachmentPP;
    renderPassInfo.subpassCount = 1;
    renderPassInfo.pSubpasses = &subpass;   
    renderPassInfo.dependencyCount = 1;
    renderPassInfo.pDependencies = &dependency; 

    vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass[1]);

The error message is output during the execution of the second vkCreateRenderPass() and says that pSubpasses[0].pColorAttachments[0] (which is colorAttachmentPP) is also an input attachment. However, this is not true because the only attachment that is also an input attachment is colorAttachmentResolve. This is what I don't understand.


Solution

  • Ok, I solved this issue.

    The validation layers were saying that pSubpasses[0].pColorAttachments[0] was an input attachment. However, after some debugging, I found that colorAttachmentPP was being considered by the validation layers as the input attachment. However, it was not, whereas colorAttachmentResolve was the only input attachment.

    The error was caused because, in the second render pass, both attachments (colorAttachmentPP and colorAttachmentResolve) had the same VkAttachmentReference::attachment value (0). Therefore, it didn't matter what I do to modify the layout of the input attachment (colorAttachmentResolve) because the other attachment (colorAttachmentPP) still had the wrong layout and the validation layers were pointing that out.