[Feat] (MG_Impl/Texture): Decouple texture internal format and input format

This commit is contained in:
2025-12-15 14:16:36 +08:00
parent 02a2f4af4a
commit b220c8baab
7 changed files with 77 additions and 42 deletions
+28 -22
View File
@@ -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<MG_State::GLState::TextureObjectMipmap*>(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<GLsizei>(texelSize.x()) ||
yoffset + height > static_cast<GLsizei>(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);
}
@@ -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<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureFormatWithType",
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureFormatWithType",
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureFormatWithType",
MakeShared<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureFormatWithType",
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
"Invalid internal format for depth component format"));
return false;
}
+2 -2
View File
@@ -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<MG_State::GLState::ITextureObject> textureObject);
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
+32 -4
View File
@@ -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) {
+2 -2
View File
@@ -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
@@ -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();
@@ -1,9 +1,12 @@
#pragma once
#include <Includes.h>
#include <MG_State/GLState/RenderState/RenderState.h>
#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);