diff --git a/GPU/Vulkan/StencilBufferVulkan.cpp b/GPU/Vulkan/StencilBufferVulkan.cpp index ebcec6c41e..6587069149 100644 --- a/GPU/Vulkan/StencilBufferVulkan.cpp +++ b/GPU/Vulkan/StencilBufferVulkan.cpp @@ -171,9 +171,8 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, StencilUp return false; if (dstBuffer->fbo) { - // Use keep because some drivers have trouble when stencilAction != depthAction. // Typically, STENCIL_IS_ZERO means it's already bound, so this bind will be optimized away. - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "Stencil"); + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }, "Stencil"); } else { // something is wrong... } diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 8290195a9b..474ed3a2f0 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -510,6 +510,23 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR VLOG("Empty render step. Usually happens after uploading pixels.."); } + // Older Mali drivers have issues with depth and stencil don't match load/clear/etc. + // TODO: Determine which versions and do this only where necessary. + u32 lateClearMask = 0; + if (depth != stencil && vulkan_->GetPhysicalDeviceProperties().properties.vendorID == VULKAN_VENDOR_ARM) { + if (stencil == VKRRenderPassAction::DONT_CARE) { + stencil = depth; + } else if (depth == VKRRenderPassAction::DONT_CARE) { + depth = stencil; + } else if (stencil == VKRRenderPassAction::CLEAR) { + depth = stencil; + lateClearMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } else if (depth == VKRRenderPassAction::CLEAR) { + stencil = depth; + lateClearMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + } + VKRStep *step = new VKRStep{ VKRStepType::RENDER }; step->render.framebuffer = fb; step->render.color = color; @@ -541,6 +558,16 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR curWidth_ = vulkan_->GetBackbufferWidth(); curHeight_ = vulkan_->GetBackbufferHeight(); } + + // See above - we add a clear afterward if only one side for depth/stencil CLEAR/KEEP. + if (lateClearMask != 0) { + VkRenderData data{ VKRRenderCommand::CLEAR }; + data.clear.clearColor = clearColor; + data.clear.clearZ = clearDepth; + data.clear.clearStencil = clearStencil; + data.clear.clearMask = lateClearMask; + curRenderStep_->commands.push_back(data); + } } bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) {