[Fix, Test] (MG_State, MG_Impl): a reserved program-pipeline name takes state from UseProgramStages and its siblings instead of rejecting them

This commit is contained in:
2026-08-11 20:10:16 -04:00
parent 6cf5a7744e
commit f7d63f88fa
3 changed files with 35 additions and 8 deletions
+16 -3
View File
@@ -937,13 +937,26 @@ namespace MobileGL::MG_State {
}
void GLContext::BindProgramPipelineObject(Uint index) {
if (index != 0 && m_programPipelines.find(index) == m_programPipelines.end()) {
// First bind is what turns a reserved name into an object.
m_programPipelines[index] = MakeShared<ProgramPipelineObject>(index);
if (index != 0) {
MaterializeProgramPipelineObject(index);
}
m_boundProgramPipeline = index;
}
// Binding is not the only thing that turns a reserved name into an object. GL 4.6 core
// 7.4 asks of UseProgramStages, ActiveShaderProgram and ValidateProgramPipeline only that
// the name came from GenProgramPipelines and has not been deleted - so a name that was
// reserved and never bound must take state from them, not be rejected. glIsProgramPipeline
// is the one place the distinction survives (it answers FALSE until the name is used),
// which is why IsProgramPipelineObject stays as it is.
const SharedPtr<ProgramPipelineObject>& GLContext::MaterializeProgramPipelineObject(Uint index) {
static const SharedPtr<ProgramPipelineObject> kNone;
if (index == 0 || !m_programPipelineNames.IsValid(index)) return kNone;
const auto it = m_programPipelines.find(index);
if (it != m_programPipelines.end()) return it->second;
return m_programPipelines[index] = MakeShared<ProgramPipelineObject>(index);
}
void GLContext::MarkProgramPipelineForDeletion(Uint index) {
if (index == 0 || !m_programPipelineNames.IsValid(index)) return;
if (index == m_boundProgramPipeline) {
+5 -1
View File
@@ -172,12 +172,16 @@ namespace MobileGL {
// Program pipeline (GL_ARB_separate_shader_objects, GL 4.6 core 7.4). Like queries
// and transform feedbacks, glGenProgramPipelines only RESERVES a name - the object
// appears on first bind - while glCreateProgramPipelines makes it immediately.
// appears on first USE (any of bind, UseProgramStages, ActiveShaderProgram,
// ValidateProgramPipeline) - while glCreateProgramPipelines makes it immediately.
void GenProgramPipelineNames(Uint number, Vector<Uint>& pipelines);
void CreateProgramPipelineObject(Uint index);
Bool ValidateProgramPipelineName(Uint index) const;
Bool IsProgramPipelineObject(Uint index) const;
void BindProgramPipelineObject(Uint index);
// Materializes a reserved name; returns null for 0 or a name that is not a live
// GenProgramPipelines name.
const SharedPtr<ProgramPipelineObject>& MaterializeProgramPipelineObject(Uint index);
void MarkProgramPipelineForDeletion(Uint index);
const SharedPtr<ProgramPipelineObject>& GetProgramPipelineObject(Uint index) const;
Uint GetBoundProgramPipelineName() const { return m_boundProgramPipeline; }