From 8d83dedc0f1475f660be4e2d11d6f788a03f6fdb Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 17 Jul 2026 19:24:55 -0400 Subject: [PATCH] [Fix] (MG_Backend/DirectVulkan): pending deferred clears outlived blit/copy writes into the same texture and later stomped them (OIT's cloud_depth copy was erased by its own earlier queued clear); materialize destination pending clears before blit/copy writes --- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 851ac679..416fda81 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -4353,6 +4353,21 @@ void main() { sourceTexture->GetExternalIndex()); } + if (!drawIsDefaultFbo) { + // A clear queued for the destination predates this blit in API order; + // execute it now, or its deferred materialization would later stomp the + // copied contents (MC 26.3 OIT clears cloud_depth, then blits the main + // depth into it - the stale loadOp=CLEAR erased the copy). + const auto destAttachmentType = ResolveFramebufferCopyAttachmentType(*drawFbo, false, dstBinding.aspectMask); + const auto& destAttachment = drawFbo->GetAttachment(destAttachmentType); + auto destTexture = destAttachment.GetTexture(); + MOBILEGL_ASSERT(destTexture != nullptr, "BlitFramebuffer: depth destination texture attachment is null"); + const Bool dstClearReady = MaterializePendingClearForTexture(frame.commandBuffer, *destTexture); + MOBILEGL_ASSERT(dstClearReady, + "BlitFramebuffer: failed to materialize pending clear for depth destination textureId=%d", + destTexture->GetExternalIndex()); + } + const VkImageLayout srcOriginalLayout = readIsDefaultFbo ? m_swapchainObject.GetDepthStencilImageLayout(m_imageIndexAcquired) : *srcBinding.trackedLayout; @@ -4489,6 +4504,19 @@ void main() { sourceTexture->GetExternalIndex()); } + if (!drawIsDefaultFbo) { + // A clear queued for the destination predates this blit in API order; execute + // it now, or its deferred materialization would later stomp the blitted color. + const auto& destAttachment = drawFbo->GetAttachment(drawFbo->GetDrawBuffers()[0]); + auto destTexture = destAttachment.GetTexture(); + if (destTexture != nullptr) { + const Bool dstClearReady = MaterializePendingClearForTexture(frame.commandBuffer, *destTexture); + MOBILEGL_ASSERT(dstClearReady, + "BlitFramebuffer: failed to materialize pending clear for destination textureId=%d", + destTexture->GetExternalIndex()); + } + } + VkImageLayout srcLayout = readIsDefaultFbo ? m_swapchainObject.GetImageLayout(m_imageIndexAcquired) : *srcBinding.trackedLayout; @@ -4683,6 +4711,15 @@ void main() { sourceTexture->GetExternalIndex()); } + { + // A clear queued for the destination predates this copy in API order; + // execute it now so the deferred materialization cannot stomp the copy. + const Bool dstClearReady = MaterializePendingClearForTexture(frame.commandBuffer, *destinationTexture); + MOBILEGL_ASSERT(dstClearReady, + "CopyTexSubImage2D: failed to materialize pending clear for destination textureId=%d", + destinationTexture->GetExternalIndex()); + } + const Bool srcUsesSwapchainDepth = readIsDefaultFbo && (srcBinding.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) == 0; const VkImageLayout srcOriginalLayout = readIsDefaultFbo ? (srcUsesSwapchainDepth