[Fix] (MG_Impl/GLImpl): stop double-recording GL errors for a bad program handle

glBindFragDataLocation, glGetFragDataLocation and glGetFragDataIndex each
recorded a redundant GL_INVALID_OPERATION on top of the error that
TryToGetProgramObject already recorded (GL_INVALID_VALUE for an unknown
name, GL_INVALID_OPERATION for a non-program object). One bad call thus
queued two errors, so an app calling glGetError twice saw a spurious
second error, and any following code that expects a clean error queue
(e.g. a later test) picked up the stale one.

Drop the second RecordError from all three call sites and rely on the
single error TryToGetProgramObject already reports -- matching the clean
`if (!programObject) return;` pattern the rest of GL_Program.cpp uses. The
first, app-visible error is unchanged; only the redundant second is gone.

ProgramTest's invalid-handle case now asserts exactly one error (mutation-
verified: reintroducing the second record fails it) and keeps a defensive
error-queue drain. ProgramTest 24/24.
This commit is contained in:
2026-07-11 00:19:33 -04:00
parent 9ffcb23877
commit bebe534bad
2 changed files with 9 additions and 23 deletions
+5 -21
View File
@@ -1485,13 +1485,9 @@ namespace MobileGL::MG_Impl::GLImpl {
void BindFragDataLocation_State(GLuint program, GLuint colorNumber, const char* name) {
auto& programObject = TryToGetProgramObject(program);
if (programObject == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " is not the name of a program object."));
return;
}
// TryToGetProgramObject already recorded the error for a bad handle (GL_INVALID_VALUE for an
// unknown name, GL_INVALID_OPERATION for a non-program object); do not record a second one.
if (!programObject) return;
if (name == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
@@ -1520,13 +1516,7 @@ namespace MobileGL::MG_Impl::GLImpl {
GLint GetFragDataLocation_State(GLuint program, const char* name) {
auto& programObject = TryToGetProgramObject(program);
if (programObject == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " is not the name of a program object."));
return -1;
}
if (!programObject) return -1; // TryToGetProgramObject already recorded the error.
if (name == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
@@ -1545,13 +1535,7 @@ namespace MobileGL::MG_Impl::GLImpl {
GLint GetFragDataIndex_State(GLuint program, const char* name) {
auto& programObject = TryToGetProgramObject(program);
if (programObject == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " is not the name of a program object."));
return -1;
}
if (!programObject) return -1; // TryToGetProgramObject already recorded the error.
if (name == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
+4 -2
View File
@@ -1564,8 +1564,10 @@ TEST_F(ProgramTest, GetFragDataIndexRejectsInvalidProgram) {
// routes through the shared program-name check, which records GL_INVALID_VALUE for an unknown name.
EXPECT_EQ(GetFragDataIndex(999999u, "fragColor"), -1);
EXPECT_EQ(GetError(), GL_INVALID_VALUE);
// The name check and the entry point each queue an error for an unknown handle; drain the rest so
// no stale error leaks into a later test (the fixture does not reset the error queue).
// Exactly ONE error is recorded per bad call: the redundant second GL_INVALID_OPERATION that the
// FragData entry points used to queue on top of the name check has been removed.
EXPECT_EQ(GetError(), GL_NO_ERROR);
// Defensive drain: keep the shared error queue clean regardless (the fixture never resets it).
while (GetError() != GL_NO_ERROR) {}
}