diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 1a4d1274..65229d4c 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -844,19 +844,13 @@ namespace MobileGL::MG_Impl::GLImpl { } GLboolean IsProgram_State(GLuint program) { - /* 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. - */ + // Deletion-flagged names stay valid while the object is still GL-visible (program in + // use, shader attached), so name validity is exactly the Is* answer. if (program == 0) return GL_FALSE; return MG_State::pGLContext->ValidateProgramName(program) ? GL_TRUE : GL_FALSE; } GLboolean IsShader_State(GLuint shader) { - /* 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. - */ if (shader == 0) return GL_FALSE; return MG_State::pGLContext->ValidateShaderName(shader) ? GL_TRUE : GL_FALSE; } diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp index 1197f7aa..2aeb76e7 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramState.cpp @@ -29,17 +29,25 @@ namespace MobileGL::MG_State::GLState { if (!CheckIndexAvail(program, m_programObjects)) return; // FIXME: add error reporting here auto& programObject = m_programObjects[program]; if (programObject != nullptr) { - // Snapshot the attachments: deleting the program is a detach point for shaders - // that were flagged with glDeleteShader while still attached. - const Vector> attachedShaders = programObject->GetAttachedShaders(); programObject->MarkAsDeleted(); - programObject.reset(); - m_programIndexGenerator.Delete(program); - for (const auto& shader : attachedShaders) { - const Uint shaderName = shader->GetExternalIndex(); - if (CheckIndexAvail(shaderName, m_shaderObjects) && m_shaderObjects[shaderName] == shader) { - ReleaseShaderNameIfOrphaned(shaderName); - } + // A program in use is only FLAGGED: its name (and every program query) stays + // valid until it stops being current, at which point UseProgram finishes the job. + if (programObject == m_currentProgram) return; + DestroyProgramSlot(program); + } + } + + void ProgramState::DestroyProgramSlot(const Uint program) { + auto& programObject = m_programObjects[program]; + // Snapshot the attachments: deleting the program is a detach point for shaders + // that were flagged with glDeleteShader while still attached. + const Vector> attachedShaders = programObject->GetAttachedShaders(); + programObject.reset(); + m_programIndexGenerator.Delete(program); + for (const auto& shader : attachedShaders) { + const Uint shaderName = shader->GetExternalIndex(); + if (CheckIndexAvail(shaderName, m_shaderObjects) && m_shaderObjects[shaderName] == shader) { + ReleaseShaderNameIfOrphaned(shaderName); } } } @@ -49,10 +57,22 @@ namespace MobileGL::MG_State::GLState { } void ProgramState::UseProgram(Uint program) { + const SharedPtr previous = m_currentProgram; + if (program == 0) m_currentProgram.reset(); - if (!CheckIndexAvail(program, m_programObjects)) return; - m_currentProgram = m_programObjects[program]; + if (CheckIndexAvail(program, m_programObjects)) { + m_currentProgram = m_programObjects[program]; + } + + // A deletion flagged while the program was current takes effect the moment it + // stops being current. + if (previous != nullptr && previous != m_currentProgram && previous->GetDeleteStatus()) { + const Uint previousName = previous->GetExternalIndex(); + if (CheckIndexAvail(previousName, m_programObjects) && m_programObjects[previousName] == previous) { + DestroyProgramSlot(previousName); + } + } } Uint ProgramState::CreateShader(ShaderStage stage) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramState.h b/MobileGL/MG_State/GLState/ProgramState/ProgramState.h index c48ec59f..5fbd4553 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramState.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramState.h @@ -35,6 +35,9 @@ namespace MobileGL::MG_State::GLState { private: Bool ShaderHasGLVisibleAttachment(const SharedPtr& shaderObject) const; + // Frees the name slot and releases orphaned attached shaders; the immediate half + // of glDeleteProgram (deferred while the program is current). + void DestroyProgramSlot(Uint program); template static Bool CheckIndexAvail(const SizeT idx, const Vector& vec) {