attackgoat / screen-13

Screen 13 is an easy-to-use Vulkan rendering engine in the spirit of QBasic.
Apache License 2.0
264 stars 13 forks source link

Depth buffer missing or incorrect barriers in some cases. #82

Open DGriffin91 opened 2 months ago

DGriffin91 commented 2 months ago

In my renderer, I sample the depth buffer as a texture. I've noticed that this seems to result in incorrect barriers. I've tried to make a more minimal example of the kind of thing I'm doing based on the multipass example. This is also based on https://github.com/attackgoat/screen-13/pull/81

multipass.rs

In my renderer this seems to result in the depth buffer not being written to for some passes.

VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL when the previous known layout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL SYNC_FRAGMENT_SHADER_SHADER_SAMPLED_READ, prior_usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE

VUID-VkImageMemoryBarrier-oldLayout-01197(ERROR / SPEC): msgNum: 307231540 - Validation Error: [ VUID-VkImageMemoryBarrier-oldLayout-01197 ] Object 0: handle = 0x18c31e421a0, type = VK_OBJECT_TYPE_COMMAND_BUFFER; Object 1: handle = 0xea7170000000031, type = VK_OBJECT_TYPE_IMAGE; | MessageID = 0x124ffb34 | vkCmdPipelineBarrier(): pImageMemoryBarriers[0].image (VkImage 0xea7170000000031[]) cannot transition the layout of aspect=2, level=0, layer=0 
from VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL when the previous known layout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL. The Vulkan spec states: If srcQueueFamilyIndex and dstQueueFamilyIndex define 
a queue family ownership transfer or oldLayout and newLayout define an image layout transition, oldLayout must be VK_IMAGE_LAYOUT_UNDEFINED or the current layout of the image subresources affected by the barrier (https://vulkan.lunarg.com/doc/view/1.3.280.0/windows/1.3-extensions/vkspec.html#VUID-VkImageMemoryBarrier-oldLayout-01197)
    Objects: 2
        [0] 0x18c31e421a0, type: 6, name: NULL
        [1] 0xea7170000000031, type: 10, name: NULL
VUID-vkCmdBeginRenderPass-initialLayout-00900(ERROR / SPEC): msgNum: -1246962192 - Validation Error: [ VUID-vkCmdBeginRenderPass-initialLayout-00900 ] Object 0: handle = 0x18c31e421a0, type = VK_OBJECT_TYPE_COMMAND_BUFFER; Object 1: handle = 0x210d07000000003a, type = VK_OBJECT_TYPE_RENDER_PASS; Object 2: handle = 0x89e60f0000000042, type = VK_OBJECT_TYPE_FRAMEBUFFER; Object 3: handle = 0xea7170000000031, type = VK_OBJECT_TYPE_IMAGE; Object 4: handle = 0x5eb05e000000003b, type = VK_OBJECT_TYPE_IMAGE_VIEW; | MessageID = 0xb5acddf0 | vkCmdBeginRenderPass(): pCreateInfo->pAttachments[1] You cannot start a render pass using attachment 1 where the render pass initial layout is VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL and the previous known layout of the attachment is VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. The layouts must match, or the render pass initial layout for the attachment must be 
VK_IMAGE_LAYOUT_UNDEFINED. The Vulkan spec states: If the initialLayout member of any of the VkAttachmentDescription structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is not VK_IMAGE_LAYOUT_UNDEFINED, then each such initialLayout must be equal to the current layout of the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin (https://vulkan.lunarg.com/doc/view/1.3.280.0/windows/1.3-extensions/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00900)
    Objects: 5
        [0] 0x18c31e421a0, type: 6, name: NULL
        [1] 0x210d07000000003a, type: 18, name: NULL
        [2] 0x89e60f0000000042, type: 24, name: NULL
        [3] 0xea7170000000031, type: 10, name: NULL
        [4] 0x5eb05e000000003b, type: 14, name: NULL
SYNC-HAZARD-READ-AFTER-WRITE(ERROR / SPEC): msgNum: -455515022 - Validation Error: [ SYNC-HAZARD-READ-AFTER-WRITE ] Object 0: handle = 0x5eb05e000000003b, type = VK_OBJECT_TYPE_IMAGE_VIEW; | MessageID = 0xe4d96472 | vkCmdDraw():  Hazard READ_AFTER_WRITE for VkImageView 0x5eb05e000000003b[], in VkCommandBuffer 0x18c31e421a0[], and VkPipeline 0x603cd90000000044[], VkDescriptorSet 0x944a2c0000000039[], type: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageLayout: VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, binding #0, index 0. Access info (usage: SYNC_FRAGMENT_SHADER_SHADER_SAMPLED_READ, prior_usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, write_barriers: 
0, command: vkCmdDrawIndexed, seq_no: 9, reset_no: 1).
    Objects: 1
        [0] 0x5eb05e000000003b, type: 14, name: NULL
VUID-vkAcquireNextImageKHR-semaphore-01779(ERROR / SPEC): msgNum: 1461184347 - Validation Error: [ VUID-vkAcquireNextImageKHR-semaphore-01779 ] Object 0: handle = 0x3fbcd60000000028, type = VK_OBJECT_TYPE_SEMAPHORE; | MessageID = 0x5717e75b | vkAcquireNextImageKHR():  Semaphore must not have any pending operations. The Vulkan spec states: If semaphore is not VK_NULL_HANDLE it must not have any uncompleted signal or wait operations pending (https://vulkan.lunarg.com/doc/view/1.3.280.0/windows/1.3-extensions/vkspec.html#VUID-vkAcquireNextImageKHR-semaphore-01779)
    Objects: 1
        [0] 0x3fbcd60000000028, type: 5, name: NULL
attackgoat commented 2 months ago

I ran into this recently with a depth pass and was able to resolve it by changing src/graph/resolver.rs:1971 to use the "late" access instead of "early":

let next_access = late.access;

I haven't thought very deeply about what else this might break, so I haven't pushed the fix up yet.

DGriffin91 commented 2 months ago

So it looks like with that there is one less validation error, but the rest remain and depth still seems to not be written.

The validation error that goes away with let next_access = late.access;:

VUID-VkImageMemoryBarrier-oldLayout-01197(ERROR / SPEC): msgNum: 307231540 - Validation Error: [ VUID-VkImageMemoryBarrier-oldLayout-01197 ] Object 0: handle = 0x200555071f0, type = VK_OBJECT_TYPE_COMMAND_BUFFER; Object 1: handle = 0xea7170000000031, type = VK_OBJECT_TYPE_IMAGE; | MessageID = 0x124ffb34 | vkCmdPipelineBarrier(): pImageMemoryBarriers[0].image (VkImage 0xea7170000000031[]) cannot transition the layout 
of aspect=2, level=0, layer=0 from VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL when the previous known layout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL. The Vulkan spec states: If srcQueueFamilyIndex and dstQueueFamilyIndex define a queue family ownership transfer or oldLayout and newLayout define an image layout transition, oldLayout must be VK_IMAGE_LAYOUT_UNDEFINED or the current layout of 
the image subresources affected by the barrier (https://vulkan.lunarg.com/doc/view/1.3.280.0/windows/1.3-extensions/vkspec.html#VUID-VkImageMemoryBarrier-oldLayout-01197)
DGriffin91 commented 2 months ago

I updated https://github.com/attackgoat/screen-13/pull/81 to also check depth both ways and a couple other small changes and now the depth seems to be written/read correctly.

I still get one depth related validation error:

VUID-vkCmdBeginRenderPass-initialLayout-00900(ERROR / SPEC): msgNum: -1246962192 - Validation Error: [ VUID-vkCmdBeginRenderPass-initialLayout-00900 ] Object 0: handle = 0x24a6b5e2c80, type = VK_OBJECT_TYPE_COMMAND_BUFFER; Object 1: handle = 0x92c9c400000001ea, type = VK_OBJECT_TYPE_RENDER_PASS; Object 2: handle = 0x2cebe2000000020e, type = VK_OBJECT_TYPE_FRAMEBUFFER; Object 3: handle = 0xad25e500000001ad, type = VK_OBJECT_TYPE_IMAGE; Object 4: handle = 0xb64ded0000000200, type = VK_OBJECT_TYPE_IMAGE_VIEW; | MessageID = 0xb5acddf0 | vkCmdBeginRenderPass(): pCreateInfo->pAttachments[1] You cannot start a render pass using attachment 1 where the render pass initial layout is VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL and the previous known layout of the attachment is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL. The layouts must match, or the render pass initial layout for the attachment must be VK_IMAGE_LAYOUT_UNDEFINED. The Vulkan spec states: If the initialLayout member of any of the VkAttachmentDescription structures specified when creating the render pass specified in the renderPass member of pRenderPassBegin is not VK_IMAGE_LAYOUT_UNDEFINED, then each such initialLayout must be equal to the current layout of the corresponding attachment image subresource of the framebuffer specified in the framebuffer member of pRenderPassBegin (https://vulkan.lunarg.com/doc/view/1.3.280.0/windows/1.3-extensions/vkspec.html#VUID-vkCmdBeginRenderPass-initialLayout-00900)

If I use let next_access = late.access; then the above error goes away and I but get a new one:

SYNC-HAZARD-READ-AFTER-WRITE(ERROR / SPEC): msgNum: -455515022 - Validation Error: [ SYNC-HAZARD-READ-AFTER-WRITE ] Object 0: handle = 0x45d6d1000000004c, type = VK_OBJECT_TYPE_RENDER_PASS; | MessageID = 0xe4d96472 | vkCmdBeginRenderPass():  Hazard READ_AFTER_WRITE in subpass 0 for attachment 0 aspect color during load with loadOp VK_ATTACHMENT_LOAD_OP_LOAD. Access info (usage: SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_READ, prior_usage: SYNC_IMAGE_LAYOUT_TRANSITION, write_barriers: SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_WRITE, command: vkCmdPipelineBarrier, seq_no: 3, VkImage 0x908683000000001d[], VkImage 0xab64de0000000020[], VkImage 0x2cfba2000000001c[], reset_no: 1).