[Fix] (MG_Backend/DirectVulkan): render passes had zero subpass dependencies and same-layout transitions emit no barrier, so tilers could race tile loads against prior passes' stores (flickering artifacts in multi-pass chains like MC 26.3 OIT); add conservative external dependencies both ways

This commit is contained in:
2026-07-17 21:03:52 -04:00
parent 0de9861da4
commit df7f5a369d
@@ -979,6 +979,52 @@ namespace MobileGL::MG_Backend::DirectVulkan {
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
// External subpass dependencies. Without them there is NO execution/memory
// dependency between consecutive render passes (or a pass and a transfer)
// touching the same attachments when the image layout does not change — the
// layout-transition helper no-ops on identical layouts and no other barrier
// exists. Tile-based GPUs then race tile loads against the previous pass's
// stores (multi-pass FBO chains like MC 26.3's OIT flicker on Adreno).
// Conservative both-ways dependencies: prior writes (attachment output,
// depth/stencil, transfer, shader) are made visible to this pass's loads,
// and this pass's attachment writes to subsequent sampling/transfer/loads.
VkSubpassDependency subpassDependencies[2];
subpassDependencies[0] = {};
subpassDependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
subpassDependencies[0].dstSubpass = 0;
subpassDependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
subpassDependencies[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
subpassDependencies[0].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpassDependencies[0].dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_SHADER_READ_BIT;
subpassDependencies[0].dependencyFlags = 0;
subpassDependencies[1] = {};
subpassDependencies[1].srcSubpass = 0;
subpassDependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
subpassDependencies[1].srcStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
subpassDependencies[1].srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
subpassDependencies[1].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
subpassDependencies[1].dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
subpassDependencies[1].dependencyFlags = 0;
// Render Pass
VkRenderPassCreateInfo renderPassCreateInfo;
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
@@ -988,8 +1034,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
renderPassCreateInfo.pAttachments = attachmentDescriptions.data();
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpassDesc;
renderPassCreateInfo.dependencyCount = 0;
renderPassCreateInfo.pDependencies = nullptr;
renderPassCreateInfo.dependencyCount = 2;
renderPassCreateInfo.pDependencies = subpassDependencies;
VkRenderPass renderPass = VK_NULL_HANDLE;
VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass));