mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[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:
@@ -19,16 +19,26 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
code, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", function, Move(message)));
|
code, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", function, Move(message)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A pipeline name only names an object once it has been bound or created; querying a
|
// GL 4.6 core 7.4 asks only that the name came from GenProgramPipelines and has not been
|
||||||
// reserved-but-unmaterialised name is INVALID_OPERATION (GL 4.6 core 7.4).
|
// deleted - so a name that was reserved and never bound is legal here, and the command
|
||||||
|
// MATERIALIZES it rather than rejecting it.
|
||||||
|
//
|
||||||
|
// Requiring a bound object instead is what broke every separable-program conformance case
|
||||||
|
// across three families: the CTS reserves a name, calls glUseProgramStages three times and
|
||||||
|
// only then binds, which is the order the spec's own example uses. Each of those calls
|
||||||
|
// failed with INVALID_OPERATION, so the stage programs were never recorded - the pipeline
|
||||||
|
// stayed empty, GetProgramForDraw flattened nothing and the draw painted nothing, and the
|
||||||
|
// rejected calls' error was left in the queue for the harness to find. One cause, both
|
||||||
|
// symptoms.
|
||||||
const SharedPtr<MG_State::GLState::ProgramPipelineObject>* TryGetPipeline(GLuint pipeline,
|
const SharedPtr<MG_State::GLState::ProgramPipelineObject>* TryGetPipeline(GLuint pipeline,
|
||||||
const char* function) {
|
const char* function) {
|
||||||
if (!MG_State::pGLContext->IsProgramPipelineObject(pipeline)) {
|
const auto& object = MG_State::pGLContext->MaterializeProgramPipelineObject(pipeline);
|
||||||
|
if (!object) {
|
||||||
RecordPipelineError(ErrorCode::InvalidOperation, function,
|
RecordPipelineError(ErrorCode::InvalidOperation, function,
|
||||||
std::format("Program pipeline {} does not exist.", pipeline));
|
std::format("Program pipeline {} does not exist.", pipeline));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &MG_State::pGLContext->GetProgramPipelineObject(pipeline);
|
return &object;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool ValidatePipelineCount(GLsizei n, const char* function) {
|
Bool ValidatePipelineCount(GLsizei n, const char* function) {
|
||||||
|
|||||||
@@ -937,13 +937,26 @@ namespace MobileGL::MG_State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GLContext::BindProgramPipelineObject(Uint index) {
|
void GLContext::BindProgramPipelineObject(Uint index) {
|
||||||
if (index != 0 && m_programPipelines.find(index) == m_programPipelines.end()) {
|
if (index != 0) {
|
||||||
// First bind is what turns a reserved name into an object.
|
MaterializeProgramPipelineObject(index);
|
||||||
m_programPipelines[index] = MakeShared<ProgramPipelineObject>(index);
|
|
||||||
}
|
}
|
||||||
m_boundProgramPipeline = 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) {
|
void GLContext::MarkProgramPipelineForDeletion(Uint index) {
|
||||||
if (index == 0 || !m_programPipelineNames.IsValid(index)) return;
|
if (index == 0 || !m_programPipelineNames.IsValid(index)) return;
|
||||||
if (index == m_boundProgramPipeline) {
|
if (index == m_boundProgramPipeline) {
|
||||||
|
|||||||
@@ -172,12 +172,16 @@ namespace MobileGL {
|
|||||||
|
|
||||||
// Program pipeline (GL_ARB_separate_shader_objects, GL 4.6 core 7.4). Like queries
|
// 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
|
// 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 GenProgramPipelineNames(Uint number, Vector<Uint>& pipelines);
|
||||||
void CreateProgramPipelineObject(Uint index);
|
void CreateProgramPipelineObject(Uint index);
|
||||||
Bool ValidateProgramPipelineName(Uint index) const;
|
Bool ValidateProgramPipelineName(Uint index) const;
|
||||||
Bool IsProgramPipelineObject(Uint index) const;
|
Bool IsProgramPipelineObject(Uint index) const;
|
||||||
void BindProgramPipelineObject(Uint index);
|
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);
|
void MarkProgramPipelineForDeletion(Uint index);
|
||||||
const SharedPtr<ProgramPipelineObject>& GetProgramPipelineObject(Uint index) const;
|
const SharedPtr<ProgramPipelineObject>& GetProgramPipelineObject(Uint index) const;
|
||||||
Uint GetBoundProgramPipelineName() const { return m_boundProgramPipeline; }
|
Uint GetBoundProgramPipelineName() const { return m_boundProgramPipeline; }
|
||||||
|
|||||||
Reference in New Issue
Block a user