From eb76686c1e30070892d6fb1650835eeb49a1232a Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Fri, 31 Jul 2026 15:51:40 -0400 Subject: [PATCH] [Fix] (DirectVulkan): stop replaying consumed renderbuffer clears mid-pass A cached RenderPassEntry bakes renderbuffer clear payloads inline into its pendingClearAttachments, and that list outlives the clear's consumption at pass begin (loadOp CLEAR). Every subsequent draw that reused the entry while its pass was still active replayed the stale clear through vkCmdClearAttachments, wiping the color and depth of everything drawn so far in the pass. Texture-keyed clears already re-checked the clear manager before clearing; do the same for inline renderbuffer payloads: only clear while the renderbuffer clear is still actually pending, and take the live payload so a newer glClear's values win. On lavapipe this takes KHR-GL33.shaders.fragdepth.* from 0/18 to 18/18; the same defect hit any renderbuffer-FBO case with several draws per pass. --- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index a29ee72b..8938d266 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -9256,7 +9256,20 @@ void main() { ClearAttachmentPayload clearPayload{}; SharedPtr liveTexture; if (pending.hasInlinePayload) { - clearPayload = pending.inlinePayload; + // The inline payload is baked into the cached RenderPassEntry and outlives + // its consumption at pass begin (loadOp CLEAR). Replaying it here would + // wipe every draw already recorded in the pass, so only clear while the + // renderbuffer's clear is still actually pending, and take the live + // payload (a newer glClear may carry different values). + if (!m_renderPassManager->GetPendingRenderbufferClear(pending.renderbuffer, clearPayload)) { + continue; + } + if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0 && pending.renderbuffer != nullptr && + MG_Util::GetBaseInternalFormatComponentCount(pending.renderbuffer->GetInternalFormat()) == 3) { + // RGB renderbuffers are backed by an RGBA image; the missing alpha reads as 1. + clearPayload.color = FloatVec4(clearPayload.color.x(), clearPayload.color.y(), + clearPayload.color.z(), 1.0f); + } } else { if (!m_clearManager->GetPendingClear(pending.key, clearPayload, liveTexture)) { continue;