Search code examples
c++synchronizationvulkanvalidationerror

Vulkan incorrectly identifying render pass layout and throwing validation error despite synchronization being enabled


I'm fairly new to Vulkan and am just trying to get a renderer working; however, I keep getting a validation error saying:

Validation Error: [ VUID-VkAttachmentReference-synchronization2-06910 ] Object 0: handle = 0x16b33ac6fe0, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x7d7f9761 | vkCreateRenderPass(): Layout for pSubpasses[0].pColorAttachments[0] is VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL but without synchronization2 enabled the layout must not be VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR or VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR. The Vulkan spec states: If the synchronization2 feature is not enabled, layout must not be VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR or VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR (https://vulkan.lunarg.com/doc/view/1.3.243.0/windows/1.3-extensions/vkspec.html#VUID-VkAttachmentReference-synchronization2-06910)

However, I have synchronization enabled

void VulkanRenderer::createSyncObjects()
{
    VkSemaphoreCreateInfo semaphoreInfo {};
    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;

    VkFenceCreateInfo fenceInfo{};
    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;

    VK_CHECK(vkCreateSemaphore(_device, &semaphoreInfo, nullptr, &_imageAvailableSemaphore));
    VK_CHECK(vkCreateSemaphore(_device, &semaphoreInfo, nullptr, &_renderFinishedSemaphore));

    VK_CHECK(vkCreateFence(_device, &fenceInfo, nullptr, &_inFlightFence));
}

and I don't even use VK_IMAGE_LAYOUT_OPTIMAL_KHR or VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR

void VulkanRenderer::createDefaultRenderPass()
{
    VkAttachmentDescription colorAttachment
    {
        .format = _swapchainImageFormat,
        .samples = VK_SAMPLE_COUNT_1_BIT,
        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
    };

    VkAttachmentReference colorAttachmentRef
    {
        .attachment = 0,
        .layout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL
    };

    VkSubpassDescription subpass
    {
        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
        .colorAttachmentCount = 1,
        .pColorAttachments = &colorAttachmentRef
    };

    VkRenderPassCreateInfo renderPassCreateInfo { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
    renderPassCreateInfo.attachmentCount = 1;
    renderPassCreateInfo.pAttachments = &colorAttachment;
    renderPassCreateInfo.subpassCount = 1;
    renderPassCreateInfo.pSubpasses = &subpass;

    VK_CHECK(vkCreateRenderPass(_device, &renderPassCreateInfo, nullptr, &_renderPass));
}

And yes, I do call both of these functions

void VulkanRenderer::Init(RendererSettings settings)
{
    _rendererSettings = settings;

    initCore();

    createSwapchain();

    createCommands();

    createSyncObjects();

    createDefaultRenderPass();

    createFramebuffers();
}

I don't really have a great understanding of Vulkan or any to the things I need, but I believe this should work. I would also like to know if I need to fix these validation errors or if it will still work fine without if I'm to encounter another one that I can't solve in the future.


Solution

  • Ok, so i actually know what i did wrong now. I wasn't able to find many resources on how to enable synchronization2 with vkbootstrap so I'll put what I did here.

    Using vkbootstrap, I created my device using this:

    vkb::DeviceBuilder deviceBuilder { vkbPhysicalDevice };
    vkb::Device vkbDevice { deviceBuilder.build().value() };
    

    but to enable synchronization2, I needed to do this:

    VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR };
    synchronization2Features.pNext = nullptr;
    synchronization2Features.synchronization2 = VK_TRUE;
    
    vkb::DeviceBuilder deviceBuilder { vkbPhysicalDevice };
    deviceBuilder.add_pNext(&synchronization2Features);
    vkb::Device vkbDevice { deviceBuilder.build().value() };
    

    This allowed me to use synchronization2 and VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL with vkbootstrap.