[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/MG_GL/State/Core/GLState.cpp
MG/MG_GL/State/Common/CommonState.cpp
MG/MG_GL/State/Texture/TextureState.cpp
# MG_GL/GLX
+30
View File
@@ -22,6 +22,36 @@ namespace MG_Constants {
inline const int LOG_LEVEL_INFO = 0x0013;
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 {
inline const GLuint MAX_TEXTURE_UNITS = 80;
+3
View File
@@ -38,6 +38,9 @@
#ifndef MOBILEGL_GLSTATE_H
#include "MG_GL/State/Core/GLState.h"
#endif
#ifndef MOBILEGL_COMMONSTATE_H
#include "MG_GL/State/Common/CommonState.h"
#endif
#ifndef MOBILEGL_TEXTURESTATE_H
#include "MG_GL/State/Texture/TextureState.h"
#endif
+9
View File
@@ -16,4 +16,13 @@ namespace MG_GL::GL {
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 ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void Clear(GLbitfield mask);
void PixelStorei(GLenum pname, GLint param);
}
#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(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, 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, 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)
+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"
TextureState* MG_State_T::textureState;
std::queue<GLenum> MG_State_T::glErrorQueue;
TextureState* MG_State_T::textureState = nullptr;
CommonState* MG_State_T::commonState = nullptr;
namespace MG_State {
void Init() {
MG_State_T::textureState = new TextureState();
MG_State_T::commonState = new CommonState();
}
void Destroy() {
delete MG_State_T::textureState;
delete MG_State_T::commonState;
}
void SetError(GLenum error) {
@@ -80,4 +83,13 @@ namespace MG_State {
GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* 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 {
static std::queue<GLenum> glErrorQueue;
static TextureState* textureState;
static CommonState* commonState;
};
namespace MG_State {
@@ -36,6 +37,9 @@ namespace MG_State {
GLenum DeleteTexture(GLuint texture);
GLenum DeleteTextures(GLsizei n, const GLuint* textures);
GLenum GetTextureLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
GLenum SetPixelStoreInt(GLenum pname, GLint param);
GLint GetPixelStoreInt(GLenum pname);
}
+354 -102
View File
@@ -4,6 +4,10 @@
#include "TextureState.h"
// Re-Include Includes.h, cuz of the absence of GLState.h
#undef MOBILEGL_GLSTATE_H
#include "../../../Includes.h"
// TextureObject
bool TextureObject::IsImmutable() const {
@@ -33,10 +37,10 @@ TextureState::TextureState() {
MG_Util::Debug::LogD("MG_State: Texture: TextureState constructor, textureUnits=%zu", textureUnits.size());
}
TextureState &TextureState::GetInstance() {
static TextureState instance;
MG_Util::Debug::LogD("MG_State: Texture: GetInstance called");
return instance;
GLint TextureState::GetUnpackParam(GLenum pname) {
GLint result = MG_State::GetPixelStoreInt(pname);
MG_Util::Debug::LogD("MG_State: Texture: GetUnpackParam pname=0x%x, returns %d", pname, result);
return result;
}
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) {
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;
switch (type) {
case GL_UNSIGNED_BYTE_3_3_2:
@@ -219,7 +229,11 @@ size_t TextureState::CalculatePixelDataSize(GLenum format, GLenum type, GLsizei
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);
return totalSize;
}
@@ -227,13 +241,15 @@ size_t TextureState::CalculatePixelDataSize(GLenum format, GLenum type, GLsizei
GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLsizei height, GLint border, GLenum format,
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);
GLenum validity = CheckUploadingTexture2DValidity(target, level, internalFormat, width, height, border, format, type, data);
MG_Util::Debug::LogD("MG_State: Texture: Upload2D called target=0x%x, level=%d, width=%d, height=%d",
target, level, width, height);
GLenum validity = CheckUploadingTexture2DValidity(target, level, internalFormat,
width, height, border, format, type, data);
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;
}
bool isProxyTexture = (target == GL_PROXY_TEXTURE_1D || target == GL_PROXY_TEXTURE_2D ||
target == GL_PROXY_TEXTURE_3D || target == GL_PROXY_TEXTURE_CUBE_MAP ||
target == GL_PROXY_TEXTURE_1D_ARRAY || target == GL_PROXY_TEXTURE_2D_ARRAY ||
@@ -253,7 +269,7 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
proxyTex.params.mipmapData[level] = mip;
return GL_NO_ERROR;
}
GLuint boundTex = textureUnits[activeTextureUnit].GetBoundTexture(target);
TextureObject& tex = textures[boundTex];
TextureParams::MipmapLevel mip{};
@@ -263,19 +279,56 @@ GLenum TextureState::Upload2D(GLenum target, GLint level, GLint internalFormat,
mip.format = format;
mip.type = type;
if (data != nullptr) {
size_t dataSize = CalculatePixelDataSize(format, type, width, height);
mip.pixelData.resize(dataSize);
memcpy(mip.pixelData.data(), data, dataSize);
GLint unpackSwapBytes = GetUnpackParam(GL_UNPACK_SWAP_BYTES);
GLint unpackLSBFirst = GetUnpackParam(GL_UNPACK_LSB_FIRST);
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;
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 {
mip.hasData = false;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D data pointer is null");
}
tex.data = data;
tex.params.mipmapData[level] = mip;
MG_Util::Debug::LogD("MG_State: Texture: Upload2D succeeded for level=%d", level);
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",
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: UpdateRegion2D invalid target=0x%x", target);
return GL_INVALID_ENUM;
GLenum validity = CheckUpdatingTextureRegion2DValidity(target, level, xoffset, yoffset, width, height, format, type, data);
if (validity != GL_NO_ERROR) {
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);
if (boundTex == 0) {
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& tex = textures[boundTex];
auto mipIt = tex.params.mipmapData.find(level);
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;
}
TextureParams::MipmapLevel& mip = mipIt->second;
if (MG_Constants::Texture::VALID_FORMATS.find(format) == MG_Constants::Texture::VALID_FORMATS.end()) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D invalid format=0x%x", format);
GLint unpackSwapBytes = GetUnpackParam(GL_UNPACK_SWAP_BYTES);
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;
}
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) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D region out of bounds: "
"x=%d+%d > %d or y=%d+%d > %d",
xoffset, width, mip.width, yoffset, height, mip.height);
MG_Util::Debug::LogE("MG_State: Texture: Update region out of bounds");
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);
const GLsizei srcRowLength = (unpackRowLength > 0) ? unpackRowLength : width;
const size_t srcRowSize = srcRowLength * bytesPerPixel;
const size_t srcRowStride = (srcRowSize + unpackAlignment - 1) & ~(unpackAlignment - 1);
const size_t srcImageStride = (unpackImageHeight > 0)
? srcRowStride * unpackImageHeight
: srcRowStride * height;
bool isDepthFormat = (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL);
if (isDepthInternal != isDepthFormat) {
MG_Util::Debug::LogE("MG_State: Texture: UpdateRegion2D format mismatch with internal format");
return GL_INVALID_OPERATION;
const GLubyte* srcData = static_cast<const GLubyte*>(data);
srcData += unpackSkipImages * srcImageStride;
srcData += unpackSkipRows * srcRowStride;
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;
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D validated subimage update");
tex.data = data;
MG_Util::Debug::LogD("MG_State: Texture: UpdateRegion2D succeeded");
return GL_NO_ERROR;
}
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);
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;
}
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) {
MG_Util::Debug::LogD("MG_State: Texture: GetComponentSizes called for internalFormat=0x%x", internalFormat);
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);
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;
const void* data = nullptr;
bool IsImmutable() const;
uint64_t createTimestamp;
uint64_t createTimestamp{};
};
class TextureUnitState {
@@ -62,10 +62,11 @@ private:
std::set<GLuint> freeIDs;
std::unordered_map<GLenum, TextureObject> proxyTextures;
static GLint GetUnpackParam(GLenum pname);
public:
TextureState();
static TextureState& GetInstance();
bool IsTextureGenerated(GLuint texture);
bool IsTexture(GLuint texture);
std::unordered_map<GLuint, TextureObject> textures;
@@ -88,12 +89,22 @@ public:
GLenum GetLevelPropertyIntVector(GLenum target, GLint level, GLenum pname, GLint* params);
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);
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,
GLsizei width, GLsizei height, GLint border, GLenum format,
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