From b220c8baabcba82eb7e40ebdf0fe70e528bbf1ad Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 15 Dec 2025 14:16:36 +0800 Subject: [PATCH] [Feat] (MG_Impl/Texture): Decouple texture internal format and input format --- .../MG_Impl/GLImpl/Texture/GL_Texture.cpp | 50 +++++++++++-------- .../MG_Impl/GLImpl/Texture/Validators.cpp | 12 ++--- MobileGL/MG_Impl/GLImpl/Texture/Validators.h | 4 +- MobileGL/MG_Util/Metrics/TextureMetrics.cpp | 36 +++++++++++-- MobileGL/MG_Util/Metrics/TextureMetrics.h | 4 +- .../MG_Util/Texture/PixelStoreProcessor.cpp | 8 ++- .../MG_Util/Texture/PixelStoreProcessor.h | 5 +- 7 files changed, 77 insertions(+), 42 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index 35ac976f..90c566ba 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -51,7 +51,7 @@ namespace MobileGL { TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format); TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type); - TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(format); +// TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(format); // ===================== Error Checking ============================== if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return; @@ -60,10 +60,6 @@ namespace MobileGL { if (!TextureImpl::ValidateTextureLevelNumber(level)) return; if (!TextureImpl::ValidateTextureSizeWithTextureUploadTarget(textureUploadingTarget, width, height)) return; if (!TextureImpl::ValidateTextureSizeRange(width, height)) return; - if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return; - if (!TextureImpl::ValidateTextureFormatWithType(textureInputFormat, textureInternalFormat, - texturePixelDataType)) - return; if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadingTarget, level)) return; if (!pixels) return; @@ -79,10 +75,15 @@ namespace MobileGL { auto activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget); auto textureObject = bindingSlot.GetBoundObject(); + TextureInternalFormat textureInternalFormat = textureObject->GetFormat(); // ===================== Error Checking ============================== if (!TextureImpl::ValidateTextureObject(textureObject)) return; if (!TextureImpl::ValidateTextureSubImageOffsets(textureObject, xoffset, width, yoffset, height)) return; + if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(textureInputFormat, + textureInternalFormat, + texturePixelDataType)) + return; // ======================= Processing ================================ // Texture object here should always be an object with mipmap @@ -94,8 +95,7 @@ namespace MobileGL { auto textureMipmapObject = static_cast(textureObject.get()); auto texelSize = textureMipmapObject->GetMipmapTexelSize(textureUploadingTarget, level); - SizeT imageSize = 0; - const SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(textureInternalFormat, texturePixelDataType); + SizeT inputSize = 0; const void* originalPixels = pixels; @@ -110,18 +110,20 @@ namespace MobileGL { } void* processedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataUnpack( - originalPixels, MG_State::pGLContext->GetPixelStoreParameters(true), bytesPerPixel, {width, height, 1}, - false /*TODO*/, imageSize); + originalPixels, MG_State::pGLContext->GetPixelStoreParameters(true), textureInternalFormat, textureInputFormat, texturePixelDataType, {width, height, 1}, + false /*TODO*/, inputSize); - if (!processedPixels || imageSize == 0) { + if (!processedPixels || inputSize == 0) { MGLOG_E("TexSubImage2D_State: Failed to process pixel data for TexSubImage2D, width: %d, height: %d", width, height); if (processedPixels) free(processedPixels); return; } - const SizeT srcRowSize = width * bytesPerPixel; - const SizeT destRowSize = texelSize.x() * bytesPerPixel; + const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType); + + const SizeT srcRowSize = width * internalBpp; + const SizeT destRowSize = texelSize.x() * internalBpp; if (xoffset + width > static_cast(texelSize.x()) || yoffset + height > static_cast(texelSize.y())) { @@ -141,7 +143,7 @@ namespace MobileGL { // } for (GLsizei y = 0; y < height; y++) { - const SizeT destRowOffset = (yoffset + y) * destRowSize + xoffset * bytesPerPixel; + const SizeT destRowOffset = (yoffset + y) * destRowSize + xoffset * internalBpp; const SizeT srcRowOffset = y * srcRowSize; Memcpy(destData + destRowOffset, srcData + srcRowOffset, srcRowSize); } @@ -522,8 +524,9 @@ namespace MobileGL { if (!TextureImpl::ValidateTextureSizeRange(width, height)) return; if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return; if (!TextureImpl::ValidateTextureBorderNumber(border)) return; - if (!TextureImpl::ValidateTextureFormatWithType(textureInputFormat, textureInternalFormat, - texturePixelDataType)) + if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(textureInputFormat, + textureInternalFormat, + texturePixelDataType)) return; if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadingTarget, level)) return; @@ -555,8 +558,9 @@ namespace MobileGL { // ======================= Processing ================================ SizeT imageSize = 0; - const SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(textureInternalFormat, texturePixelDataType); - const SizeT totalBytes = width * height * bytesPerPixel; + const SizeT inputBpp = MG_Util::GetInputBytesPerPixel(textureInputFormat, texturePixelDataType); + const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType); + const SizeT internalBytes = width * height * internalBpp; textureObject->SetInternalFormat(textureInternalFormat); @@ -581,7 +585,7 @@ namespace MobileGL { // Allocate in TextureObject - textureMipmapObject->AllocateStorage(textureUploadingTarget, level, {{width, height, 1}, totalBytes}); + textureMipmapObject->AllocateStorage(textureUploadingTarget, level, {{width, height, 1}, internalBytes}); if (!originalPixels) { MGLOG_D("TexImage2D_State: No input pixel and no PBO bound, no pixel transfer"); @@ -590,17 +594,19 @@ namespace MobileGL { void* processedPixels = nullptr; processedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataUnpack( - originalPixels, MG_State::pGLContext->GetPixelStoreParameters(true), bytesPerPixel, {width, height, 1}, + originalPixels, MG_State::pGLContext->GetPixelStoreParameters(true), + textureInternalFormat, textureInputFormat, texturePixelDataType, + {width, height, 1}, false, imageSize); if (processedPixels && imageSize > 0) { - if (imageSize != totalBytes) { + if (imageSize != internalBytes) { MGLOG_W("TexImage2D_State: Processed pixel data size (%zu) does not match expected size (%zu). " "This may indicate an alignment or processing issue.", - imageSize, totalBytes); + imageSize, internalBytes); } - const SizeT copySize = std::min(imageSize, totalBytes); + const SizeT copySize = std::min(imageSize, internalBytes); DataPtr texelInput{processedPixels, copySize}; textureMipmapObject->UpdateMipmapSubData(textureUploadingTarget, level, texelInput); } diff --git a/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp b/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp index 8d40865a..2fec4b63 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/Validators.cpp @@ -162,15 +162,15 @@ namespace MobileGL::MG_Impl::GLImpl { } return true; } - Bool ValidateTextureFormatWithType(TextureInputFormat format, TextureInternalFormat internalFormat, - TexturePixelDataType type) { + Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format, TextureInternalFormat internalFormat, + TexturePixelDataType type) { if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev || type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev || type == TexturePixelDataType::UnsignedInt101111Rev) { if (format != TextureInputFormat::RGB) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, - MakeShared("MG_Impl/GLImpl", "ValidateTextureFormatWithType", + MakeShared("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", "Invalid format for the given type")); return false; } @@ -185,7 +185,7 @@ namespace MobileGL::MG_Impl::GLImpl { if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, - MakeShared("MG_Impl/GLImpl", "ValidateTextureFormatWithType", + MakeShared("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", "Invalid format for the given type")); return false; } @@ -198,7 +198,7 @@ namespace MobileGL::MG_Impl::GLImpl { if (format != TextureInputFormat::DepthComponent) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, - MakeShared("MG_Impl/GLImpl", "ValidateTextureFormatWithType", + MakeShared("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", "Invalid format for depth component internal format")); return false; } @@ -213,7 +213,7 @@ namespace MobileGL::MG_Impl::GLImpl { )) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, - MakeShared("MG_Impl/GLImpl", "ValidateTextureFormatWithType", + MakeShared("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput", "Invalid internal format for depth component format")); return false; } diff --git a/MobileGL/MG_Impl/GLImpl/Texture/Validators.h b/MobileGL/MG_Impl/GLImpl/Texture/Validators.h index 18354fd5..77da8b9a 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/Validators.h +++ b/MobileGL/MG_Impl/GLImpl/Texture/Validators.h @@ -15,8 +15,8 @@ namespace MobileGL::MG_Impl::GLImpl { Bool ValidateTextureSizeRange(SizeT width, SizeT height); Bool ValidateTextureInternalFormat(TextureInternalFormat format); Bool ValidateTextureBorderNumber(Int border); - Bool ValidateTextureFormatWithType(TextureInputFormat format, TextureInternalFormat internalFormat, - TexturePixelDataType type); + Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format, TextureInternalFormat internalFormat, + TexturePixelDataType type); Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level); Bool ValidateTextureObject(SharedPtr textureObject); Bool ValidateTextureTargetUniformity(SharedPtr textureObject, diff --git a/MobileGL/MG_Util/Metrics/TextureMetrics.cpp b/MobileGL/MG_Util/Metrics/TextureMetrics.cpp index 52d4b124..3f59fe02 100644 --- a/MobileGL/MG_Util/Metrics/TextureMetrics.cpp +++ b/MobileGL/MG_Util/Metrics/TextureMetrics.cpp @@ -85,6 +85,34 @@ namespace MobileGL { } } + SizeT GetBaseInputFormatComponentCount(TextureInputFormat format) { + switch (format) { + case TextureInputFormat::Red: + case TextureInputFormat::RInteger: + return 1; + case TextureInputFormat::RG: + case TextureInputFormat::RGInteger: + return 2; + case TextureInputFormat::RGB: + case TextureInputFormat::BGR: + case TextureInputFormat::RGBInteger: + case TextureInputFormat::BGRInteger: + return 3; + case TextureInputFormat::RGBA: + case TextureInputFormat::BGRA: + case TextureInputFormat::RGBAInteger: + case TextureInputFormat::BGRAInteger: + return 4; + case TextureInputFormat::StencilIndex: + case TextureInputFormat::DepthComponent: + case TextureInputFormat::DepthStencil: + return 1; + default: + MGLOG_D("%s: Unknown input format!", __func__); + return 0; + } + } + SizeT GetBaseInternalFormatComponentCount(TextureInternalFormat format) { switch (format) { case TextureInternalFormat::DepthComponent: @@ -208,17 +236,17 @@ namespace MobileGL { return chCount * bytesPerChannel; } - SizeT GetInputBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type) { + SizeT GetInputBytesPerPixel(TextureInputFormat inputFormat, TexturePixelDataType type) { SizeT sizedPixelFormatSize = GetSizedTexturePixelDataTypeSize(type); if (sizedPixelFormatSize > 0) return sizedPixelFormatSize; SizeT bytesPerChannel = GetBaseTexturePixelDataTypeSize(type); - SizeT chCount = GetBaseInternalFormatComponentCount(internalformat); + SizeT chCount = GetBaseInputFormatComponentCount(inputFormat); return chCount * bytesPerChannel; } - SizeT CalculateInputTextureImageSize(TextureInternalFormat internalFormat, TexturePixelDataType pixelDataType, + SizeT CalculateInputTextureImageSize(TextureInputFormat inputFormat, TexturePixelDataType pixelDataType, IntVec3 size) { - return GetInputBytesPerPixel(internalFormat, pixelDataType) * size.x() * size.y() * size.z(); + return GetInputBytesPerPixel(inputFormat, pixelDataType) * size.x() * size.y() * size.z(); } ComponentSizes GetComponentSizesForInternalFormat(TextureInternalFormat internal) { diff --git a/MobileGL/MG_Util/Metrics/TextureMetrics.h b/MobileGL/MG_Util/Metrics/TextureMetrics.h index 212a984a..7ad01ffd 100644 --- a/MobileGL/MG_Util/Metrics/TextureMetrics.h +++ b/MobileGL/MG_Util/Metrics/TextureMetrics.h @@ -11,8 +11,8 @@ namespace MobileGL { // This should respect internal format more SizeT GetInternalBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type); // This should respect type more, representing data passed in - SizeT GetInputBytesPerPixel(TextureInternalFormat internalformat, TexturePixelDataType type); - SizeT CalculateInputTextureImageSize(TextureInternalFormat internalFormat, TexturePixelDataType pixelDataType, + SizeT GetInputBytesPerPixel(TextureInputFormat inputFormat, TexturePixelDataType type); + SizeT CalculateInputTextureImageSize(TextureInputFormat inputFormat, TexturePixelDataType pixelDataType, IntVec3 size); ComponentSizes GetComponentSizesForInternalFormat(TextureInternalFormat internal); } // namespace MG_Util diff --git a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp index 7758cb17..775c853a 100644 --- a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp +++ b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp @@ -43,12 +43,10 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { } } - void* ProcessTexturePixelsDataUnpack(const void* inputPixels, const PixelStoreParameters& params, SizeT pixelSize, + void* ProcessTexturePixelsDataUnpack(const void* inputPixels, const PixelStoreParameters& params, + TextureInternalFormat targetInternalFormat, TextureInputFormat textureInputFormat, TexturePixelDataType inputDataType, IntVec3 dimension, Bool isBitmap, SizeT& outSize) { - if (pixelSize == 0) { - outSize = 0; - return nullptr; - } + const SizeT pixelSize = MG_Util::GetInputBytesPerPixel(textureInputFormat, inputDataType); Int width = dimension.x(); Int height = dimension.y(); diff --git a/MobileGL/MG_Util/Texture/PixelStoreProcessor.h b/MobileGL/MG_Util/Texture/PixelStoreProcessor.h index 84a36a5f..b5eb77f6 100644 --- a/MobileGL/MG_Util/Texture/PixelStoreProcessor.h +++ b/MobileGL/MG_Util/Texture/PixelStoreProcessor.h @@ -1,9 +1,12 @@ #pragma once #include #include +#include "MG_State/GLState/TextureState/TextureEnum.h" +#include "MG_Util/Metrics/TextureMetrics.h" namespace MobileGL::MG_Util::PixelStoreProcessor { - void* ProcessTexturePixelsDataUnpack(const void* inputPixels, const PixelStoreParameters& params, SizeT pixelSize, + void* ProcessTexturePixelsDataUnpack(const void* inputPixels, const PixelStoreParameters& params, + TextureInternalFormat targetInternalFormat, TextureInputFormat textureInputFormat, TexturePixelDataType inputDataType, IntVec3 dimension, Bool isBitmap, SizeT& outSize); void* ProcessTexturePixelsDataPack(const void* inputPixels, const PixelStoreParameters& params, SizeT pixelSize, IntVec3 dimension, Bool isBitmap, SizeT& outSize);