[Feat] (MG_Backend/DirectGLES|MG_Impl): Initial implementions of GetTexImage and ReadPixels.

This commit is contained in:
BZLZHH
2026-02-06 20:14:18 +08:00
parent 07927dc4a3
commit a7d8e90600
9 changed files with 596 additions and 27 deletions
@@ -151,7 +151,7 @@ DECLARE_GL_FUNCTION_HEAD(void, LineWidth, GLfloat width) DECLARE_GL_FUNCTION_END
DECLARE_GL_FUNCTION_HEAD(void, LinkProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, LinkProgram, program)
DECLARE_GL_FUNCTION_HEAD(void, PixelStorei, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PixelStorei, pname, param)
DECLARE_GL_FUNCTION_HEAD(void, PolygonOffset, GLfloat factor, GLfloat units) DECLARE_GL_FUNCTION_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_HEAD(void, ReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) DECLARE_GL_FUNCTION_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_HEAD(void, RenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, RenderbufferStorage, target, internalformat, width, height)
DECLARE_GL_FUNCTION_HEAD(void, SampleCoverage, GLfloat value, GLboolean invert) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleCoverage, value, invert)
@@ -9,6 +9,7 @@
#include "GL_Framebuffer.h"
#include "Validators.h"
#include "Config.h"
#include <MG_Util/Metrics/TextureMetrics.h>
#include <MG_Impl/GLImpl/Texture/Validators.h>
#include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
@@ -310,10 +311,10 @@ namespace MobileGL {
// ------------------- Check validity begin ------------------------
if (attType == FramebufferAttachmentType::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("`mode` = {} is not an accepted value.",
MG_Util::ConvertGLEnumToString(mode))));
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__,
std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode))));
return;
}
@@ -507,7 +508,142 @@ namespace MobileGL {
#endif
}
void ReadPixels_State(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
void* pixels) {
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
// Check width/height
if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Width and height must be non-negative"));
return;
}
// Validate format
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
return;
}
// Validate type
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
return;
}
// Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
auto framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No framebuffer bound to read target"));
return;
}
// Check framebuffer completeness
if (!framebufferObject->CheckCompleteness()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidFramebufferOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
return;
}
// Check for required buffers
if (textureInputFormat == TextureInputFormat::StencilIndex) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No stencil buffer for stencil index format"));
return;
}
} else if (textureInputFormat == TextureInputFormat::DepthComponent) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth buffer for depth component format"));
return;
}
} else if (textureInputFormat == TextureInputFormat::DepthStencil) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid() ||
!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth/stencil buffer for depth-stencil format"));
return;
}
// Validate type for depth/stencil
if (texturePixelDataType != TexturePixelDataType::UnsignedInt248 &&
texturePixelDataType != TexturePixelDataType::Float32UnsignedInt248Rev) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Invalid type for depth-stencil format"));
return;
}
}
// Check PBO state
const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) {
// Check if PBO is mapped
if (pixelPackBufferObject->IsMapped()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel pack buffer is currently mapped"));
return;
}
// Check alignment
const SizeT typeSize = MG_Util::GetTexturePixelDataTypeSize(texturePixelDataType);
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel data not aligned for pixel pack buffer"));
return;
}
}
// Check multisampling
if (framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).IsRenderbuffer()) {
auto rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer();
if (rbo && rbo->GetSamples() > 1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"ReadPixels not supported for multisampled framebuffers"));
return;
}
}
}
void ReadPixels_Backend(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
void* pixels) {
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
MG_Backend::DirectGLES::ReadPixels(x, y, width, height, format, type, pixels);
#endif
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
ReadPixels_State(x, y, width, height, format, type, pixels);
ReadPixels_Backend(x, y, width, height, format, type, pixels);
}
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
ClearBufferfi_Backend(buffer, drawbuffer, depth, stencil);
}
@@ -14,6 +14,7 @@
namespace MobileGL {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
+129 -8
View File
@@ -1164,10 +1164,6 @@ namespace MobileGL {
}
}
void GetTexImage_State(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
// TODO: implement
}
void GetCompressedTexImage_State(GLenum target, GLint level, void* img) {
// TODO: implement
}
@@ -1378,7 +1374,136 @@ namespace MobileGL {
MG_State::pGLContext->SetActiveTextureUnit(texture - GL_TEXTURE0);
}
void GetTexImage_Backend(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
#if MOBILEGL_BACKEND == MOBILEGL_BACKEND_TYPE_DIRECT_GLES
MG_Backend::DirectGLES::GetTexImage(target, level, format, type, pixels);
#endif
}
// Add to GL_Texture.cpp
void GetTexImage_State(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
// ======================= Converting ================================
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
// ===================== Error Checking ==============================
// Validate target
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid texture target"));
return;
}
// Validate level
if (level < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Level must be non-negative"));
return;
}
// Validate format
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid format"));
return;
}
// Validate type
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid pixel data type"));
return;
}
// Get texture object
SharedPtr<MG_State::GLState::ITextureObject> textureObject = nullptr;
if (TextureImpl::IsProxyTextureTarget(textureUploadTarget)) {
textureObject = TextureImpl::pProxyTextureManager->GetProxyTextureObject(textureUploadTarget);
} else {
auto activeUnit =
MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
textureObject = bindingSlot.GetBoundObject();
}
if (!TextureImpl::ValidateTextureObject(textureObject)) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"No valid texture bound to target"));
return;
}
// Check texture completeness
if (!textureObject->IsComplete()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Texture is incomplete"));
return;
}
// Check PBO state
const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) {
// Check if PBO is mapped
if (pixelPackBufferObject->IsMapped()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Pixel pack buffer is currently mapped"));
return;
}
// Check alignment
const SizeT typeSize = MG_Util::GetTexturePixelDataTypeSize(texturePixelDataType);
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Pixel data not aligned for pixel pack buffer"));
return;
}
}
// Special case for depth/stencil
if (textureInputFormat == TextureInputFormat::StencilIndex) {
if (textureObject->GetFormat() != TextureInternalFormat::DepthStencil &&
textureObject->GetFormat() != TextureInternalFormat::Depth24Stencil8 &&
textureObject->GetFormat() != TextureInternalFormat::Depth32FStencil8) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"No stencil buffer for stencil index format"));
return;
}
}
// Check for multisampling
if (textureObject->GetStorageType() == TextureStorageType::Mipmap) {
auto mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
if (mipmapObject->GetMipmapLevelCount() > 1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Multisampled textures not supported for GetTexImage"));
return;
}
}
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
GetTexImage_State(target, level, format, type, pixels);
GetTexImage_Backend(target, level, format, type, pixels);
}
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) {
TexSubImage3D_State(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
@@ -1475,10 +1600,6 @@ namespace MobileGL {
GetTexLevelParameterfv_State(target, level, pname, params);
}
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
GetTexImage_State(target, level, format, type, pixels);
}
void GetCompressedTexImage(GLenum target, GLint level, void* img) {
GetCompressedTexImage_State(target, level, img);
}
+1 -1
View File
@@ -12,6 +12,7 @@
namespace MobileGL {
namespace MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
@@ -43,7 +44,6 @@ namespace MobileGL {
void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
void GetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params);
void GetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat* params);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void GetCompressedTexImage(GLenum target, GLint level, void* img);
void GenTextures(GLsizei n, GLuint* textures);
void DeleteTextures(GLsizei n, const GLuint* textures);