From 2c40177f062b518c22053daff43969fda735392c Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 11 Aug 2025 15:19:35 +0800 Subject: [PATCH 1/3] [Feat] (MG_Impl/Program, MG_State/Program): initial impl of shader related states --- .../MG_Impl/GLImpl/Program/GL_Program.cpp | 104 ++++++++++++++++-- MobileGL/MG_State/GLState/Core.cpp | 31 ++++++ MobileGL/MG_State/GLState/Core.h | 12 ++ .../GLState/ProgramState/ProgramObject.cpp | 20 ++-- .../GLState/ProgramState/ProgramObject.h | 4 +- .../GLState/ProgramState/ProgramState.cpp | 58 ++++++++-- .../GLState/ProgramState/ProgramState.h | 30 +++-- .../GLState/ProgramState/ShaderObject.cpp | 5 +- .../GLState/ProgramState/ShaderObject.h | 5 + 9 files changed, 231 insertions(+), 38 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 760059e8..75b92f4c 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -1,5 +1,7 @@ #include "GL_Program.h" +#include "MG_State/GLState/Core.h" + namespace MobileGL { namespace MG_Impl::GLImpl { void AttachShader_State(GLuint program, GLuint shader) { @@ -11,27 +13,99 @@ namespace MobileGL { } void CompileShader_State(GLuint shader) { - THROW_UNIMPL_EXCEPTION; + if (!MG_State::pGLContext->ValidateShaderName(shader)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", __func__, + "`shader` is not a value generated by OpenGL.")); + return; + } + + auto shaderObject = MG_State::pGLContext->GetShaderObject(shader); + if (!shaderObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`shader` is not a shader object.")); + return; + } + shaderObject->Compile(); } GLuint CreateProgram_State(void) { - THROW_UNIMPL_EXCEPTION; + return MG_State::pGLContext->CreateProgram(); } GLuint CreateShader_State(GLenum type) { - THROW_UNIMPL_EXCEPTION; + auto shaderId = MG_State::pGLContext->CreateShader(MG_State::GLState::GetMGLShaderStageByGLShaderType(type)); + if (shaderId == 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", __func__, + "`shaderType` is not an accepted value.")); + return 0; + } + return shaderId; } void DeleteProgram_State(GLuint program) { - THROW_UNIMPL_EXCEPTION; + if (!MG_State::pGLContext->ValidateProgramName(program)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", __func__, + "`program` is not a value generated by OpenGL")); + return; + } + MG_State::pGLContext->MarkProgramForDeletion(program); } void DeleteShader_State(GLuint shader) { - THROW_UNIMPL_EXCEPTION; + if (!MG_State::pGLContext->ValidateShaderName(shader)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", __func__, + "`shader` is not a value generated by OpenGL")); + return; + } + MG_State::pGLContext->MarkShaderForDeletion(shader); } void DetachShader_State(GLuint program, GLuint shader) { - THROW_UNIMPL_EXCEPTION; + if (!MG_State::pGLContext->ValidateProgramName(program) || + !MG_State::pGLContext->ValidateShaderName(shader)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", __func__, + "Either `program` or `shader` is a value that was not generated by OpenGL")); + return; + } + + auto programObject = MG_State::pGLContext->GetProgramObject(program); + if (!programObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`program` is not a program object.")); + return; + } + + auto shaderObject = MG_State::pGLContext->GetShaderObject(shader); + if (!shaderObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`shader` is not a shader object.")); + return; + } + + auto count = programObject->DetachShader(shaderObject); + if (count <= 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "Shader is not attached to program.")); + return; + } } void GetActiveAttrib_State(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, @@ -85,11 +159,19 @@ namespace MobileGL { } GLboolean IsProgram_State(GLuint program) { - THROW_UNIMPL_EXCEPTION; + /* FIXME: Handle situations that: + * A program object marked for deletion with glDeleteProgram but still in use as part of current + * rendering state is still considered a program object and glIsProgram will return GL_TRUE. + */ + return MG_State::pGLContext->ValidateProgramName(program); } GLboolean IsShader_State(GLuint shader) { - THROW_UNIMPL_EXCEPTION; + /* FIXME: Handle situations that: + * A shader object marked for deletion with glDeleteShader but still attached to a program object is still + * considered a shader object and glIsShader will return GL_TRUE. + */ + return MG_State::pGLContext->ValidateShaderName(shader); } void LinkProgram_State(GLuint program) { @@ -227,8 +309,9 @@ namespace MobileGL { void GetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) { GetAttachedShaders_State(program, maxCount, count, shaders); } + GLint GetAttribLocation(GLuint program, const GLchar* name) { - GetAttribLocation_State(program, name); + return GetAttribLocation_State(program, name); } void GetProgramiv(GLuint program, GLenum pname, GLint* params) { @@ -250,8 +333,9 @@ namespace MobileGL { void GetShaderSource(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source) { GetShaderSource_State(shader, bufSize, length, source); } + GLint GetUniformLocation(GLuint program, const GLchar* name) { - GetUniformLocation_State(program, name); + return GetUniformLocation_State(program, name); } void GetUniformfv(GLuint program, GLint location, GLfloat* params) { diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index 1f97e7c7..92c190ea 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -156,6 +156,37 @@ namespace MobileGL { m_textureState.SetActiveTextureUnit(unit); } + Uint GLContext::CreateProgram() { + return m_programState.CreateProgram(); + } + + Uint GLContext::CreateShader(const ShaderStage stage) { + return m_programState.CreateShader(stage); + } + + void GLContext::MarkProgramForDeletion(const Uint index) { + return m_programState.MarkProgramObjectForDeletion(index); + } + + void GLContext::MarkShaderForDeletion(const Uint index) { + return m_programState.MarkShaderObjectForDeletion(index); + } + + Bool GLContext::ValidateProgramName(const Uint index) const { + return m_programState.ValidateProgramObject(index); + } + + Bool GLContext::ValidateShaderName(const Uint index) const { + return m_programState.ValidateShaderObject(index); + } + + SharedPtr GLContext::GetProgramObject(const Uint index) { + return m_programState.GetProgramObject(index); + } + + SharedPtr GLContext::GetShaderObject(const Uint index) { + return m_programState.GetShaderObject(index); + } } // namespace GLState GLState::GLContext* pGLContext; diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index fe013a5a..b3bb10c6 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -54,6 +54,15 @@ namespace MobileGL { Int GetActiveTextureUnit() const; void SetActiveTextureUnit(Int unit); + // Program + Uint CreateProgram(); + Uint CreateShader(ShaderStage stage); + void MarkProgramForDeletion(Uint index); + void MarkShaderForDeletion(Uint index); + Bool ValidateProgramName(Uint index) const; + Bool ValidateShaderName(Uint index) const; + SharedPtr GetProgramObject(Uint index); + SharedPtr GetShaderObject(Uint index); private: // Error ErrorState m_errorState; @@ -66,6 +75,9 @@ namespace MobileGL { // Texture TextureState m_textureState; + + // Program + ProgramState m_programState; }; } // namespace GLState diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index f69b8412..2f58b2b7 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -8,22 +8,22 @@ namespace MobileGL { m_shaders.emplace_back(shader); } - void ProgramObject::DetachShader(SharedPtr shader) { + SizeT ProgramObject::DetachShader(SharedPtr shader) { auto count = std::erase_if( - m_shaders, [shader](const SharedPtr& s) { return s.get() == shader.get(); }); + m_shaders, + [shader](const SharedPtr& s) { + return s.get() == shader.get(); + }); - if (count == 0) { - // FIXME: handle error here - THROW_EXCEPTION("Program object does not have such shader object attached"); - } + return count; } void ProgramObject::Link() { Vector shaderTypes(m_shaders.size()); Vector> shaders(m_shaders.size()); for (SizeT i = 0; i < m_shaders.size(); i++) { - shaderTypes[i] = GetGLShaderTypeByMGLShaderStage(m_shaders[i]->m_stage); - shaders[i] = m_shaders[i]->m_shader; + shaderTypes[i] = GetGLShaderTypeByMGLShaderStage(m_shaders[i]->GetShaderStage()); + shaders[i] = m_shaders[i]->GetCompiledShader(); } MG_Util::ShaderTranspiler::ProgramAttrib attrib{ @@ -44,6 +44,10 @@ namespace MobileGL { THROW_EXCEPTION(e); } } + + void ProgramObject::MarkAsDeleted() { + m_deleteStatus = true; + } } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index e5171feb..2d2819a5 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -8,9 +8,9 @@ namespace MobileGL { class ProgramObject { public: void AttachShader(SharedPtr shader); - void DetachShader(SharedPtr shader); + SizeT DetachShader(SharedPtr shader); void Link(); - + void MarkAsDeleted(); private: Vector> m_shaders; // basically this contains SPIR-V in binary format diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp index 31462afd..b90c276d 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp @@ -5,20 +5,62 @@ namespace MobileGL { namespace GLState { Uint ProgramState::CreateProgram() { Uint programId = 0; - m_indexGenerator.Generate(1, &programId); - EnsureIndexAvail(programId); - m_programObjects[programId] = MakeShared(); + m_programIndexGenerator.Generate(1, &programId); + EnsureIndexAvail(programId, m_programObjects); + auto programObject = MakeShared(programId); + if (programObject == nullptr) + return 0; + m_programObjects[programId] = programObject; return programId; } - SharedPtr ProgramState::GetProgramObject(Uint id) { - if (!CheckIndexAvail(id)) return nullptr; // FIXME: add error reporting here + SharedPtr ProgramState::GetProgramObject(const Uint id) { + if (!CheckIndexAvail(id, m_programObjects)) return nullptr; // FIXME: add error reporting here return m_programObjects[id]; } - void ProgramState::DeleteProgram(Uint id) { - if (!CheckIndexAvail(id)) return; // FIXME: add error reporting here - m_programObjects[id].reset(); + void ProgramState::MarkProgramObjectForDeletion(const Uint program) { + if (!CheckIndexAvail(program, m_programObjects)) return; // FIXME: add error reporting here + auto& programObject = m_programObjects[program]; + if (programObject != nullptr) { + programObject->MarkAsDeleted(); + programObject.reset(); + m_programIndexGenerator.Delete(program); + } + } + + Bool ProgramState::ValidateProgramObject(const Uint program) const { + return CheckIndexAvail(program, m_programObjects) && m_programObjects[program] != nullptr; + } + + Uint ProgramState::CreateShader(ShaderStage stage) { + Uint shaderId = 0; + m_shaderIndexGenerator.Generate(1, &shaderId); + EnsureIndexAvail(shaderId, m_shaderObjects); + auto shaderObject = MakeShared(stage); + if (shaderObject == nullptr) + return 0; + m_shaderObjects[shaderId] = shaderObject; + return shaderId; + } + + SharedPtr ProgramState::GetShaderObject(const Uint shader) { + if (!CheckIndexAvail(shader, m_shaderObjects)) return nullptr; + return m_shaderObjects[shader]; + } + + void ProgramState::MarkShaderObjectForDeletion(Uint shader) { + if (!CheckIndexAvail(shader, m_shaderObjects)) return; + auto& shaderObject = m_shaderObjects[shader]; + if (shaderObject != nullptr) { + m_shaderObjects[shader]->MarkAsDeleted(); + m_shaderObjects[shader].reset(); + m_shaderIndexGenerator.Delete(shader); + } + } + + Bool ProgramState::ValidateShaderObject(Uint shader) const { + return CheckIndexAvail(shader, m_shaderObjects) && m_shaderObjects[shader] != nullptr; } } // namespace GLState } // namespace MG_State diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramState.h b/MobileGL/MG_State/GLState/ProgramState/ProgramState.h index ccda4881..85a653a0 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramState.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramState.h @@ -12,20 +12,32 @@ namespace MobileGL { // To retrieve created program object, use GetProgramObject() Uint CreateProgram(); SharedPtr GetProgramObject(Uint id); - void DeleteProgram(Uint program); + void MarkProgramObjectForDeletion(Uint program); + Bool ValidateProgramObject(Uint program) const; + Uint CreateShader(ShaderStage stage); + SharedPtr GetShaderObject(Uint shader); + void MarkShaderObjectForDeletion(Uint shader); + Bool ValidateShaderObject(Uint shader) const; private: - Bool CheckIndexAvail(SizeT idx) { return idx < m_programObjects.size(); } - - void EnsureIndexAvail(SizeT idx) { - if (CheckIndexAvail(idx)) return; - - m_programObjects.reserve(std::bit_ceil(idx)); - m_programObjects.resize(idx + 1); + template + static Bool CheckIndexAvail(const SizeT idx, const Vector& vec) { + return idx < vec.size(); } - IndexGenerator m_indexGenerator; + template + static void EnsureIndexAvail(const SizeT idx, Vector& vec) { + if (CheckIndexAvail(idx, vec)) return; + + vec.reserve(std::bit_ceil(idx)); + vec.resize(idx + 1); + } + + IndexGenerator m_programIndexGenerator; Vector> m_programObjects; + + IndexGenerator m_shaderIndexGenerator; + Vector> m_shaderObjects; }; } // namespace GLState } // namespace MG_State diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp index fd8a07fb..fbbd93de 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp @@ -26,9 +26,12 @@ namespace MobileGL { const std::string e = std::format("Shader compilation failed: \nerrc: {}\nmsg: {}\n", result.error().errc, result.error().log); - THROW_EXCEPTION(e); } } + + void ShaderObject::MarkAsDeleted() { + m_deleteStatus = true; + } } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h index d473c097..c743a629 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h @@ -59,7 +59,12 @@ namespace MobileGL { ShaderObject(const ShaderStage stage) : m_stage(stage) {} void SetShaderSource(const std::string& source); void Compile(); + void MarkAsDeleted(); + ShaderStage GetShaderStage() const { return m_stage; } + const std::string& GetShaderSource() const { return m_source; } + SharedPtr GetCompiledShader() const { return m_shader; } + private: const ShaderStage m_stage; std::string m_source; SharedPtr m_shader; From 4ec815a383e2c9d8e5121259aa80caa97ed07729 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 11 Aug 2025 15:40:17 +0800 Subject: [PATCH 2/3] [Feat] (MG_Impl/Program): use helper functions to simplify the code --- .../MG_Impl/GLImpl/Program/GL_Program.cpp | 120 ++++++++++-------- 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 75b92f4c..4186cc58 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -4,6 +4,58 @@ namespace MobileGL { namespace MG_Impl::GLImpl { + static bool CheckShaderNameValidity(Uint shader) { + if (!MG_State::pGLContext->ValidateShaderName(shader)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", __func__, + "`shader` is not a value generated by OpenGL.")); + return false; + } + return true; + } + + static SharedPtr TryToGetShaderObject(Uint shader) { + if (!CheckShaderNameValidity(shader)) + return nullptr; + + auto shaderObject = MG_State::pGLContext->GetShaderObject(shader); + if (!shaderObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`shader` is not a shader object.")); + return nullptr; + } + return shaderObject; + } + + static bool CheckProgramNameValidity(GLuint program) { + if (!MG_State::pGLContext->ValidateProgramName(program)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeShared("MG_Impl/GLImpl", __func__, + "`program` is not a value generated by OpenGL")); + return false; + } + return true; + } + + static SharedPtr TryToGetProgramObject(GLuint program) { + if (!CheckProgramNameValidity(program)) + return nullptr; + + auto programObject = MG_State::pGLContext->GetProgramObject(program); + if (!programObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`program` is not a program object.")); + return nullptr; + } + return programObject; + } + void AttachShader_State(GLuint program, GLuint shader) { THROW_UNIMPL_EXCEPTION; } @@ -13,22 +65,9 @@ namespace MobileGL { } void CompileShader_State(GLuint shader) { - if (!MG_State::pGLContext->ValidateShaderName(shader)) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidValue, - MakeShared("MG_Impl/GLImpl", __func__, - "`shader` is not a value generated by OpenGL.")); + auto shaderObject = TryToGetShaderObject(shader); + if (!shaderObject) return; - } - - auto shaderObject = MG_State::pGLContext->GetShaderObject(shader); - if (!shaderObject) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidOperation, - MakeShared("MG_Impl/GLImpl", __func__, - "`shader` is not a shader object.")); - return; - } shaderObject->Compile(); } @@ -49,54 +88,24 @@ namespace MobileGL { } void DeleteProgram_State(GLuint program) { - if (!MG_State::pGLContext->ValidateProgramName(program)) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidValue, - MakeShared("MG_Impl/GLImpl", __func__, - "`program` is not a value generated by OpenGL")); + if (!CheckProgramNameValidity(program)) return; - } MG_State::pGLContext->MarkProgramForDeletion(program); } void DeleteShader_State(GLuint shader) { - if (!MG_State::pGLContext->ValidateShaderName(shader)) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidValue, - MakeShared("MG_Impl/GLImpl", __func__, - "`shader` is not a value generated by OpenGL")); + if (!CheckProgramNameValidity(shader)) return; - } MG_State::pGLContext->MarkShaderForDeletion(shader); } void DetachShader_State(GLuint program, GLuint shader) { - if (!MG_State::pGLContext->ValidateProgramName(program) || - !MG_State::pGLContext->ValidateShaderName(shader)) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidValue, - MakeShared("MG_Impl/GLImpl", __func__, - "Either `program` or `shader` is a value that was not generated by OpenGL")); + auto shaderObject = TryToGetShaderObject(shader); + if (!shaderObject) return; - } - - auto programObject = MG_State::pGLContext->GetProgramObject(program); - if (!programObject) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidOperation, - MakeShared("MG_Impl/GLImpl", __func__, - "`program` is not a program object.")); + auto programObject = TryToGetProgramObject(program); + if (!programObject) return; - } - - auto shaderObject = MG_State::pGLContext->GetShaderObject(shader); - if (!shaderObject) { - MG_State::pGLContext->RecordError( - ErrorCode::InvalidOperation, - MakeShared("MG_Impl/GLImpl", __func__, - "`shader` is not a shader object.")); - return; - } auto count = programObject->DetachShader(shaderObject); if (count <= 0) { @@ -163,7 +172,7 @@ namespace MobileGL { * A program object marked for deletion with glDeleteProgram but still in use as part of current * rendering state is still considered a program object and glIsProgram will return GL_TRUE. */ - return MG_State::pGLContext->ValidateProgramName(program); + return CheckProgramNameValidity(program); } GLboolean IsShader_State(GLuint shader) { @@ -171,11 +180,14 @@ namespace MobileGL { * A shader object marked for deletion with glDeleteShader but still attached to a program object is still * considered a shader object and glIsShader will return GL_TRUE. */ - return MG_State::pGLContext->ValidateShaderName(shader); + return CheckShaderNameValidity(shader); } void LinkProgram_State(GLuint program) { - THROW_UNIMPL_EXCEPTION; + auto programObject = TryToGetProgramObject(program); + if (!programObject) + return; + programObject->Link(); } void ShaderSource_State(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) { From 429618a00a5ccda44c8a5ae2a672f5d22c06a545 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 11 Aug 2025 15:50:24 +0800 Subject: [PATCH 3/3] [Feat] (MG_Impl/Program): glAttachShader --- MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp | 14 +++++++++++++- .../GLState/ProgramState/ProgramObject.cpp | 13 ++++++++++++- .../MG_State/GLState/ProgramState/ProgramObject.h | 3 ++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 4186cc58..d65a1db5 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -57,7 +57,19 @@ namespace MobileGL { } void AttachShader_State(GLuint program, GLuint shader) { - THROW_UNIMPL_EXCEPTION; + auto programObject = TryToGetProgramObject(program); + if (!programObject) + return; + auto shaderObject = TryToGetShaderObject(shader); + if (!shaderObject) + return; + if (!programObject->AttachShader(shaderObject)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`shader` is already attached to `program`.")); + return; + } } void BindAttribLocation_State(GLuint program, GLuint index, const GLchar* name) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 2f58b2b7..a82c57a9 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -4,8 +4,19 @@ namespace MobileGL { namespace MG_State { namespace GLState { - void ProgramObject::AttachShader(SharedPtr shader) { + bool ProgramObject::ShaderIsAttached(SharedPtr shader) { + auto it = std::find_if(m_shaders.begin(), m_shaders.end(), + [shader](const SharedPtr& s) { + return s.get() == shader.get(); + }); + return it != m_shaders.end(); + } + + bool ProgramObject::AttachShader(SharedPtr shader) { + if (ShaderIsAttached(shader)) + return false; m_shaders.emplace_back(shader); + return true; } SizeT ProgramObject::DetachShader(SharedPtr shader) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index 2d2819a5..1946707d 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -7,7 +7,8 @@ namespace MobileGL { namespace GLState { class ProgramObject { public: - void AttachShader(SharedPtr shader); + bool ShaderIsAttached(SharedPtr shader); + bool AttachShader(SharedPtr shader); SizeT DetachShader(SharedPtr shader); void Link(); void MarkAsDeleted();