mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Feat] (...): Handle pixel store correctly.
This commit is contained in:
@@ -6,10 +6,11 @@
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_Util/Metrics/TextureMetrics.h>
|
||||
#include <MG_State/GLState/ErrorState/Error.h>
|
||||
#include <MG_Util/Texture/PixelStoreProcessor.h>
|
||||
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
@@ -39,6 +40,7 @@ namespace MobileGL {
|
||||
texturePixelDataType))
|
||||
return;
|
||||
if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadingTarget, level)) return;
|
||||
if (!pixels) 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.
|
||||
@@ -58,44 +60,52 @@ namespace MobileGL {
|
||||
if (!TextureImpl::ValidateTextureSubImageOffsets(textureObject, xoffset, width, yoffset, height)) return;
|
||||
|
||||
// ======================= Processing ================================
|
||||
// SizeT imageSize =
|
||||
// MG_Util::CalculateInputTextureImageSize(textureInternalFormat,
|
||||
// texturePixelDataType,
|
||||
// {width, height, 1});
|
||||
auto& mipmap = textureObject->GetMipmap(level);
|
||||
Vector<Uint8>& data = mipmap.data;
|
||||
|
||||
SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(textureInternalFormat, texturePixelDataType);
|
||||
// SizeT rowStride = mipmap.size.x() * bytesPerPixel;
|
||||
SizeT imageSize = 0;
|
||||
const SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(textureInternalFormat, texturePixelDataType);
|
||||
|
||||
const Uint8* srcData = reinterpret_cast<const Uint8*>(pixels);
|
||||
if (!srcData) {
|
||||
void* processedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataUnpack(
|
||||
pixels, MG_State::pGLContext->GetPixelStoreParameters(true), bytesPerPixel, {width, height, 1},
|
||||
false /*TODO*/, imageSize);
|
||||
|
||||
if (!processedPixels || imageSize == 0) {
|
||||
MGLOG_E("TexSubImage2D_State: Failed to process pixel data for TexSubImage2D, width: %d, height: %d",
|
||||
width, height);
|
||||
if (processedPixels) free(processedPixels);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixels != nullptr) {
|
||||
auto rowsToSkip = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackSkipRows);
|
||||
auto pixelsToSkip = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackSkipPixels);
|
||||
const SizeT srcRowSize = width * bytesPerPixel;
|
||||
const SizeT destRowSize = mipmap.size.x() * bytesPerPixel;
|
||||
|
||||
srcData += (rowsToSkip * width + pixelsToSkip);
|
||||
if (xoffset + width > static_cast<GLsizei>(mipmap.size.x()) ||
|
||||
yoffset + height > static_cast<GLsizei>(mipmap.size.y())) {
|
||||
MGLOG_E("TexSubImage2D_State: Specified region exceeds texture dimensions, xoffset: %d, yoffset: %d, "
|
||||
"width: %d, height: %d, mipmap size: (%d, %d)",
|
||||
xoffset, yoffset, width, height, mipmap.size.x(), mipmap.size.y());
|
||||
free(processedPixels);
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLint row = 0; row < height; ++row) {
|
||||
SizeT dstOffset = ((yoffset + row) * mipmap.size.x() + xoffset) * bytesPerPixel;
|
||||
// Should take states from glPixelStorei/glPixelStoref into account
|
||||
SizeT srcOffset = row * width * bytesPerPixel;
|
||||
|
||||
if (dstOffset + width * bytesPerPixel <= data.size()) {
|
||||
Memcpy(data.data() + dstOffset, srcData + srcOffset, width * bytesPerPixel);
|
||||
} else {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Copy failed. Dest image does not have sufficient space."));
|
||||
break;
|
||||
}
|
||||
const auto* srcData = static_cast<const Uint8*>(processedPixels);
|
||||
Uint8* destData = data.data();
|
||||
if (!data.size()) {
|
||||
SizeT totalSize = mipmap.size.x() * mipmap.size.y() * bytesPerPixel;
|
||||
data.resize(totalSize);
|
||||
}
|
||||
|
||||
for (GLsizei y = 0; y < height; y++) {
|
||||
const SizeT destRowOffset = (yoffset + y) * destRowSize + xoffset * bytesPerPixel;
|
||||
const SizeT srcRowOffset = y * srcRowSize;
|
||||
MGLOG_I("memcpy params: dst: %p, src: %p, size: %zu", destData + destRowOffset, srcData + srcRowOffset,
|
||||
srcRowSize);
|
||||
Memcpy(destData + destRowOffset, srcData + srcRowOffset, srcRowSize);
|
||||
}
|
||||
|
||||
free(processedPixels);
|
||||
|
||||
mipmap.dirty = true;
|
||||
}
|
||||
|
||||
@@ -285,6 +295,20 @@ namespace MobileGL {
|
||||
|
||||
void TexImage2D_State(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
|
||||
GLint border, GLenum format, GLenum type, const void* pixels) {
|
||||
MGLOG_D(
|
||||
"TexImage2D_State called with target: %s, level: %d, internalformat: %s, width: %d, height: %d, "
|
||||
"border: %d, format: %s, type: %s, pixels: %p",
|
||||
MG_Util::ConvertTextureUploadTargetToString(MG_Util::ConvertGLEnumToTextureUploadTarget(target))
|
||||
.c_str(),
|
||||
level,
|
||||
MG_Util::ConvertTextureInternalFormatToString(
|
||||
MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat))
|
||||
.c_str(),
|
||||
width, height, border,
|
||||
MG_Util::ConvertTextureInputFormatToString(MG_Util::ConvertGLEnumToTextureInputFormat(format)).c_str(),
|
||||
MG_Util::ConvertTexturePixelDataTypeToString(MG_Util::ConvertGLEnumToTexturePixelDataType(type))
|
||||
.c_str(),
|
||||
pixels);
|
||||
// ======================= Converting ================================
|
||||
TextureUploadTarget textureUploadingTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||
TextureTarget textureTarget = MG_Util::ConvertTextureUploadTargetToTextureTarget(textureUploadingTarget);
|
||||
@@ -332,23 +356,50 @@ namespace MobileGL {
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||
|
||||
// ======================= Processing ================================
|
||||
SizeT imageSize = isProxy ? 0
|
||||
: MG_Util::CalculateInputTextureImageSize(
|
||||
textureInternalFormat, texturePixelDataType, {width, height, 1});
|
||||
|
||||
Uint8* skippedPixels = (Uint8*)pixels;
|
||||
if (pixels != nullptr) {
|
||||
auto rowsToSkip = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackSkipRows);
|
||||
auto pixelsToSkip = MG_State::pGLContext->GetPixelStoreParam(PixelStoreParam::UnpackSkipPixels);
|
||||
SizeT imageSize = 0;
|
||||
void* processedPixels = nullptr;
|
||||
const SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(textureInternalFormat, texturePixelDataType);
|
||||
const SizeT totalBytes = width * height * bytesPerPixel;
|
||||
|
||||
skippedPixels += (rowsToSkip * width + pixelsToSkip);
|
||||
if (pixels) {
|
||||
processedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataUnpack(
|
||||
pixels, MG_State::pGLContext->GetPixelStoreParameters(true), bytesPerPixel, {width, height, 1},
|
||||
false, imageSize);
|
||||
}
|
||||
|
||||
MG_State::GLState::MipmapLevelInput mipmap =
|
||||
MG_State::GLState::MipmapLevelInput({width, height, 1}, level, false, 0,
|
||||
{isProxy ? nullptr : malloc(totalBytes), isProxy ? 0 : totalBytes});
|
||||
|
||||
if (!isProxy && !mipmap.inputData.data) {
|
||||
MGLOG_E("TexImage2D_State: Failed to allocate memory for mipmap level data, size: %zu", totalBytes);
|
||||
if (processedPixels) free(processedPixels);
|
||||
processedPixels = nullptr;
|
||||
}
|
||||
|
||||
if (processedPixels && imageSize > 0 && !isProxy) {
|
||||
if (imageSize != totalBytes) {
|
||||
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);
|
||||
}
|
||||
|
||||
const SizeT copySize = std::min(imageSize, totalBytes);
|
||||
Memcpy(mipmap.inputData.data, processedPixels, copySize);
|
||||
free(processedPixels);
|
||||
} else if (pixels && !isProxy) {
|
||||
MGLOG_E("TexImage2D_State: Failed to process pixel data, initializing with original data.");
|
||||
Memcpy(mipmap.inputData.data, pixels, totalBytes);
|
||||
} else {
|
||||
if (mipmap.inputData.data) {
|
||||
free(mipmap.inputData.data);
|
||||
mipmap.inputData.data = nullptr;
|
||||
}
|
||||
}
|
||||
textureObject->SetInternalFormat(textureInternalFormat);
|
||||
MG_State::GLState::MipmapLevelInput mipmap = MG_State::GLState::MipmapLevelInput(
|
||||
{width, height, 1}, level, false, 0,
|
||||
{const_cast<void*>(isProxy ? (void*)skippedPixels : nullptr), imageSize});
|
||||
textureObject->SetMipmapLevel(mipmap);
|
||||
if (mipmap.inputData.data) free(mipmap.inputData.data);
|
||||
}
|
||||
|
||||
void TexImage1D_State(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border,
|
||||
|
||||
Reference in New Issue
Block a user