From 04b4627c657c15bf220e820858e524686990d538 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 20 Jul 2026 01:38:11 -0400 Subject: [PATCH] [Fix] (DirectVulkan): pass depth/stencil formats through sampled-view resolution so D24S8/D32FS8 samplers stop dropping draws, and memoize per-binding view-format resolution --- .../DirectVulkan/Renderer/UniformManager.cpp | 25 ++++++++++++++++--- .../DirectVulkan/Renderer/UniformManager.h | 7 ++++++ .../Renderer/VkTextureManager.cpp | 9 +++++++ MobileGL/MG_Test/SanityTest.cpp | 20 ++++++++++++++- 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp index fa356319..f54aa155 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp @@ -298,8 +298,23 @@ namespace MobileGL::MG_Backend::DirectVulkan { // descriptor valid. const Bool forceNearestFiltering = numericDomain == SamplerNumericDomain::SignedInteger || numericDomain == SamplerNumericDomain::UnsignedInteger; - const VkFormat sampledViewFormat = - VkTextureManager::ResolveSampledImageViewFormat(resource->format, numericDomain); + SamplerResolveMemo* viewFormatMemo = + binding < m_samplerResolveMemo.size() ? &m_samplerResolveMemo[binding] : nullptr; + VkFormat sampledViewFormat; + if (viewFormatMemo != nullptr && viewFormatMemo->viewFormatValid && + viewFormatMemo->viewFormatSource == resource->format && + viewFormatMemo->viewFormatDomain == numericDomain) { + sampledViewFormat = viewFormatMemo->viewFormat; + } else { + sampledViewFormat = + VkTextureManager::ResolveSampledImageViewFormat(resource->format, numericDomain); + if (viewFormatMemo != nullptr) { + viewFormatMemo->viewFormatSource = resource->format; + viewFormatMemo->viewFormatDomain = numericDomain; + viewFormatMemo->viewFormat = sampledViewFormat; + viewFormatMemo->viewFormatValid = true; + } + } if (sampledViewFormat == VK_FORMAT_UNDEFINED) { MGLOG_E("ResolveSamplerDescriptor: no compatible sampled view for binding=%u ('%s') " "textureId=%d imageFormat=%d numericDomain=%d", @@ -307,8 +322,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { static_cast(resource->format), static_cast(numericDomain)); return false; } + // No reinterpretation requested: bind the depth-or-color aspect view the sync above + // already produced instead of re-entering GetOrCreateSampledImageView's sync path. const VkImageView sampledImageView = - m_textureManager->GetOrCreateSampledImageView(*texture, sampledViewFormat); + sampledViewFormat == resource->format + ? resource->sampledView + : m_textureManager->GetOrCreateSampledImageView(*texture, sampledViewFormat); if (sampledImageView == VK_NULL_HANDLE) { MGLOG_E("ResolveSamplerDescriptor: failed to resolve sampled view for binding=%u ('%s') " "textureId=%d imageFormat=%d viewFormat=%d numericDomain=%d", diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.h index b3d5c503..d7afe8c2 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.h @@ -176,6 +176,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { Uint16 textureParamsVersion = 0; Bool forceNearestFiltering = false; Bool valid = false; + // ResolveSampledImageViewFormat is pure in (image format, numeric domain), but a + // domain mismatch walks a ~184-entry format table. Memo the resolution per binding + // so a reinterpreted sampler pays that scan once, not once per draw. + VkFormat viewFormatSource = VK_FORMAT_UNDEFINED; + SamplerNumericDomain viewFormatDomain = SamplerNumericDomain::Unknown; + VkFormat viewFormat = VK_FORMAT_UNDEFINED; + Bool viewFormatValid = false; }; mutable Vector m_samplerResolveMemo; }; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index d737772c..78f6fddc 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -1921,6 +1921,15 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkFormat VkTextureManager::ResolveSampledImageViewFormat(VkFormat imageFormat, SamplerNumericDomain numericDomain) { + // Depth/stencil images always sample through the existing depth-aspect sampledView. + // Combined formats (D24S8, D32FS8) are multi-numeric, so vkuFormatIsSampledFloat is + // false for them by design, yet their depth aspect reads as float in every GL depth + // texture mode; Vulkan also forbids reinterpreting them through color-class views. + // Integer domains keep the same view (pre-reinterpretation behavior for stencil-index + // style access) rather than failing the draw. + if (vkuFormatIsDepthOrStencil(imageFormat)) { + return imageFormat; + } if (imageFormat == VK_FORMAT_UNDEFINED || numericDomain == SamplerNumericDomain::Unknown || FormatMatchesSamplerNumericDomain(imageFormat, numericDomain)) { return imageFormat; diff --git a/MobileGL/MG_Test/SanityTest.cpp b/MobileGL/MG_Test/SanityTest.cpp index 60b024ea..c93038aa 100644 --- a/MobileGL/MG_Test/SanityTest.cpp +++ b/MobileGL/MG_Test/SanityTest.cpp @@ -999,9 +999,27 @@ TEST(DirectVulkanSanity, SampledViewFormatMatchesSamplerNumericDomainWithoutChan EXPECT_EQ(VkTextureManager::ResolveSampledImageViewFormat( VK_FORMAT_B10G11R11_UFLOAT_PACK32, SamplerNumericDomain::UnsignedInteger), VK_FORMAT_UNDEFINED); + + // Depth/stencil formats never resolve through color-class reinterpretation; they pass + // through unchanged so the existing depth-aspect sampled view is used. Combined + // depth-stencil formats are multi-numeric (vkuFormatIsSampledFloat is false for them), + // so without the passthrough a plain sampler2D/sampler2DShadow on GL_DEPTH24_STENCIL8 + // would resolve to UNDEFINED and the draw would be dropped. + EXPECT_EQ(VkTextureManager::ResolveSampledImageViewFormat( + VK_FORMAT_D24_UNORM_S8_UINT, SamplerNumericDomain::Float), + VK_FORMAT_D24_UNORM_S8_UINT); + EXPECT_EQ(VkTextureManager::ResolveSampledImageViewFormat( + VK_FORMAT_D32_SFLOAT_S8_UINT, SamplerNumericDomain::Float), + VK_FORMAT_D32_SFLOAT_S8_UINT); + EXPECT_EQ(VkTextureManager::ResolveSampledImageViewFormat( + VK_FORMAT_D32_SFLOAT, SamplerNumericDomain::Float), + VK_FORMAT_D32_SFLOAT); + EXPECT_EQ(VkTextureManager::ResolveSampledImageViewFormat( + VK_FORMAT_D24_UNORM_S8_UINT, SamplerNumericDomain::UnsignedInteger), + VK_FORMAT_D24_UNORM_S8_UINT); EXPECT_EQ(VkTextureManager::ResolveSampledImageViewFormat( VK_FORMAT_D32_SFLOAT, SamplerNumericDomain::UnsignedInteger), - VK_FORMAT_UNDEFINED); + VK_FORMAT_D32_SFLOAT); EXPECT_TRUE(VkTextureManager::AreSampledImageViewFormatsCompatible( VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32_UINT));