mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Feat] (...): Add FramebufferState while implementing these gl functions.
This commit is contained in:
@@ -66,6 +66,8 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
|
||||
|
||||
MG/MG_GL/State/Program/ShaderObject.cpp
|
||||
MG/MG_GL/State/Program/ProgramState.cpp
|
||||
|
||||
MG/MG_GL/State/Framebuffer/FramebufferState.cpp
|
||||
|
||||
# MG_GL/BackendLoader
|
||||
MG/MG_GL/BackendLoader/GLES/Loader.cpp
|
||||
|
||||
@@ -23,6 +23,21 @@ namespace MG_Constants {
|
||||
inline const int LOG_LEVEL_FATAL = 0x0014;
|
||||
}
|
||||
|
||||
namespace Framebuffer {
|
||||
static const std::unordered_set<GLenum> VALID_ATTACHMENTS = {
|
||||
GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
|
||||
GL_STENCIL_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT
|
||||
}; // OpenGL 3
|
||||
|
||||
static const std::unordered_set<GLenum> VALID_TARGETS = {
|
||||
GL_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER
|
||||
}; // OpenGL 3
|
||||
|
||||
static const std::unordered_set<GLenum> VALID_ACCESS = {
|
||||
GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE
|
||||
}; // OpenGL 3
|
||||
}
|
||||
|
||||
namespace Buffer {
|
||||
static const std::unordered_set<GLenum> VALID_PARAM_NAMES = {
|
||||
GL_BUFFER_ACCESS, GL_BUFFER_MAPPED, GL_BUFFER_SIZE, GL_BUFFER_USAGE
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ namespace MG_Global {
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
inline const int LogLevel = MG_Constants::Common::LOG_LEVEL_INFO;
|
||||
inline const int LogLevel = MG_Constants::Common::LOG_LEVEL_DEBUG;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
inline const char* LOG_FILE_PATH = "/sdcard/MG/latest.log";
|
||||
|
||||
@@ -53,6 +53,9 @@
|
||||
#ifndef MOBILEGL_PROGRAMSTATE_H
|
||||
#include "MG_GL/State/Program/ProgramState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
#include "MG_GL/State/Framebuffer/FramebufferState.h"
|
||||
#endif
|
||||
#ifndef MOBILEGL_LOOKUP_H
|
||||
#include "MG_GL/Implementations/GLX/LookUp/LookUp.h"
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,63 @@
|
||||
#include "GL_Framebuffer.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers) {
|
||||
MG_Util::Debug::LogD("glGenFramebuffers, n: %d, framebuffers: %p", n, framebuffers);
|
||||
GLenum result = MG_State::CreateFramebuffers(n, framebuffers);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Framebuffer generation failed: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) {
|
||||
MG_Util::Debug::LogD("glDeleteFramebuffers, n: %d, framebuffers: %p", n, framebuffers);
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
GLenum result = MG_State::DeleteFramebuffer(framebuffers[i]);
|
||||
if (result != GL_NO_ERROR) {
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Failed to delete framebuffer %u: %s",
|
||||
framebuffers[i], MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BindFramebuffer(GLenum target, GLuint framebuffer) {
|
||||
MG_Util::Debug::LogD("glBindFramebuffer, target: %s, fb: %u",
|
||||
MG_Util::Debug::GLEnumToString(target), framebuffer);
|
||||
GLenum result = MG_State::BindFramebuffer(target, framebuffer);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Framebuffer bind error: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level) {
|
||||
MG_Util::Debug::LogD("glFramebufferTexture2D, target: %s, attach: %s, textarget: %s, tex: %u, level: %d",
|
||||
MG_Util::Debug::GLEnumToString(target),
|
||||
MG_Util::Debug::GLEnumToString(attachment),
|
||||
MG_Util::Debug::GLEnumToString(textarget),
|
||||
texture, level);
|
||||
|
||||
GLenum result = MG_State::AttachTexture2DToFramebuffer(
|
||||
target, attachment, textarget, texture, level
|
||||
);
|
||||
if (result == GL_NO_ERROR) return;
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Texture attachment failed: %s", MG_Util::Debug::GLEnumToString(result));
|
||||
}
|
||||
|
||||
GLenum CheckFramebufferStatus(GLenum target) {
|
||||
return GL_FRAMEBUFFER_COMPLETE;
|
||||
MG_Util::Debug::LogD("glCheckFramebufferStatus, target: %s",
|
||||
MG_Util::Debug::GLEnumToString(target));
|
||||
GLenum result = MG_State::ValidateFramebufferCompleteness(target);
|
||||
if (result >= GL_FRAMEBUFFER_COMPLETE) {
|
||||
MG_Util::Debug::LogD("Framebuffer status: %s",
|
||||
MG_Util::Debug::GLEnumToString(result));
|
||||
return result;
|
||||
}
|
||||
MG_State::SetError(result);
|
||||
MG_Util::Debug::LogE("Framebuffer incomplete: %s",
|
||||
MG_Util::Debug::GLEnumToString(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "../../../../Includes.h"
|
||||
|
||||
namespace MG_GL::GL {
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
||||
void BindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
GLenum CheckFramebufferStatus(GLenum target);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ DECLARE_GL_FUNCTION_HEAD(void, ActiveTexture, GLenum texture) DECLARE_GL_FUNCTIO
|
||||
DECLARE_GL_FUNCTION_HEAD(void, AttachShader, GLuint program, GLuint shader) DECLARE_GL_FUNCTION_END_NO_RETURN(void, AttachShader, program,shader)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindAttribLocation, GLuint program, GLuint index, const GLchar *name) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindAttribLocation, program,index,name)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindBuffer, GLenum target, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBuffer, target,buffer)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFramebuffer, GLenum target, GLuint framebuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFramebuffer, target,framebuffer)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindFramebuffer, GLenum target, GLuint framebuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindFramebuffer, target,framebuffer)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindRenderbuffer, GLenum target, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindRenderbuffer, target,renderbuffer)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindTexture, GLenum target, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTexture, target,texture)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendColor, red,green,blue,alpha)
|
||||
@@ -62,7 +62,7 @@ DECLARE_GL_FUNCTION_HEAD(GLuint, CreateProgram) DECLARE_GL_FUNCTION_END(GLuint,
|
||||
DECLARE_GL_FUNCTION_HEAD(GLuint, CreateShader, GLenum type) DECLARE_GL_FUNCTION_END(GLuint, CreateShader, type)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CullFace, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CullFace, mode)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteBuffers, GLsizei n, const GLuint *buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteBuffers, n,buffers)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteFramebuffers, GLsizei n, const GLuint *framebuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteFramebuffers, n,framebuffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, DeleteFramebuffers, GLsizei n, const GLuint *framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteFramebuffers, n,framebuffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, DeleteProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteProgram, program)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteRenderbuffers, GLsizei n, const GLuint *renderbuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteRenderbuffers, n,renderbuffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, DeleteShader, GLuint shader) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteShader, shader)
|
||||
@@ -80,11 +80,11 @@ DECLARE_GL_FUNCTION_HEAD(void, EnableVertexAttribArray, GLuint index) DECLARE_GL
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Finish) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Finish)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, Flush) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Flush)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferRenderbuffer, target,attachment,renderbuffertarget,renderbuffer)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferTexture2D, target,attachment,textarget,texture,level)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target,attachment,textarget,texture,level)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, FrontFace, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FrontFace, mode)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GenBuffers, GLsizei n, GLuint *buffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenBuffers, n,buffers)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateMipmap, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateMipmap, target)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenFramebuffers, GLsizei n, GLuint *framebuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenFramebuffers, n,framebuffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GenFramebuffers, GLsizei n, GLuint *framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenFramebuffers, n,framebuffers)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenRenderbuffers, GLsizei n, GLuint *renderbuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenRenderbuffers, n,renderbuffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GenTextures, GLsizei n, GLuint *textures) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenTextures, n,textures)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveAttrib, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveAttrib, program,index,bufSize,length,size,type,name)
|
||||
|
||||
@@ -10,6 +10,7 @@ CommonState* MG_State_T::commonState = nullptr;
|
||||
BufferState* MG_State_T::bufferState = nullptr;
|
||||
VertexArrayState* MG_State_T::vertexArrayState = nullptr;
|
||||
ProgramState* MG_State_T::programState = nullptr;
|
||||
FramebufferState* MG_State_T::framebufferState = nullptr;
|
||||
|
||||
namespace MG_State {
|
||||
void Init() {
|
||||
@@ -18,6 +19,7 @@ namespace MG_State {
|
||||
MG_State_T::bufferState = new BufferState();
|
||||
MG_State_T::vertexArrayState = new VertexArrayState();
|
||||
MG_State_T::programState = new ProgramState();
|
||||
MG_State_T::framebufferState = new FramebufferState();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
@@ -26,6 +28,7 @@ namespace MG_State {
|
||||
delete MG_State_T::bufferState;
|
||||
delete MG_State_T::vertexArrayState;
|
||||
delete MG_State_T::programState;
|
||||
delete MG_State_T::framebufferState;
|
||||
}
|
||||
|
||||
void SetError(GLenum error) {
|
||||
@@ -300,4 +303,31 @@ void UpdateProgramUniformMatrix##suffix##Vector(GLint location, GLsizei count, G
|
||||
bool SetShaderStatus(GLuint shader, GLboolean status) {
|
||||
return MG_State_T::programState->SetShaderStatus(shader, status);
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
GLenum MG_State::CreateFramebuffer(GLuint* framebuffer) {
|
||||
return MG_State_T::framebufferState->Create(framebuffer);
|
||||
}
|
||||
|
||||
GLenum MG_State::CreateFramebuffers(GLsizei n, GLuint* framebuffers) {
|
||||
return MG_State_T::framebufferState->CreateN(n, framebuffers);
|
||||
}
|
||||
|
||||
GLenum MG_State::DeleteFramebuffer(GLuint framebuffer) {
|
||||
return MG_State_T::framebufferState->Delete(framebuffer);
|
||||
}
|
||||
|
||||
GLenum MG_State::BindFramebuffer(GLenum target, GLuint framebuffer) {
|
||||
return MG_State_T::framebufferState->Bind(target, framebuffer);
|
||||
}
|
||||
|
||||
GLenum MG_State::AttachTexture2DToFramebuffer(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level) {
|
||||
return MG_State_T::framebufferState->glAttachTexture2D(target, attachment, textarget,
|
||||
texture, level);
|
||||
}
|
||||
|
||||
GLenum MG_State::ValidateFramebufferCompleteness(GLenum target) {
|
||||
return MG_State_T::framebufferState->glValidateCompleteness(target);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ struct MG_State_T {
|
||||
static BufferState* bufferState;
|
||||
static VertexArrayState* vertexArrayState;
|
||||
static ProgramState* programState;
|
||||
static FramebufferState* framebufferState;
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
@@ -117,6 +118,15 @@ namespace MG_State {
|
||||
GLuint GetCurrentProgram();
|
||||
bool SetProgramStatus(GLuint program, GLboolean status);
|
||||
bool SetShaderStatus(GLuint shader, GLboolean status);
|
||||
|
||||
// Framebuffer
|
||||
GLenum CreateFramebuffer(GLuint* framebuffer);
|
||||
GLenum CreateFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
GLenum DeleteFramebuffer(GLuint framebuffer);
|
||||
GLenum BindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
GLenum AttachTexture2DToFramebuffer(GLenum target, GLenum attachment, GLenum textarget,
|
||||
GLuint texture, GLint level);
|
||||
GLenum ValidateFramebufferCompleteness(GLenum target);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
// TODO: Add more gl error check for framebuffer state manager.
|
||||
// TODO: Check if the state machine really meets up to OpenGL 3 standard.
|
||||
|
||||
#include "FramebufferState.h"
|
||||
|
||||
// Re-Include Includes.h, cuz of the absence of GLState.h
|
||||
#undef MOBILEGL_GLSTATE_H
|
||||
#include "../../../Includes.h"
|
||||
|
||||
GLenum FramebufferState::Create(GLuint* framebuffer) {
|
||||
if (!framebuffer) return GL_INVALID_VALUE;
|
||||
GLuint id = freeIds_.empty() ? ++lastId_ : *freeIds_.begin();
|
||||
if (!freeIds_.empty()) freeIds_.erase(freeIds_.begin());
|
||||
*framebuffer = id;
|
||||
framebuffers_[id].generated = true;
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::CreateN(GLsizei n, GLuint* framebuffers) {
|
||||
if (n < 0) return GL_INVALID_VALUE;
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
if (GLenum err = Create(&framebuffers[i])) return err;
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::Delete(GLuint framebuffer) {
|
||||
if (framebuffer == 0) return GL_INVALID_VALUE;
|
||||
|
||||
if (framebuffers_.erase(framebuffer)) {
|
||||
freeIds_.insert(framebuffer);
|
||||
for (auto& [target, id] : currentBindings_) {
|
||||
if (id == framebuffer) id = 0;
|
||||
}
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::Bind(GLenum target, GLuint framebuffer) {
|
||||
if (MG_Constants::Framebuffer::VALID_TARGETS.find(target) == MG_Constants::Framebuffer::VALID_TARGETS.end())
|
||||
return GL_INVALID_ENUM;
|
||||
if (framebuffer != 0 && !ValidateHandle(framebuffer))
|
||||
return GL_INVALID_OPERATION;
|
||||
if (target == GL_FRAMEBUFFER) {
|
||||
currentBindings_[GL_READ_FRAMEBUFFER] = framebuffer;
|
||||
currentBindings_[GL_DRAW_FRAMEBUFFER] = framebuffer;
|
||||
currentBindings_[GL_FRAMEBUFFER] = framebuffer;
|
||||
} else {
|
||||
currentBindings_[target] = framebuffer;
|
||||
}
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::glAttachTexture2D(GLenum target, GLenum attachment,
|
||||
GLenum textarget, GLuint texture, GLint level) {
|
||||
if (MG_Constants::Framebuffer::VALID_ATTACHMENTS.find(attachment) == MG_Constants::Framebuffer::VALID_ATTACHMENTS.end() ||
|
||||
MG_Constants::Texture::VALID_TARGETS.find(textarget) == MG_Constants::Texture::VALID_TARGETS.end())
|
||||
return GL_INVALID_ENUM;
|
||||
FramebufferObject* fbo = GetCurrentFBO(target);
|
||||
if (!fbo) return GL_INVALID_OPERATION;
|
||||
if (texture != 0 && !MG_State_T::textureState->IsTexture(texture))
|
||||
return GL_INVALID_VALUE;
|
||||
FramebufferAttachment att;
|
||||
att.type = GL_TEXTURE_2D;
|
||||
att.handle = texture;
|
||||
att.mipLevel = level;
|
||||
fbo->attachments[attachment] = att;
|
||||
|
||||
if (texture != 0) {
|
||||
GLint params = 0;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
textarget, level, GL_TEXTURE_WIDTH, ¶ms);
|
||||
fbo->width = params;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
textarget, level, GL_TEXTURE_HEIGHT, ¶ms);
|
||||
fbo->height = params;
|
||||
}
|
||||
UpdateCompleteness(*fbo);
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
|
||||
GLenum FramebufferState::glValidateCompleteness(GLenum target) {
|
||||
FramebufferObject* fbo = GetCurrentFBO(target);
|
||||
if (!fbo) return GL_INVALID_OPERATION;
|
||||
return fbo->status;
|
||||
}
|
||||
|
||||
void FramebufferState::UpdateCompleteness(FramebufferObject& fbo) {
|
||||
if (fbo.attachments.empty()) {
|
||||
fbo.status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
return;
|
||||
}
|
||||
bool hasColor = false;
|
||||
bool hasDepth = false;
|
||||
bool hasStencil = false;
|
||||
GLsizei width = 0, height = 0;
|
||||
for (const auto& [attach, att] : fbo.attachments) {
|
||||
GLsizei attWidth = 0, attHeight = 0;
|
||||
if (att.handle != 0) {
|
||||
GLint params = 0;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
GL_TEXTURE_2D, att.mipLevel, GL_TEXTURE_WIDTH, ¶ms);
|
||||
attWidth = params;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
GL_TEXTURE_2D, att.mipLevel, GL_TEXTURE_HEIGHT, ¶ms);
|
||||
attHeight = params;
|
||||
}
|
||||
if (width == 0) {
|
||||
width = attWidth;
|
||||
height = attHeight;
|
||||
} else if (attWidth != width || attHeight != height) {
|
||||
fbo.status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (attach == GL_DEPTH_ATTACHMENT) hasDepth = true;
|
||||
if (attach == GL_STENCIL_ATTACHMENT) hasStencil = true;
|
||||
if (attach >= GL_COLOR_ATTACHMENT0 &&
|
||||
attach <= GL_COLOR_ATTACHMENT31) hasColor = true;
|
||||
}
|
||||
|
||||
if (!ValidateAttachmentCombination(fbo)) {
|
||||
fbo.status = GL_FRAMEBUFFER_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
fbo.status = GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
bool FramebufferState::ValidateAttachmentCombination(const FramebufferObject& fbo) {
|
||||
bool depthStencilConflict = false;
|
||||
for (const auto& [attach, att] : fbo.attachments) {
|
||||
if (attach == GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
GLint internalFormat = 0;
|
||||
MG_State_T::textureState->QueryLevelPropertyIntVector(
|
||||
GL_TEXTURE_2D, att.mipLevel, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
|
||||
if (internalFormat != GL_DEPTH24_STENCIL8 &&
|
||||
internalFormat != GL_DEPTH32F_STENCIL8) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
FramebufferObject* FramebufferState::GetCurrentFBO(GLenum target) {
|
||||
auto it = currentBindings_.find(target);
|
||||
if (it == currentBindings_.end()) return nullptr;
|
||||
|
||||
GLuint id = it->second;
|
||||
if (id == 0) return nullptr;
|
||||
|
||||
auto fboIt = framebuffers_.find(id);
|
||||
return (fboIt != framebuffers_.end()) ? &fboIt->second : nullptr;
|
||||
}
|
||||
|
||||
bool FramebufferState::ValidateHandle(GLuint framebuffer) {
|
||||
return framebuffers_.count(framebuffer) &&
|
||||
framebuffers_[framebuffer].generated;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Created by BZLZHH on 2025/5/3.
|
||||
//
|
||||
|
||||
#ifndef MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
#define MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
#define MOBILEGL_GLSTATE_H
|
||||
|
||||
#include "../../../Includes.h"
|
||||
|
||||
struct FramebufferAttachment {
|
||||
GLenum type = GL_NONE;
|
||||
GLuint handle = 0;
|
||||
GLint mipLevel = 0;
|
||||
GLint zoffset = 0;
|
||||
};
|
||||
|
||||
struct FramebufferObject {
|
||||
bool generated = false;
|
||||
std::unordered_map<GLenum, FramebufferAttachment> attachments;
|
||||
GLenum status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
GLsizei width = 0;
|
||||
GLsizei height = 0;
|
||||
};
|
||||
|
||||
class FramebufferState {
|
||||
public:
|
||||
// Return: the validity of the operation
|
||||
GLenum Create(GLuint* framebuffer);
|
||||
GLenum CreateN(GLsizei n, GLuint* framebuffers);
|
||||
GLenum Delete(GLuint framebuffer);
|
||||
GLenum Bind(GLenum target, GLuint framebuffer);
|
||||
GLenum glAttachTexture2D(GLenum target, GLenum attachment,
|
||||
GLenum textarget, GLuint texture, GLint level);
|
||||
GLenum glValidateCompleteness(GLenum target);
|
||||
FramebufferObject* GetCurrentFBO(GLenum target);
|
||||
|
||||
private:
|
||||
std::unordered_map<GLuint, FramebufferObject> framebuffers_;
|
||||
std::unordered_map<GLenum, GLuint> currentBindings_; // READ/DRAW/FRAMEBUFFER
|
||||
std::set<GLuint> freeIds_;
|
||||
GLuint lastId_ = 0;
|
||||
bool ValidateHandle(GLuint framebuffer);
|
||||
static void UpdateCompleteness(FramebufferObject& fbo);
|
||||
static bool ValidateAttachmentCombination(const FramebufferObject& fbo);
|
||||
};
|
||||
|
||||
#endif //MOBILEGL_FRAMEBUFFERSTATE_H
|
||||
Reference in New Issue
Block a user