From ff76af9df7d62a982c0f4ca2028cea5ff6778541 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Tue, 4 Aug 2026 10:27:23 -0400 Subject: [PATCH] [Fix] (MG_State, MG_Impl): a transform feedback name is only an object once it is bound glIsTransformFeedback answered GL_TRUE for any name glGenTransformFeedbacks had handed out. A generated name is reserved but does not denote an object until the first glBindTransformFeedback (GL 4.6 core 13.2.1) - the same rule the other object types follow - and KHR-GL40.api.coverage checks exactly the window in between. The two questions are now asked separately: whether a name may be bound or deleted (reserved, which is what the delete and bind paths need) and whether it is an object (reserved and bound at least once). --- MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp | 5 +++-- MobileGL/MG_State/GLState/Core.cpp | 7 +++++++ MobileGL/MG_State/GLState/Core.h | 4 ++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp index 50686af3..35abb221 100644 --- a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp +++ b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp @@ -909,8 +909,9 @@ namespace MobileGL::MG_Impl::GLImpl { } GLboolean IsTransformFeedback(GLuint id) { - // Name 0 is the default object, which glIsTransformFeedback reports as not an object. - return (id != 0 && MG_State::pGLContext->ValidateTransformFeedbackName(id)) ? GL_TRUE : GL_FALSE; + // Name 0 is the default object, and a name glGenTransformFeedbacks handed out only + // becomes the name of an object once it has been bound. + return MG_State::pGLContext->IsTransformFeedbackObject(id) ? GL_TRUE : GL_FALSE; } // glDrawTransformFeedback[Stream][Instanced]: replays the vertices the named object diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index edb7eb74..f4738080 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -798,9 +798,16 @@ namespace MobileGL::MG_State { if (index == m_boundTransformFeedback) return; SaveBoundTransformFeedbackState(); m_boundTransformFeedback = index; + m_transformFeedbackObjects[index].everBound = true; RestoreBoundTransformFeedbackState(); } + Bool GLContext::IsTransformFeedbackObject(Uint index) const { + if (index == 0 || !m_transformFeedbackNames.IsValid(index)) return false; + const auto it = m_transformFeedbackObjects.find(index); + return it != m_transformFeedbackObjects.end() && it->second.everBound; + } + void GLContext::MarkTransformFeedbackObjectForDeletion(Uint index) { if (index == 0 || !m_transformFeedbackNames.IsValid(index)) return; // Deleting the bound object reverts to the default one (GL 4.6 core 13.2.1); diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index 376aa799..0961f850 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -274,6 +274,9 @@ namespace MobileGL { // A name glGenTransformFeedbacks handed out and glDeleteTransformFeedbacks // has not taken back. Name 0 is always valid. Bool ValidateTransformFeedbackName(Uint index) const; + // What glIsTransformFeedback reports: a generated name only becomes the name + // of an object once it has been bound at least once (GL 4.6 core 13.2.1). + Bool IsTransformFeedbackObject(Uint index) const; void BindTransformFeedbackObject(Uint index); void MarkTransformFeedbackObjectForDeletion(Uint index); Uint GetBoundTransformFeedbackName() const { return m_boundTransformFeedback; } @@ -344,6 +347,7 @@ namespace MobileGL { Uint64 inputPrimitives = 0; Uint64 recordedVertices = 0; Bool hasCompletedSpan = false; + Bool everBound = false; }; void SaveBoundTransformFeedbackState(); void RestoreBoundTransformFeedbackState();