From 18d19a9a8b38314e868b2834ec2567390efe9cb6 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 23 Jun 2026 07:37:25 +0800 Subject: [PATCH] [Fix]: fix Complementary - add a DirectGLES ANGLE fallback control for 8-bit SNORM texture formats - normalize SNORM8 textures to float storage so ANGLE can render Complementary intermediate framebuffers - reuse the normalized upload conversion path for SNORM8 and existing norm16 float fallbacks --- MobileGL/MG_Backend/DirectGLES/Managers.cpp | 55 ++++++++++++++----- MobileGL/MG_Backend/DirectGLES/Utils.cpp | 1 + .../Texture/TextureFormatProcessor.cpp | 32 +++++++++++ .../MG_Util/Texture/TextureFormatProcessor.h | 1 + 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 7c1b199f..44452aab 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -533,17 +533,21 @@ namespace MobileGL::MG_Backend::DirectGLES { GLint m_prevSkipImages = 0; }; - static Uint GetNorm16ComponentCount(TextureInternalFormat format) { + static Uint GetNormFallbackComponentCount(TextureInternalFormat format) { switch (format) { + case TextureInternalFormat::R8Snorm: case TextureInternalFormat::R16: case TextureInternalFormat::R16Snorm: return 1; + case TextureInternalFormat::RG8Snorm: case TextureInternalFormat::RG16: case TextureInternalFormat::RG16Snorm: return 2; + case TextureInternalFormat::RGB8Snorm: case TextureInternalFormat::RGB16: case TextureInternalFormat::RGB16Snorm: return 3; + case TextureInternalFormat::RGBA8Snorm: case TextureInternalFormat::RGBA16: case TextureInternalFormat::RGBA16Snorm: return 4; @@ -552,8 +556,12 @@ namespace MobileGL::MG_Backend::DirectGLES { } } - static Bool IsSnorm16Format(TextureInternalFormat format) { + static Bool IsSnormFallbackFormat(TextureInternalFormat format) { switch (format) { + case TextureInternalFormat::R8Snorm: + case TextureInternalFormat::RG8Snorm: + case TextureInternalFormat::RGB8Snorm: + case TextureInternalFormat::RGBA8Snorm: case TextureInternalFormat::R16Snorm: case TextureInternalFormat::RG16Snorm: case TextureInternalFormat::RGB16Snorm: @@ -564,13 +572,25 @@ namespace MobileGL::MG_Backend::DirectGLES { } } - static const void* PrepareNorm16FloatFallbackUpload(TextureInternalFormat format, - const IntVec3& texelSize, - const void* data, - SizeT byteSize, - GLenum uploadType, - Vector& convertedData) { - const Uint componentCount = GetNorm16ComponentCount(format); + static Bool IsNorm8FallbackFormat(TextureInternalFormat format) { + switch (format) { + case TextureInternalFormat::R8Snorm: + case TextureInternalFormat::RG8Snorm: + case TextureInternalFormat::RGB8Snorm: + case TextureInternalFormat::RGBA8Snorm: + return true; + default: + return false; + } + } + + static const void* PrepareNormFloatFallbackUpload(TextureInternalFormat format, + const IntVec3& texelSize, + const void* data, + SizeT byteSize, + GLenum uploadType, + Vector& convertedData) { + const Uint componentCount = GetNormFallbackComponentCount(format); if (componentCount == 0 || uploadType != GL_FLOAT || data == nullptr || byteSize == 0) { return data; } @@ -579,14 +599,21 @@ namespace MobileGL::MG_Backend::DirectGLES { static_cast(std::max(texelSize.y(), 0)) * static_cast(std::max(texelSize.z(), 0)); const SizeT componentTotal = texelCount * static_cast(componentCount); - const SizeT sourceComponentTotal = byteSize / sizeof(Uint16); + const SizeT sourceComponentSize = IsNorm8FallbackFormat(format) ? sizeof(Int8) : sizeof(Uint16); + const SizeT sourceComponentTotal = byteSize / sourceComponentSize; if (componentTotal == 0 || sourceComponentTotal == 0) { return nullptr; } convertedData.assign(componentTotal, 0.0f); const SizeT copyComponentTotal = std::min(componentTotal, sourceComponentTotal); - if (IsSnorm16Format(format)) { + if (IsNorm8FallbackFormat(format)) { + const Int8* src = static_cast(data); + constexpr Float invMaxSnorm8 = 1.0f / 127.0f; + for (SizeT i = 0; i < copyComponentTotal; ++i) { + convertedData[i] = std::max(static_cast(src[i]) * invMaxSnorm8, -1.0f); + } + } else if (IsSnormFallbackFormat(format)) { const Int16* src = static_cast(data); constexpr Float invMaxSnorm16 = 1.0f / 32767.0f; for (SizeT i = 0; i < copyComponentTotal; ++i) { @@ -695,7 +722,7 @@ namespace MobileGL::MG_Backend::DirectGLES { ? textureMipmapObject->MapMipmapData(uploadTarget, level) : nullptr; Vector convertedUploadData; - const void* uploadData = PrepareNorm16FloatFallbackUpload( + const void* uploadData = PrepareNormFloatFallbackUpload( textureMipmapObject->GetFormat(), levelTexelSize, pData, levelByteSize, glType, convertedUploadData); @@ -785,7 +812,7 @@ namespace MobileGL::MG_Backend::DirectGLES { ? textureMipmapObject->MapMipmapData(uploadTarget, level) : nullptr; Vector convertedUploadData; - const void* uploadData = PrepareNorm16FloatFallbackUpload( + const void* uploadData = PrepareNormFloatFallbackUpload( textureMipmapObject->GetFormat(), levelTexelSize, pData, levelByteSize, glType, convertedUploadData); MGLOG_D("%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, " @@ -889,7 +916,7 @@ namespace MobileGL::MG_Backend::DirectGLES { auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level); const void* mipData = textureMipmapObject->MapMipmapData(uploadTarget, level); Vector convertedUploadData; - const void* uploadData = PrepareNorm16FloatFallbackUpload( + const void* uploadData = PrepareNormFloatFallbackUpload( textureMipmapObject->GetFormat(), texelSize, mipData, byteSize, glType, convertedUploadData); switch (stateTextureObject->GetTarget()) { diff --git a/MobileGL/MG_Backend/DirectGLES/Utils.cpp b/MobileGL/MG_Backend/DirectGLES/Utils.cpp index 88c0e0ce..9f2fea81 100644 --- a/MobileGL/MG_Backend/DirectGLES/Utils.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Utils.cpp @@ -32,6 +32,7 @@ namespace MobileGL::MG_Backend::DirectGLES { if (g_GLESCapabilities.GLESRendererString.find("ANGLE") != String::npos) { options |= PixelFormatNormalizeOptionBit::NoRgb16; options |= PixelFormatNormalizeOptionBit::NoSnorm16; + options |= PixelFormatNormalizeOptionBit::NoSnorm8; } NormalizePixelFormat(MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat), options, outInternalFormat, outFormat, outType); diff --git a/MobileGL/MG_Util/Texture/TextureFormatProcessor.cpp b/MobileGL/MG_Util/Texture/TextureFormatProcessor.cpp index d1412004..ac7a9129 100644 --- a/MobileGL/MG_Util/Texture/TextureFormatProcessor.cpp +++ b/MobileGL/MG_Util/Texture/TextureFormatProcessor.cpp @@ -82,6 +82,34 @@ namespace MobileGL::MG_Util::TextureFormatProcessor { } *outInternalFormat = internalFormat; break; + case GL_RGBA8_SNORM: + if (options & PixelFormatNormalizeOptionBit::NoSnorm8) { + *outInternalFormat = GL_RGBA16F; + break; + } + *outInternalFormat = internalFormat; + break; + case GL_RGB8_SNORM: + if (options & PixelFormatNormalizeOptionBit::NoSnorm8) { + *outInternalFormat = GL_RGB16F; + break; + } + *outInternalFormat = internalFormat; + break; + case GL_RG8_SNORM: + if (options & PixelFormatNormalizeOptionBit::NoSnorm8) { + *outInternalFormat = GL_RG16F; + break; + } + *outInternalFormat = internalFormat; + break; + case GL_R8_SNORM: + if (options & PixelFormatNormalizeOptionBit::NoSnorm8) { + *outInternalFormat = GL_R16F; + break; + } + *outInternalFormat = internalFormat; + break; default: *outInternalFormat = internalFormat; break; @@ -296,6 +324,10 @@ namespace MobileGL::MG_Util::TextureFormatProcessor { case GL_RGB8_SNORM: case GL_RG8_SNORM: case GL_R8_SNORM: + if (options & PixelFormatNormalizeOptionBit::NoSnorm8) { + *outType = GL_FLOAT; + break; + } *outType = GL_BYTE; break; diff --git a/MobileGL/MG_Util/Texture/TextureFormatProcessor.h b/MobileGL/MG_Util/Texture/TextureFormatProcessor.h index 3ab5dbf4..8a23d1e2 100644 --- a/MobileGL/MG_Util/Texture/TextureFormatProcessor.h +++ b/MobileGL/MG_Util/Texture/TextureFormatProcessor.h @@ -14,6 +14,7 @@ namespace MobileGL { NoNorm16 = 1 << 0, NoSnorm16 = 1 << 1, NoRgb16 = 1 << 2, + NoSnorm8 = 1 << 3, None = 0, }; namespace MG_Util::TextureFormatProcessor {