[Feat|Improvement] (...): (MG_State) Implement glPixelStorei. Optimize code.

This commit is contained in:
BZLZHH
2025-04-30 17:31:10 +08:00
parent e19df94ece
commit e644efbe81
12 changed files with 507 additions and 107 deletions
+2
View File
@@ -48,6 +48,8 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
# MG_GL/State # MG_GL/State
MG/MG_GL/State/Core/GLState.cpp MG/MG_GL/State/Core/GLState.cpp
MG/MG_GL/State/Common/CommonState.cpp
MG/MG_GL/State/Texture/TextureState.cpp MG/MG_GL/State/Texture/TextureState.cpp
# MG_GL/GLX # MG_GL/GLX
+30
View File
@@ -23,6 +23,36 @@ namespace MG_Constants {
inline const int LOG_LEVEL_FATAL = 0x0014; inline const int LOG_LEVEL_FATAL = 0x0014;
} }
namespace PixelStore {
static const std::unordered_map<GLenum, GLint> DEFAULT_VALUES_MAP = {
{GL_PACK_SWAP_BYTES, GL_FALSE},
{GL_PACK_LSB_FIRST, GL_FALSE},
{GL_PACK_ROW_LENGTH, 0},
{GL_PACK_IMAGE_HEIGHT, 0},
{GL_PACK_SKIP_ROWS, 0},
{GL_PACK_SKIP_PIXELS, 0},
{GL_PACK_SKIP_IMAGES, 0},
{GL_PACK_ALIGNMENT, 4},
{GL_UNPACK_SWAP_BYTES, GL_FALSE},
{GL_UNPACK_LSB_FIRST, GL_FALSE},
{GL_UNPACK_ROW_LENGTH, 0},
{GL_UNPACK_IMAGE_HEIGHT, 0},
{GL_UNPACK_SKIP_ROWS, 0},
{GL_UNPACK_SKIP_PIXELS,0},
{GL_UNPACK_SKIP_IMAGES,0},
{GL_UNPACK_ALIGNMENT, 4}
}; // OpenGL 3
static const std::unordered_set<GLenum> VALID_PARAM_NAMES = {
GL_PACK_SWAP_BYTES, GL_PACK_LSB_FIRST, GL_PACK_ROW_LENGTH, GL_PACK_IMAGE_HEIGHT,
GL_PACK_SKIP_ROWS, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_IMAGES, GL_PACK_ALIGNMENT,
GL_UNPACK_SWAP_BYTES, GL_UNPACK_LSB_FIRST, GL_UNPACK_ROW_LENGTH,
GL_UNPACK_IMAGE_HEIGHT,
GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_IMAGES,
GL_UNPACK_ALIGNMENT
}; // OpenGL 3
}
namespace Texture { namespace Texture {
inline const GLuint MAX_TEXTURE_UNITS = 80; inline const GLuint MAX_TEXTURE_UNITS = 80;
const GLsizei MAX_TEXTURE_SIZE = 32768; const GLsizei MAX_TEXTURE_SIZE = 32768;
+3
View File
@@ -38,6 +38,9 @@
#ifndef MOBILEGL_GLSTATE_H #ifndef MOBILEGL_GLSTATE_H
#include "MG_GL/State/Core/GLState.h" #include "MG_GL/State/Core/GLState.h"
#endif #endif
#ifndef MOBILEGL_COMMONSTATE_H
#include "MG_GL/State/Common/CommonState.h"
#endif
#ifndef MOBILEGL_TEXTURESTATE_H #ifndef MOBILEGL_TEXTURESTATE_H
#include "MG_GL/State/Texture/TextureState.h" #include "MG_GL/State/Texture/TextureState.h"
#endif #endif
+9
View File
@@ -16,4 +16,13 @@ namespace MG_GL::GL {
void Clear(GLbitfield mask) { void Clear(GLbitfield mask) {
} }
void PixelStorei(GLenum pname, GLint param) {
MG_Util::Debug::LogD("glPixelStorei, pname: %d, param: %d", pname, param);
GLenum result = MG_State::SetPixelStoreInt(pname,param);
if (result == GL_NO_ERROR)
return;
MG_State::SetError(result);
MG_Util::Debug::LogE("Error from MG State: %s", MG_Util::Debug::GLEnumToString(result));
}
} }
+1
View File
@@ -11,6 +11,7 @@ namespace MG_GL::GL {
void ClearDepth(::GLdouble depth); void ClearDepth(::GLdouble depth);
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void Clear(GLbitfield mask); void Clear(GLbitfield mask);
void PixelStorei(GLenum pname, GLint param);
} }
#endif //MOBILEGL_GL_COMMON_H #endif //MOBILEGL_GL_COMMON_H
+1 -1
View File
@@ -122,7 +122,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsShader, GLuint shader) DECLARE_GL_FUN
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsTexture, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsTexture, texture) DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsTexture, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsTexture, texture)
DECLARE_GL_FUNCTION_STUB_HEAD(void, LineWidth, GLfloat width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, LineWidth, width) DECLARE_GL_FUNCTION_STUB_HEAD(void, LineWidth, GLfloat width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, LineWidth, width)
DECLARE_GL_FUNCTION_STUB_HEAD(void, LinkProgram, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, LinkProgram, program) DECLARE_GL_FUNCTION_STUB_HEAD(void, LinkProgram, GLuint program) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, LinkProgram, program)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PixelStorei, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PixelStorei, pname,param) DECLARE_GL_FUNCTION_HEAD(void, PixelStorei, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PixelStorei, pname,param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffset, GLfloat factor, GLfloat units) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffset, factor,units) DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffset, GLfloat factor, GLfloat units) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffset, factor,units)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReadPixels, x,y,width,height,format,type,pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, ReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReadPixels, x,y,width,height,format,type,pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ReleaseShaderCompiler) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReleaseShaderCompiler) DECLARE_GL_FUNCTION_STUB_HEAD(void, ReleaseShaderCompiler) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ReleaseShaderCompiler)
+56
View File
@@ -0,0 +1,56 @@
//
// Created by BZLZHH on 2025/4/30.
//
#include "CommonState.h"
GLenum CommonState::SetPixelStoreInt(GLenum pname, GLint param) {
if (MG_Constants::PixelStore::VALID_PARAM_NAMES.find(pname) == MG_Constants::PixelStore::VALID_PARAM_NAMES.end()) {
return GL_INVALID_ENUM;
}
switch (pname) {
case GL_PACK_SWAP_BYTES:
case GL_PACK_LSB_FIRST:
case GL_UNPACK_SWAP_BYTES:
case GL_UNPACK_LSB_FIRST:
break;
case GL_PACK_ROW_LENGTH:
case GL_PACK_IMAGE_HEIGHT:
case GL_PACK_SKIP_ROWS:
case GL_PACK_SKIP_PIXELS:
case GL_PACK_SKIP_IMAGES:
case GL_UNPACK_ROW_LENGTH:
case GL_UNPACK_IMAGE_HEIGHT:
case GL_UNPACK_SKIP_ROWS:
case GL_UNPACK_SKIP_PIXELS:
case GL_UNPACK_SKIP_IMAGES:
if (param < 0) {
return GL_INVALID_VALUE;
}
break;
case GL_PACK_ALIGNMENT:
case GL_UNPACK_ALIGNMENT:
if (param != 1 && param != 2 && param != 4 && param != 8) {
return GL_INVALID_VALUE;
}
break;
default:
return GL_INVALID_ENUM;
}
pixelStoreParams[pname] = param;
return GL_NO_ERROR;
}
GLint CommonState::GetPixelStoreInt(GLenum pname) {
auto it = pixelStoreParams.find(pname);
if (it != pixelStoreParams.end()) {
return it->second;
}
auto defaultIt = MG_Constants::PixelStore::DEFAULT_VALUES_MAP.find(pname);
return (defaultIt != MG_Constants::PixelStore::DEFAULT_VALUES_MAP.end()) ? defaultIt->second : 0;
}
+20
View File
@@ -0,0 +1,20 @@
//
// Created by BZLZHH on 2025/4/30.
//
#ifndef MOBILEGL_COMMONSTATE_H
#define MOBILEGL_COMMONSTATE_H
#define MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
class CommonState {
private:
std::unordered_map<GLenum, GLint> pixelStoreParams;
public:
GLenum SetPixelStoreInt(GLenum pname, GLint param);
GLint GetPixelStoreInt(GLenum pname);
};
#endif //MOBILEGL_COMMONSTATE_H
+13 -1
View File
@@ -4,16 +4,19 @@
#include "GLState.h" #include "GLState.h"
TextureState* MG_State_T::textureState;
std::queue<GLenum> MG_State_T::glErrorQueue; std::queue<GLenum> MG_State_T::glErrorQueue;
TextureState* MG_State_T::textureState = nullptr;
CommonState* MG_State_T::commonState = nullptr;
namespace MG_State { namespace MG_State {
void Init() { void Init() {
MG_State_T::textureState = new TextureState(); MG_State_T::textureState = new TextureState();
MG_State_T::commonState = new CommonState();
} }
void Destroy() { void Destroy() {
delete MG_State_T::textureState; delete MG_State_T::textureState;
delete MG_State_T::commonState;
} }
void SetError(GLenum error) { void SetError(GLenum error) {
@@ -80,4 +83,13 @@ namespace MG_State {
GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params) { GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params) {
return MG_State_T::textureState->GetLevelPropertyIntVector(target, level, pname, params); return MG_State_T::textureState->GetLevelPropertyIntVector(target, level, pname, params);
} }
GLenum MG_State::SetPixelStoreInt(GLenum pname, GLint param) {
return MG_State_T::commonState->SetPixelStoreInt(pname, param);
}
GLint MG_State::GetPixelStoreInt(GLenum pname) {
return MG_State_T::commonState->GetPixelStoreInt(pname);
}
} }
+4
View File
@@ -10,6 +10,7 @@
struct MG_State_T { struct MG_State_T {
static std::queue<GLenum> glErrorQueue; static std::queue<GLenum> glErrorQueue;
static TextureState* textureState; static TextureState* textureState;
static CommonState* commonState;
}; };
namespace MG_State { namespace MG_State {
@@ -36,6 +37,9 @@ namespace MG_State {
GLenum DeleteTexture(GLuint texture); GLenum DeleteTexture(GLuint texture);
GLenum DeleteTextures(GLsizei n, const GLuint* textures); GLenum DeleteTextures(GLsizei n, const GLuint* textures);
GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params); GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
GLenum SetPixelStoreInt(GLenum pname, GLint param);
GLint GetPixelStoreInt(GLenum pname);
} }
+352 -100
View File
@@ -4,6 +4,10 @@
#include "TextureState.h" #include "TextureState.h"
// Re-Include Includes.h, cuz of the absence of GLState.h
#undef MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
// TextureObject // TextureObject
bool TextureObject::IsImmutable() const { bool TextureObject::IsImmutable() const {
@@ -33,10 +37,10 @@ TextureState::TextureState() {
MG_Util::Debug::LogD("MG_State: Texture: TextureState constructor, textureUnits=%zu", textureUnits.size()); MG_Util::Debug::LogD("MG_State: Texture: TextureState constructor, textureUnits=%zu", textureUnits.size());
} }
TextureState &TextureState::GetInstance() { GLint TextureState::GetUnpackParam(GLenum pname) {
static TextureState instance; GLint result = MG_State::GetPixelStoreInt(pname);
MG_Util::Debug::LogD("MG_State: Texture: GetInstance called"); MG_Util::Debug::LogD("MG_State: Texture: GetUnpackParam pname=0x%x, returns %d", pname, result);
return instance; return result;
} }
bool TextureState::IsTextureGenerated(GLuint texture) { bool TextureState::IsTextureGenerated(GLuint texture) {
@@ -172,6 +176,12 @@ GLenum TextureState::Bind(GLenum target, GLuint texture) {
size_t TextureState::CalculatePixelDataSize(GLenum format, GLenum type, GLsizei width, GLsizei height) { size_t TextureState::CalculatePixelDataSize(GLenum format, GLenum type, GLsizei width, GLsizei height) {
MG_Util::Debug::LogD("MG_State: Texture: CalculatePixelDataSize called format=0x%x, type=0x%x, width=%d, height=%d", format, type, width, height); MG_Util::Debug::LogD("MG_State: Texture: CalculatePixelDataSize called format=0x%x, type=0x%x, width=%d, height=%d", format, type, width, height);
// Unpack Param
GLint rowLength = TextureState::GetUnpackParam(GL_UNPACK_ROW_LENGTH);
GLint alignment = TextureState::GetUnpackParam(GL_UNPACK_ALIGNMENT);
GLsizei actualRowLength = (rowLength > 0) ? rowLength : width;
size_t bytesPerPixel = 0; size_t bytesPerPixel = 0;
switch (type) { switch (type) {
case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_3_3_2:
@@ -219,7 +229,11 @@ size_t TextureState::CalculatePixelDataSize(GLenum format, GLenum type, GLsizei
break; break;
} }
} }
size_t totalSize = static_cast<size_t>(width) * static_cast<size_t>(height) * bytesPerPixel;
size_t rowSize = actualRowLength * bytesPerPixel;
size_t alignedRowSize = (rowSize + (alignment - 1)) & ~(alignment - 1);
size_t totalSize = alignedRowSize * height;
MG_Util::Debug::LogD("MG_State: Texture: CalculatePixelDataSize returns %zu", totalSize); MG_Util::Debug::LogD("MG_State: Texture: CalculatePixelDataSize returns %zu", totalSize);
return totalSize; return totalSize;
} }
@@ -227,10 +241,12 @@ size_t TextureState::CalculatePixelDataSize(GLenum format, GLenum type, GLsizei
GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat, GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLsizei height, GLint border, GLenum format, GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, const void* data) { GLenum type, const void* data) {
MG_Util::Debug::LogD("MG_State: Texture: Upload2D called target=0x%x, level=%d, width=%d, height=%d", target, level, width, height); MG_Util::Debug::LogD("MG_State: Texture: Upload2D called target=0x%x, level=%d, width=%d, height=%d",
GLenum validity = CheckUploadingTexture2DValidity(target, level, internalFormat, width, height, border, format, type, data); target, level, width, height);
GLenum validity = CheckUploadingTexture2DValidity(target, level, internalFormat,
width, height, border, format, type, data);
if (validity != GL_NO_ERROR) { if (validity != GL_NO_ERROR) {
MG_Util::Debug::LogE("MG_State: Texture: Upload2D CheckUploadingTexture2DValidity failed with error 0x%x", validity); MG_Util::Debug::LogE("MG_State: Texture: Upload2D validation failed with error 0x%x", validity);
return validity; return validity;
} }
@@ -263,19 +279,56 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
mip.format = format; mip.format = format;
mip.type = type; mip.type = type;
if (data != nullptr) { if (data != nullptr) {
size_t dataSize = CalculatePixelDataSize(format, type, width, height); GLint unpackSwapBytes = GetUnpackParam(GL_UNPACK_SWAP_BYTES);
mip.pixelData.resize(dataSize); GLint unpackLSBFirst = GetUnpackParam(GL_UNPACK_LSB_FIRST);
memcpy(mip.pixelData.data(), data, dataSize); GLint unpackSkipPixels = GetUnpackParam(GL_UNPACK_SKIP_PIXELS);
GLint unpackSkipRows = GetUnpackParam(GL_UNPACK_SKIP_ROWS);
GLint unpackRowLength = GetUnpackParam(GL_UNPACK_ROW_LENGTH);
GLint unpackAlignment = GetUnpackParam(GL_UNPACK_ALIGNMENT);
GLint unpackImageHeight = GetUnpackParam(GL_UNPACK_IMAGE_HEIGHT);
GLint unpackSkipImages = GetUnpackParam(GL_UNPACK_SKIP_IMAGES);
GLsizei rowLength = (unpackRowLength > 0) ? unpackRowLength : width;
size_t bytesPerPixel = CalculateBytesPerPixel(format, type);
size_t componentSize = GetComponentSize(type);
size_t srcRowSize = rowLength * bytesPerPixel;
size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1);
size_t srcImageStride = (unpackImageHeight > 0) ?
srcRowStride * unpackImageHeight :
srcRowStride * height;
const GLubyte* srcData = static_cast<const GLubyte*>(data);
srcData += unpackSkipImages * srcImageStride;
srcData += unpackSkipRows * srcRowStride;
srcData += unpackSkipPixels * bytesPerPixel;
size_t dstRowStride = width * bytesPerPixel;
size_t dstSize = dstRowStride * height;
mip.pixelData.resize(dstSize);
GLubyte* dstData = mip.pixelData.data();
for (GLsizei y = 0; y < height; ++y) {
const GLubyte* srcRow = srcData + y * srcRowStride;
GLubyte* dstRow = dstData + y * dstRowStride;
if (unpackSwapBytes) {
SwapBytesForTexture(format, type, srcRow, dstRow, width);
}
else if (unpackLSBFirst && componentSize == 1) {
ReverseBitOrder(srcRow, dstRow, width * bytesPerPixel);
}
else {
memcpy(dstRow, srcRow, width * bytesPerPixel);
}
}
mip.hasData = true; mip.hasData = true;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D uploaded data size=%zu", dataSize); MG_Util::Debug::LogD("MG_State: Texture: Upload2D uploaded %zu bytes with unpack params", dstSize);
} else { } else {
mip.hasData = false; mip.hasData = false;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D data pointer is null"); MG_Util::Debug::LogD("MG_State: Texture: Upload2D data pointer is null");
} }
tex.data = data;
tex.params.mipmapData[level] = mip; tex.params.mipmapData[level] = mip;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D succeeded for level=%d", level);
return GL_NO_ERROR; return GL_NO_ERROR;
} }
@@ -285,114 +338,91 @@ GLenum TextureState::UpdateRegion2D(GLenum target, GLint level, GLint xoffset,
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D called target=0x%x, level=%d, x=%d, y=%d, w=%d, h=%d", MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D called target=0x%x, level=%d, x=%d, y=%d, w=%d, h=%d",
target, level, xoffset, yoffset, width, height); target, level, xoffset, yoffset, width, height);
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) { GLenum validity = CheckUpdatingTextureRegion2DValidity(target, level, xoffset, yoffset, width, height, format, type, data);
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D invalid target=0x%x", target); if (validity != GL_NO_ERROR) {
return GL_INVALID_ENUM; MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D validation failed with error 0x%x", validity);
} return validity;
if (level < 0) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D invalid level=%d", level);
return GL_INVALID_VALUE;
}
if (xoffset < 0 || yoffset < 0) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D negative offset x=%d, y=%d", xoffset, yoffset);
return GL_INVALID_VALUE;
}
if (width < 0 || height < 0) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D negative dimensions w=%d, h=%d", width, height);
return GL_INVALID_VALUE;
}
if (!data) {
// TODO: need to impl PBO and then impl here
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D data pointer is null");
return GL_INVALID_OPERATION ;
} }
GLuint boundTex = textureUnits[activeTextureUnit].GetBoundTexture(target); GLuint boundTex = textureUnits[activeTextureUnit].GetBoundTexture(target);
if (boundTex == 0) { auto& tex = textures[boundTex];
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D no texture bound for target=0x%x", target);
return GL_INVALID_OPERATION;
}
if (!IsTextureGenerated(boundTex)) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D texture %u not generated", boundTex);
return GL_INVALID_OPERATION;
}
auto tex = textures[boundTex];
if (tex.IsImmutable()) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D texture is immutable");
return GL_INVALID_OPERATION;
}
auto mipIt = tex.params.mipmapData.find(level); auto mipIt = tex.params.mipmapData.find(level);
if (mipIt == tex.params.mipmapData.end()) { if (mipIt == tex.params.mipmapData.end()) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D no mipmap level %d", level); MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D mipmap level %d not found", level);
return GL_INVALID_OPERATION; return GL_INVALID_OPERATION;
} }
TextureParams::MipmapLevel& mip = mipIt->second; TextureParams::MipmapLevel& mip = mipIt->second;
if (MG_Constants::Texture::VALID_FORMATS.find(format) == MG_Constants::Texture::VALID_FORMATS.end()) { GLint unpackSwapBytes = GetUnpackParam(GL_UNPACK_SWAP_BYTES);
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D invalid format=0x%x", format); GLint unpackLSBFirst = GetUnpackParam(GL_UNPACK_LSB_FIRST);
GLint unpackRowLength = GetUnpackParam(GL_UNPACK_ROW_LENGTH);
GLint unpackAlignment = GetUnpackParam(GL_UNPACK_ALIGNMENT);
GLint unpackSkipPixels = GetUnpackParam(GL_UNPACK_SKIP_PIXELS);
GLint unpackSkipRows = GetUnpackParam(GL_UNPACK_SKIP_ROWS);
GLint unpackImageHeight = GetUnpackParam(GL_UNPACK_IMAGE_HEIGHT);
GLint unpackSkipImages = GetUnpackParam(GL_UNPACK_SKIP_IMAGES);
const size_t bytesPerPixel = CalculateBytesPerPixel(format, type);
const size_t srcSize = CalculatePixelDataSize(format, type, width, height);
if (bytesPerPixel == 0) {
MG_Util::Debug::LogE("MG_State: Texture: Invalid format/type combination");
return GL_INVALID_ENUM; return GL_INVALID_ENUM;
} }
if (MG_Constants::Texture::VALID_TYPES.find(type) == MG_Constants::Texture::VALID_TYPES.end()) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D invalid type=0x%x", type);
return GL_INVALID_ENUM;
}
bool typeNeedsRGB = (type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV ||
type == GL_UNSIGNED_SHORT_5_6_5 || type == GL_UNSIGNED_SHORT_5_6_5_REV);
if (typeNeedsRGB && format != GL_RGB) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D type requires RGB format");
return GL_INVALID_OPERATION;
}
bool typeNeedsRGBA = (type == GL_UNSIGNED_SHORT_4_4_4_4 || type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
type == GL_UNSIGNED_SHORT_5_5_5_1 || type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
type == GL_UNSIGNED_INT_8_8_8_8 || type == GL_UNSIGNED_INT_8_8_8_8_REV ||
type == GL_UNSIGNED_INT_10_10_10_2 || type == GL_UNSIGNED_INT_2_10_10_10_REV);
if (typeNeedsRGBA && format != GL_RGBA && format != GL_BGRA) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D type requires RGBA/BGRA format");
return GL_INVALID_OPERATION;
}
if (xoffset + width > mip.width || yoffset + height > mip.height) { if (xoffset + width > mip.width || yoffset + height > mip.height) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D region out of bounds: " MG_Util::Debug::LogE("MG_State: Texture: Update region out of bounds");
"x=%d+%d > %d or y=%d+%d > %d",
xoffset, width, mip.width, yoffset, height, mip.height);
return GL_INVALID_VALUE; return GL_INVALID_VALUE;
} }
bool isDepthInternal = (mip.internalFormat == GL_DEPTH_COMPONENT || const GLsizei srcRowLength = (unpackRowLength > 0) ? unpackRowLength : width;
mip.internalFormat == GL_DEPTH_COMPONENT16 || const size_t srcRowSize = srcRowLength * bytesPerPixel;
mip.internalFormat == GL_DEPTH_COMPONENT24 || const size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1);
mip.internalFormat == GL_DEPTH_COMPONENT32F || const size_t srcImageStride = (unpackImageHeight > 0)
mip.internalFormat == GL_DEPTH_STENCIL || ? srcRowStride * unpackImageHeight
mip.internalFormat == GL_DEPTH24_STENCIL8 || : srcRowStride * height;
mip.internalFormat == GL_DEPTH32F_STENCIL8);
bool isDepthFormat = (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL); const GLubyte* srcData = static_cast<const GLubyte*>(data);
if (isDepthInternal != isDepthFormat) { srcData += unpackSkipImages * srcImageStride;
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D format mismatch with internal format"); srcData += unpackSkipRows * srcRowStride;
return GL_INVALID_OPERATION; srcData += unpackSkipPixels * bytesPerPixel;
const size_t requiredSrcSize = (height - 1) * srcRowStride + width * bytesPerPixel;
// TODO: Check the buffer data size.
const size_t dstRowStride = mip.width * bytesPerPixel;
if (mip.pixelData.empty())
mip.pixelData.resize(srcSize);
GLubyte* dstData = mip.pixelData.data() + yoffset * dstRowStride + xoffset * bytesPerPixel;
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D srcRowStride=%zu, dstRowStride=%zu", srcRowStride, dstRowStride);
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D srcData=%p, dstData=%p", srcData, dstData);
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D bytesPerPixel=%zu", bytesPerPixel);
for (GLsizei y = 0; y < height; ++y) {
const GLubyte* srcRow = srcData + y * srcRowStride;
GLubyte* dstRow = dstData + y * dstRowStride;
if (unpackSwapBytes) {
for (GLsizei x = 0; x < width; ++x) {
const GLubyte* srcPixel = srcRow + x * bytesPerPixel;
GLubyte* dstPixel = dstRow + x * bytesPerPixel;
SwapPixelBytes(format, type, srcPixel, dstPixel);
}
} else if (unpackLSBFirst && GetComponentSize(type) == 1) {
for (size_t i = 0; i < width * bytesPerPixel; ++i) {
dstRow[i] = ReverseBits(srcRow[i]);
}
} else {
memmove(dstRow, srcRow, width * bytesPerPixel);
}
} }
mip.hasData = true; mip.hasData = true;
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D validated subimage update"); MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D succeeded");
tex.data = data;
return GL_NO_ERROR; return GL_NO_ERROR;
} }
GLenum TextureState::SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloat param) { GLenum TextureState::SetTexturePropertyFloat(GLenum target, GLenum pname, GLfloat param) {
MG_Util::Debug::LogD("MG_State: Texture: SetTexturePropertyFloat called target=0x%x, pname=0x%x, param=%f", target, pname, param); MG_Util::Debug::LogD("MG_State: Texture: SetTexturePropertyFloat called target=0x%x, pname=0x%x, param=%f", target, pname, param);
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) { if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
@@ -818,6 +848,113 @@ GLenum TextureState::CheckUploadingTexture2DValidity(GLenum target, GLint level,
return GL_NO_ERROR; return GL_NO_ERROR;
} }
GLenum TextureState::CheckUpdatingTextureRegion2DValidity(GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLsizei width, GLsizei height, GLenum format,
GLenum type, const GLvoid* data) {
MG_Util::Debug::LogD("MG_State: Texture: CheckUpdatingTextureRegion2DValidity called target=0x%x, level=%d, x=%d, y=%d, w=%d, h=%d",
target, level, xoffset, yoffset, width, height);
if (MG_Constants::Texture::VALID_TARGETS.find(target) == MG_Constants::Texture::VALID_TARGETS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity invalid target=0x%x", target);
return GL_INVALID_ENUM;
}
if (level < 0) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity invalid level=%d", level);
return GL_INVALID_VALUE;
}
if (xoffset < 0 || yoffset < 0) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity negative offset x=%d, y=%d", xoffset, yoffset);
return GL_INVALID_VALUE;
}
if (width < 0 || height < 0) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity negative dimensions w=%d, h=%d", width, height);
return GL_INVALID_VALUE;
}
if (!data) {
// TODO: need to impl PBO and then impl here
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity data pointer is null");
return GL_INVALID_OPERATION ;
}
GLuint boundTex = textureUnits[activeTextureUnit].GetBoundTexture(target);
if (boundTex == 0) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity no texture bound for target=0x%x", target);
return GL_INVALID_OPERATION;
}
if (!IsTextureGenerated(boundTex)) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity texture %u not generated", boundTex);
return GL_INVALID_OPERATION;
}
auto tex = textures[boundTex];
if (tex.IsImmutable()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity texture is immutable");
return GL_INVALID_OPERATION;
}
auto mipIt = tex.params.mipmapData.find(level);
if (mipIt == tex.params.mipmapData.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity no mipmap level %d", level);
return GL_INVALID_OPERATION;
}
if (MG_Constants::Texture::VALID_FORMATS.find(format) == MG_Constants::Texture::VALID_FORMATS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity invalid format=0x%x", format);
return GL_INVALID_ENUM;
}
if (MG_Constants::Texture::VALID_TYPES.find(type) == MG_Constants::Texture::VALID_TYPES.end()) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity invalid type=0x%x", type);
return GL_INVALID_ENUM;
}
bool typeNeedsRGB = (type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV ||
type == GL_UNSIGNED_SHORT_5_6_5 || type == GL_UNSIGNED_SHORT_5_6_5_REV);
if (typeNeedsRGB && format != GL_RGB) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity type requires RGB format");
return GL_INVALID_OPERATION;
}
bool typeNeedsRGBA = (type == GL_UNSIGNED_SHORT_4_4_4_4 || type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
type == GL_UNSIGNED_SHORT_5_5_5_1 || type == GL_UNSIGNED_SHORT_1_5_5_5_REV ||
type == GL_UNSIGNED_INT_8_8_8_8 || type == GL_UNSIGNED_INT_8_8_8_8_REV ||
type == GL_UNSIGNED_INT_10_10_10_2 || type == GL_UNSIGNED_INT_2_10_10_10_REV);
if (typeNeedsRGBA && format != GL_RGBA && format != GL_BGRA) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity type requires RGBA/BGRA format");
return GL_INVALID_OPERATION;
}
TextureParams::MipmapLevel& mip = mipIt->second;
if (xoffset + width > mip.width || yoffset + height > mip.height) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity region out of bounds: "
"x=%d+%d > %d or y=%d+%d > %d",
xoffset, width, mip.width, yoffset, height, mip.height);
return GL_INVALID_VALUE;
}
bool isDepthInternal = (mip.internalFormat == GL_DEPTH_COMPONENT ||
mip.internalFormat == GL_DEPTH_COMPONENT16 ||
mip.internalFormat == GL_DEPTH_COMPONENT24 ||
mip.internalFormat == GL_DEPTH_COMPONENT32F ||
mip.internalFormat == GL_DEPTH_STENCIL ||
mip.internalFormat == GL_DEPTH24_STENCIL8 ||
mip.internalFormat == GL_DEPTH32F_STENCIL8);
bool isDepthFormat = (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL);
if (isDepthInternal != isDepthFormat) {
MG_Util::Debug::LogE("MG_State: Texture: CheckUpdatingTextureRegion2DValidity format mismatch with internal format");
return GL_INVALID_OPERATION;
}
MG_Util::Debug::LogD("MG_State: Texture: CheckUpdatingTextureRegion2DValidity validated subimage update");
return GL_NO_ERROR;
}
ComponentSizes TextureState::GetComponentSizes(GLenum internalFormat) { ComponentSizes TextureState::GetComponentSizes(GLenum internalFormat) {
MG_Util::Debug::LogD("MG_State: Texture: GetComponentSizes called for internalFormat=0x%x", internalFormat); MG_Util::Debug::LogD("MG_State: Texture: GetComponentSizes called for internalFormat=0x%x", internalFormat);
ComponentSizes sizes = {0}; ComponentSizes sizes = {0};
@@ -935,3 +1072,118 @@ ComponentSizes TextureState::GetComponentSizes(GLenum internalFormat) {
sizes.red, sizes.green, sizes.blue, sizes.alpha, sizes.depth, sizes.stencil, sizes.isCompressed); sizes.red, sizes.green, sizes.blue, sizes.alpha, sizes.depth, sizes.stencil, sizes.isCompressed);
return sizes; return sizes;
} }
size_t TextureState::CalculateBytesPerPixel(GLenum format, GLenum type) {
switch (type) {
case GL_UNSIGNED_BYTE_3_3_2:
case GL_UNSIGNED_BYTE_2_3_3_REV:
return 1;
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_5_6_5_REV:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_4_4_4_4_REV:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_UNSIGNED_SHORT_1_5_5_5_REV:
return 2;
case GL_UNSIGNED_INT_8_8_8_8:
case GL_UNSIGNED_INT_8_8_8_8_REV:
case GL_UNSIGNED_INT_10_10_10_2:
case GL_UNSIGNED_INT_2_10_10_10_REV:
return 4;
default:
break;
}
int components = 0;
switch (format) {
case GL_RED:
case GL_DEPTH_COMPONENT:
components = 1;
break;
case GL_RG:
case GL_DEPTH_STENCIL:
components = 2;
break;
case GL_RGB:
case GL_BGR:
components = 3;
break;
case GL_RGBA:
case GL_BGRA:
components = 4;
break;
default:
components = 0;
break;
}
size_t componentSize = GetComponentSize(type);
return components * componentSize;
}
size_t TextureState::GetComponentSize(GLenum type) {
switch (type) {
case GL_BYTE:
case GL_UNSIGNED_BYTE:
return 1;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_HALF_FLOAT:
return 2;
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
return 4;
case GL_UNSIGNED_BYTE_3_3_2:
case GL_UNSIGNED_BYTE_2_3_3_REV:
return 1;
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_5_6_5_REV:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_4_4_4_4_REV:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_UNSIGNED_SHORT_1_5_5_5_REV:
return 2;
case GL_UNSIGNED_INT_8_8_8_8:
case GL_UNSIGNED_INT_8_8_8_8_REV:
case GL_UNSIGNED_INT_10_10_10_2:
case GL_UNSIGNED_INT_2_10_10_10_REV:
return 4;
default:
return 0;
}
}
void TextureState::SwapBytesForTexture(GLenum format, GLenum type, const GLubyte* src, GLubyte* dst, GLsizei width) {
size_t componentSize = GetComponentSize(type);
if (componentSize <= 1) {
memcpy(dst, src, width * componentSize);
return;
}
for (GLsizei i = 0; i < width; ++i) {
for (size_t j = 0; j < componentSize; ++j) {
dst[i * componentSize + j] = src[i * componentSize + (componentSize - 1 - j)];
}
}
}
GLubyte TextureState::ReverseBits(GLubyte b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
void TextureState::ReverseBitOrder(const GLubyte* src, GLubyte* dst, size_t byteCount) {
for (size_t i = 0; i < byteCount; ++i) {
dst[i] = ReverseBits(src[i]);
}
}
void TextureState::SwapPixelBytes(GLenum format, GLenum type, const GLubyte* src, GLubyte* dst) {
const size_t size = GetComponentSize(type);
for (size_t i = 0; i < size; ++i) {
dst[i] = src[size - 1 - i];
}
}
+14 -3
View File
@@ -40,7 +40,7 @@ public:
TextureParams params; TextureParams params;
const void* data = nullptr; const void* data = nullptr;
bool IsImmutable() const; bool IsImmutable() const;
uint64_t createTimestamp; uint64_t createTimestamp{};
}; };
class TextureUnitState { class TextureUnitState {
@@ -62,10 +62,11 @@ private:
std::set<GLuint> freeIDs; std::set<GLuint> freeIDs;
std::unordered_map<GLenum, TextureObject> proxyTextures; std::unordered_map<GLenum, TextureObject> proxyTextures;
static GLint GetUnpackParam(GLenum pname);
public: public:
TextureState(); TextureState();
static TextureState& GetInstance();
bool IsTextureGenerated(GLuint texture); bool IsTextureGenerated(GLuint texture);
bool IsTexture(GLuint texture); bool IsTexture(GLuint texture);
std::unordered_map<GLuint, TextureObject> textures; std::unordered_map<GLuint, TextureObject> textures;
@@ -88,12 +89,22 @@ public:
GLenum GetLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params); GLenum GetLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
private: private:
static static size_t CalculatePixelDataSize(GLenum format, GLenum type, GLsizei width, GLsizei height); size_t CalculatePixelDataSize(GLenum format, GLenum type, GLsizei width, GLsizei height);
void InvalidateTextureInAllUnits(GLuint texture); void InvalidateTextureInAllUnits(GLuint texture);
static ComponentSizes GetComponentSizes(GLenum internalFormat); static ComponentSizes GetComponentSizes(GLenum internalFormat);
size_t CalculateBytesPerPixel(GLenum format, GLenum type);
static size_t GetComponentSize(GLenum type);
void SwapBytesForTexture(GLenum format, GLenum type, const GLubyte* src, GLubyte* dst, GLsizei width);
static void ReverseBitOrder(const GLubyte* src, GLubyte* dst, size_t size);
static GLubyte ReverseBits(GLubyte b);
void SwapPixelBytes(GLenum format, GLenum type, const GLubyte* src, GLubyte* dst);
GLenum CheckUploadingTexture2DValidity(GLenum target, GLint level, GLint internalFormat, GLenum CheckUploadingTexture2DValidity(GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLsizei height, GLint border, GLenum format, GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, const void* data); GLenum type, const void* data);
GLenum CheckUpdatingTextureRegion2DValidity(GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLsizei width, GLsizei height, GLenum format,
GLenum type, const GLvoid* data);
}; };
#endif //MOBILEGL_TEXTURESTATE_H #endif //MOBILEGL_TEXTURESTATE_H