diff --git a/implementations/Crafter.Graphics-UI.cpp b/implementations/Crafter.Graphics-UI.cpp index e8ce871..602deca 100644 --- a/implementations/Crafter.Graphics-UI.cpp +++ b/implementations/Crafter.Graphics-UI.cpp @@ -182,15 +182,41 @@ void UIRenderer::Dispatch(GraphicsCommandBuffer cmd, const GraphicsComputeShader const void* push, std::uint32_t pushBytes, std::uint32_t gx, std::uint32_t gy, std::uint32_t gz) { if (!firstDispatchThisFrame_) { - VkMemoryBarrier mb { - .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + // Every UI pass read-modify-writes the same swapchain storage image + // (later passes overdraw earlier ones), so each dispatch must observe + // the previous dispatch's writes. The only resource the hazard touches + // is that one image, so scope the dependency to its subresource with a + // VkImageMemoryBarrier rather than a queue-wide VkMemoryBarrier: same + // correctness, but only this image's shader caches are flushed — + // unrelated buffers/images are no longer invalidated. The image stays + // in VK_IMAGE_LAYOUT_GENERAL (bound as a storage image), so this is a + // pure memory dependency, no layout transition. + // + // The execution dependency is still COMPUTE->COMPUTE over the whole + // queue, so the passes do NOT overlap — this is a narrower cache flush + // only. Eliminating the barriers entirely requires fusing the passes + // into one dispatch (tracked in #47); do not attempt that here. + VkImageMemoryBarrier ib { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = window_->images[window_->currentBuffer], + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, }; vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - 0, 1, &mb, 0, nullptr, 0, nullptr); + 0, 0, nullptr, 0, nullptr, 1, &ib); } firstDispatchThisFrame_ = false; shader.Dispatch(cmd, push, pushBytes, gx, gy, gz);