diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp index de5214fc..3269165c 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/ProgramFactory.cpp @@ -2094,7 +2094,15 @@ namespace MobileGL::MG_Backend::DirectVulkan { case SpvImageFormatR11fG11fB10f: return VK_FORMAT_B10G11R11_UFLOAT_PACK32; case SpvImageFormatR16f: return VK_FORMAT_R16_SFLOAT; case SpvImageFormatRgba16: return VK_FORMAT_R16G16B16A16_UNORM; - case SpvImageFormatRgb10A2: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + // A2**B**10G10R10, matching MGToVk::ConvertTextureInternalFormatToVkFormat's RGB10A2. + // This value becomes the storage image VIEW's format while the image itself was created + // from the texture's internal format, so the two must name the same bit layout or the + // shader reads the texel through a different component order than the host wrote it. + // GL_RGB10_A2 with GL_UNSIGNED_INT_2_10_10_10_REV puts R in bits 0-9, G in 10-19, B in + // 20-29 and A in 30-31, which is Vulkan's A2B10G10R10; A2R10G10B10 transposes R and B. + // KHR-GL43.shader_image_load_store.basic-allFormats-store read back [2,1,0,3] for an + // rgb10_a2ui image stored as [0,1,2,3] while these two converters disagreed. + case SpvImageFormatRgb10A2: return VK_FORMAT_A2B10G10R10_UNORM_PACK32; case SpvImageFormatRg16: return VK_FORMAT_R16G16_UNORM; case SpvImageFormatRg8: return VK_FORMAT_R8G8_UNORM; case SpvImageFormatR16: return VK_FORMAT_R16_UNORM; @@ -2117,7 +2125,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { case SpvImageFormatRgba16ui: return VK_FORMAT_R16G16B16A16_UINT; case SpvImageFormatRgba8ui: return VK_FORMAT_R8G8B8A8_UINT; case SpvImageFormatR32ui: return VK_FORMAT_R32_UINT; - case SpvImageFormatRgb10a2ui: return VK_FORMAT_A2R10G10B10_UINT_PACK32; + case SpvImageFormatRgb10a2ui: return VK_FORMAT_A2B10G10R10_UINT_PACK32; // see Rgb10A2 above case SpvImageFormatRg32ui: return VK_FORMAT_R32G32_UINT; case SpvImageFormatRg16ui: return VK_FORMAT_R16G16_UINT; case SpvImageFormatRg8ui: return VK_FORMAT_R8G8_UINT; diff --git a/MobileGL/MG_Test/SanityTest.cpp b/MobileGL/MG_Test/SanityTest.cpp index c0ea526e..3c6d100c 100644 --- a/MobileGL/MG_Test/SanityTest.cpp +++ b/MobileGL/MG_Test/SanityTest.cpp @@ -1374,7 +1374,10 @@ TEST(DirectVulkanSanity, SpirvStorageImageFormatsMapToVulkanFormats) { {SpvImageFormatR11fG11fB10f, VK_FORMAT_B10G11R11_UFLOAT_PACK32}, {SpvImageFormatR16f, VK_FORMAT_R16_SFLOAT}, {SpvImageFormatRgba16, VK_FORMAT_R16G16B16A16_UNORM}, - {SpvImageFormatRgb10A2, VK_FORMAT_A2R10G10B10_UNORM_PACK32}, + // A2**B**10G10R10, matching MGToVk::ConvertTextureInternalFormatToVkFormat's RGB10A2: + // the view format and the image format have to name the same bit layout, and + // GL_UNSIGNED_INT_2_10_10_10_REV is A2B10G10R10. A2R10G10B10 transposes R and B. + {SpvImageFormatRgb10A2, VK_FORMAT_A2B10G10R10_UNORM_PACK32}, {SpvImageFormatRg16, VK_FORMAT_R16G16_UNORM}, {SpvImageFormatRg8, VK_FORMAT_R8G8_UNORM}, {SpvImageFormatR16, VK_FORMAT_R16_UNORM}, @@ -1397,7 +1400,7 @@ TEST(DirectVulkanSanity, SpirvStorageImageFormatsMapToVulkanFormats) { {SpvImageFormatRgba16ui, VK_FORMAT_R16G16B16A16_UINT}, {SpvImageFormatRgba8ui, VK_FORMAT_R8G8B8A8_UINT}, {SpvImageFormatR32ui, VK_FORMAT_R32_UINT}, - {SpvImageFormatRgb10a2ui, VK_FORMAT_A2R10G10B10_UINT_PACK32}, + {SpvImageFormatRgb10a2ui, VK_FORMAT_A2B10G10R10_UINT_PACK32}, {SpvImageFormatRg32ui, VK_FORMAT_R32G32_UINT}, {SpvImageFormatRg16ui, VK_FORMAT_R16G16_UINT}, {SpvImageFormatRg8ui, VK_FORMAT_R8G8_UINT}, diff --git a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp index ab57de7f..c36069ec 100644 --- a/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp +++ b/MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp @@ -287,9 +287,17 @@ namespace MobileGL { case TexturePixelDataType::UnsignedInt8888Rev: return VK_FORMAT_R8G8B8A8_UINT; case TexturePixelDataType::UnsignedInt1010102: - return VK_FORMAT_A2R10G10B10_UINT_PACK32; + // GL_UNSIGNED_INT_10_10_10_2 is R in bits 22-31, G 12-21, B 2-11, A 0-1 - an + // R10G10B10A2 packing Vulkan has no format for at all. Reported as UNDEFINED + // rather than as the A2*10*10*10 neighbours below, which are a different + // packing: naming one of those would hand a caller a format whose components + // sit in the wrong bits. + return VK_FORMAT_UNDEFINED; case TexturePixelDataType::UnsignedInt2101010Rev: - return VK_FORMAT_A2R10G10B10_UINT_PACK32; + // A2**B**10G10R10, for the reason spelled out on + // ConvertTextureInternalFormatToVkFormat's RGB10A2: _REV puts R in bits 0-9, + // which is A2B10G10R10. A2R10G10B10 silently swaps R and B. + return VK_FORMAT_A2B10G10R10_UINT_PACK32; case TexturePixelDataType::UnsignedInt101111Rev: return VK_FORMAT_B10G11R11_UFLOAT_PACK32; case TexturePixelDataType::UnsignedInt5999Rev: