From 7e048fc2bffb878d340d2288d21306a3c1af23c9 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 26 Jul 2026 19:13:46 -0400 Subject: [PATCH] [Fix] (DirectVulkan): map RGB10_A2(UI) to A2B10G10R10 - GL 2_10_10_10_REV puts R in bits 0-9 so the A2R10G10B10 mapping silently swapped R/B on upload; also decode both 1010102 variants in readback --- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 21 ++++++++++++++++++- .../MGToVk/TextureEnumConverter.cpp | 6 ++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 14a2c5cc..21285259 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -1951,6 +1951,8 @@ void main() { // --- packed / special --- case VK_FORMAT_A2B10G10R10_UNORM_PACK32: case VK_FORMAT_A2B10G10R10_UINT_PACK32: + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + case VK_FORMAT_A2R10G10B10_UINT_PACK32: case VK_FORMAT_B10G11R11_UFLOAT_PACK32: case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: case VK_FORMAT_R5G6B5_UNORM_PACK16: @@ -1960,7 +1962,8 @@ void main() { case VK_FORMAT_B5G5R5A1_UNORM_PACK16: case VK_FORMAT_R4G4B4A4_UNORM_PACK16: case VK_FORMAT_B4G4R4A4_UNORM_PACK16: - out.sourceClass = format == VK_FORMAT_A2B10G10R10_UINT_PACK32 ? + out.sourceClass = (format == VK_FORMAT_A2B10G10R10_UINT_PACK32 || + format == VK_FORMAT_A2R10G10B10_UINT_PACK32) ? ReadbackSourceClass::UnsignedInt : ReadbackSourceClass::Float; out.special = format; return true; @@ -2036,6 +2039,15 @@ void main() { rgba[3] = static_cast((word >> 30) & 0x3u) / 3.0f; return; } + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: { + Uint32 word = 0; + Memcpy(&word, source, sizeof(word)); + rgba[2] = static_cast(word & 0x3FFu) / 1023.0f; + rgba[1] = static_cast((word >> 10) & 0x3FFu) / 1023.0f; + rgba[0] = static_cast((word >> 20) & 0x3FFu) / 1023.0f; + rgba[3] = static_cast((word >> 30) & 0x3u) / 3.0f; + return; + } case VK_FORMAT_B10G11R11_UFLOAT_PACK32: { Uint32 word = 0; Memcpy(&word, source, sizeof(word)); @@ -2187,6 +2199,13 @@ void main() { rgba[1] = (word >> 10) & 0x3FFu; rgba[2] = (word >> 20) & 0x3FFu; rgba[3] = (word >> 30) & 0x3u; + } else if (srcFormat == VK_FORMAT_A2R10G10B10_UINT_PACK32) { + Uint32 word = 0; + Memcpy(&word, source, sizeof(word)); + rgba[2] = word & 0x3FFu; + rgba[1] = (word >> 10) & 0x3FFu; + rgba[0] = (word >> 20) & 0x3FFu; + rgba[3] = (word >> 30) & 0x3u; } else { for (Int c = 0; c < desc.channels; ++c) { if (desc.componentBits == 8) { diff --git a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp index 66e45902..7a7041fb 100644 --- a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp @@ -133,9 +133,11 @@ namespace MobileGL { case TextureInternalFormat::RGBA8Snorm: return VK_FORMAT_R8G8B8A8_SNORM; case TextureInternalFormat::RGB10A2: - return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + // GL_UNSIGNED_INT_2_10_10_10_REV puts R in bits 0-9, which is Vulkan's + // A2B10G10R10 layout - A2R10G10B10 silently swaps R and B on upload. + return VK_FORMAT_A2B10G10R10_UNORM_PACK32; case TextureInternalFormat::RGB10A2UI: - return VK_FORMAT_A2R10G10B10_UINT_PACK32; + return VK_FORMAT_A2B10G10R10_UINT_PACK32; case TextureInternalFormat::RGBA16: return VK_FORMAT_R16G16B16A16_UNORM; case TextureInternalFormat::RGBA16Snorm: