From 3d97f6fa8fabeeaf1f6c8b233d4a44ed52782962 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Tue, 4 Aug 2026 21:00:13 -0400 Subject: [PATCH] [Fix] (DirectVulkan): decline a draw with no usable fallback instead of aborting GetFallbackTexture asserted that the target was 2D or rectangle, so a sampler whose texture could not be resolved took the process down whenever it was any other kind. A multisample sampler reaches exactly that path: its texture is reported incomplete, the resolve falls back, and the assert fires. Sixty direct_state_access multisample cases died that way, and because the abort kills the whole process the harness lost the rest of its chunk with them -- one run needed 63 invocations to get through the suite instead of 3. The fallback is a single-sampled 2D image, so it genuinely cannot stand in for a multisample sampler: that descriptor demands a multisample view, and binding this one is invalid usage rather than a degraded picture. So report that no fallback exists and let the caller decline the draw. An unbound or incomplete sampler is an application-level mistake with a defined GL meaning; it is never a reason to abort. The cases still fail -- multisample textures are not yet complete enough to sample -- but they fail as one reported case each. --- .../DirectVulkan/Renderer/UniformManager.cpp | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp index 5d47bf7b..c2df6944 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp @@ -277,9 +277,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (texture == nullptr) { fallbackHolder = GetFallbackTexture(preferredTarget); texture = fallbackHolder.get(); - MOBILEGL_ASSERT(texture != nullptr, - "ResolveSamplerDescriptor: no fallback texture available for binding=%u location=%d unit=%d target=%d", - binding, location, unit, static_cast(preferredTarget)); + if (texture == nullptr) { + MGLOG_E("ResolveSamplerDescriptor: no fallback texture available for binding=%u ('%s') " + "location=%d unit=%d target=%d", + binding, programObj.samplerNameByBinding[binding].c_str(), location, unit, + static_cast(preferredTarget)); + return false; + } MGLOG_W( "ResolveSamplerDescriptor: using fallback texture for unbound sampler binding=%u ('%s') location=%d unit=%d target=%d", binding, programObj.samplerNameByBinding[binding].c_str(), location, unit, @@ -772,9 +776,16 @@ namespace MobileGL::MG_Backend::DirectVulkan { } SharedPtr UniformManager::GetFallbackTexture(TextureTarget target) const { - MOBILEGL_ASSERT(target == TextureTarget::Texture2D || target == TextureTarget::TextureRectangle, - "UniformManager::GetFallbackTexture: unsupported fallback target=%d", - static_cast(target)); + // The fallback is a single-sampled 2D image, so it can only stand in for a sampler that + // would accept one. A multisample sampler in particular cannot: its descriptor demands a + // multisample view, and handing it this one is invalid Vulkan, not a degraded picture. + // Report that there is no fallback and let the caller decline the draw - aborting the + // process over an unbound sampler is never the right answer. + if (target != TextureTarget::Texture2D && target != TextureTarget::TextureRectangle) { + MGLOG_E("UniformManager::GetFallbackTexture: no fallback exists for target=%d", + static_cast(target)); + return nullptr; + } if (m_fallbackTexture2D == nullptr) { auto fallbackTexture = MakeShared(kFallbackTexture2DExternalIndex);