[Feat] (MG_Impl/Texture): Implement TexSubImage2D.

This commit is contained in:
BZLZHH
2025-08-25 15:21:08 +08:00
parent b92bc0b44a
commit 262e2be9cb
3 changed files with 104 additions and 3 deletions
+67 -2
View File
@@ -1,4 +1,5 @@
#include "GL_Texture.h"
#include "GL/glext.h"
#include "MG_State/GLState/TextureState/TextureObject.h"
#include "MG_Util/Types.h"
#include "Validators.h"
@@ -19,7 +20,71 @@ namespace MobileGL {
void TexSubImage2D_State(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
GLsizei height, GLenum format, GLenum type, const void* pixels) {
// TODO: implement
// ======================= Converting ================================
TextureUploadTarget textureUploadingTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
TextureTarget textureTarget = MG_Util::ConvertTextureUploadTargetToTextureTarget(textureUploadingTarget);
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(format);
// ===================== Error Checking ==============================
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return;
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadingTarget)) return;
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;
// TODO: GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the
// GL_PIXEL_UNPACK_BUFFER target and the buffer object's data store is currently mapped.
// GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to the
// GL_PIXEL_UNPACK_BUFFER target and the data would be unpacked from the buffer object such that the
// memory reads required would exceed the data store size. GL_INVALID_OPERATION is generated if a
// non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and data is not evenly
// divisible into the number of bytes needed to store in memory a datum indicated by type.
// ======================= Processing ================================
auto activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
auto textureObject = bindingSlot.GetBoundObject();
// ===================== Error Checking ==============================
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
if (!TextureImpl::ValidateTextureSubImageOffsets(textureObject, xoffset, width, yoffset, height)) return;
// ======================= Processing ================================
SizeT imageSize =
MG_Util::CalculateTextureImageSize(textureInternalFormat, texturePixelDataType, {width, height, 1});
auto& mipmap = textureObject->GetMipmap(level);
Vector<Uint8>& data = mipmap.data;
SizeT bytesPerPixel = MG_Util::GetTexturePixelSize(textureInternalFormat) *
MG_Util::GetTexturePixelDataTypeSize(texturePixelDataType);
SizeT rowStride = mipmap.size.x() * bytesPerPixel;
const Uint8* srcData = reinterpret_cast<const Uint8*>(pixels);
if (!srcData) {
return;
}
for (GLint row = 0; row < height; ++row) {
SizeT dstOffset = ((yoffset + row) * mipmap.size.x() + xoffset) * bytesPerPixel;
SizeT srcOffset = row * width * bytesPerPixel;
if (dstOffset + width * bytesPerPixel <= data.size()) {
Copy(reinterpret_cast<const Uint8*>(srcData + srcOffset),
reinterpret_cast<Uint8*>(&data[dstOffset]), width * bytesPerPixel);
} else {
return;
}
}
mipmap.dirty = true;
}
void TexSubImage1D_State(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type,
@@ -57,7 +122,7 @@ namespace MobileGL {
TextureTarget textureTarget = MG_Util::ConvertTextureUploadTargetToTextureTarget(textureUploadingTarget);
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(format);
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
// ===================== Error Checking ==============================
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
+35 -1
View File
@@ -229,6 +229,7 @@ namespace MobileGL::MG_Impl::GLImpl {
return false;
}
}
return true;
}
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject) {
@@ -238,7 +239,6 @@ namespace MobileGL::MG_Impl::GLImpl {
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null"));
return false;
}
return true;
}
@@ -255,5 +255,39 @@ namespace MobileGL::MG_Impl::GLImpl {
}
return true;
}
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
Int width, Int yoffset, Int height, Int zoffset, Int depth) {
auto baseSize = textureObject->GetBaseSize();
if (xoffset < 0 || (xoffset + width) > baseSize.x()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
"xoffset must be non-negative and (xoffset + width) must not exceed "
"the texture width."));
return false;
}
if (baseSize.y() == 0) return true;
if (yoffset < 0 || (yoffset + height) > baseSize.y()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
"yoffset must be non-negative and (yoffset + height) must not exceed "
"the texture height."));
return false;
}
if (baseSize.z() == 0) return true;
if (zoffset < 0 || (zoffset + depth) > baseSize.z()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
"zoffset must be non-negative and (zoffset + depth) must not exceed "
"the texture depth."));
return false;
}
return true;
}
} // namespace TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl
@@ -21,5 +21,7 @@ namespace MobileGL::MG_Impl::GLImpl {
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject);
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
TextureTarget target);
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
} // namespace TextureImpl
} // namespace MobileGL::MG_Impl::GLImpl