From c186f5f2553172355cf0ceb83f570209c2261fb8 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Tue, 4 Aug 2026 21:07:18 -0400 Subject: [PATCH] [Feat] (MG_Impl): implement glCreateQueries and stop treating a reserved name as a query glGenQueries only reserves names; a name becomes a query object when it is first used with BeginQuery or QueryCounter (GL 4.6 core 4.2.1). MobileGL created the live object eagerly at glGenQueries time and glIsQuery reported every reserved name as an object, with a comment noting the shortcut. The registry already distinguished the two states -- a target of 0 means the name has never been used -- so glIsQuery now consults it, and a name that came from glCreateQueries carries a flag saying it is an object regardless. glCreateQueries itself was a stub. It creates the objects outright with their target already fixed, which is the whole point of the DSA form: there is no binding step to infer the target from later. --- .../MG_Impl/GLImpl/Exporting/Definitions.cpp | 2 +- MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp | 46 +++++++++++++++++-- MobileGL/MG_Impl/GLImpl/Query/GL_Query.h | 1 + 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index e3ca2e2e..df6f5c9f 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -1097,7 +1097,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIndexediv, GLuint vaobj, GLuin DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIndexed64iv, GLuint vaobj, GLuint index, GLenum pname, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIndexed64iv, vaobj, index, pname, param) DECLARE_GL_FUNCTION_HEAD(void, CreateSamplers, GLsizei n, GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateSamplers, n, samplers) DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateProgramPipelines, GLsizei n, GLuint* pipelines) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateProgramPipelines, n, pipelines) -DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateQueries, GLenum target, GLsizei n, GLuint* ids) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateQueries, target, n, ids) +DECLARE_GL_FUNCTION_HEAD(void, CreateQueries, GLenum target, GLsizei n, GLuint* ids) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateQueries, target, n, ids) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjecti64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjecti64v, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset) diff --git a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp index 1676722f..1889823c 100644 --- a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp +++ b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp @@ -23,6 +23,9 @@ namespace MobileGL::MG_Impl::GLImpl { struct QueryObject { GLuint id = 0; GLenum target = 0; // 0 = gen'd but never used with BeginQuery/QueryCounter + // glCreateQueries makes the object outright; glGenQueries only reserves the name, + // and the object appears when the name is first used (GL 4.6 core 4.2.1). + Bool created = false; MG_Backend::BackendQueryHandle backendHandle = nullptr; Bool active = false; Bool ended = false; @@ -177,6 +180,41 @@ namespace MobileGL::MG_Impl::GLImpl { } } + // glCreateQueries differs from glGenQueries in creating the objects outright, with their + // target already fixed and the rest of their state at the defaults (GL 4.6 core 4.2.1). + void CreateQueries(GLenum target, GLsizei n, GLuint* ids) { + switch (target) { + case GL_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + case GL_TIME_ELAPSED: + case GL_TIMESTAMP: + case GL_PRIMITIVES_GENERATED: + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + break; + default: + RecordQueryError(ErrorCode::InvalidEnum, __FUNCTION__, "Query target is not accepted."); + return; + } + if (n < 0) { + RecordQueryError(ErrorCode::InvalidValue, __FUNCTION__, "n cannot be negative."); + return; + } + if (!ids) { + return; + } + const std::lock_guard lock(g_queryObjectsMutex); + for (GLsizei i = 0; i < n; ++i) { + const GLuint id = g_nextQueryId++; + auto* queryObject = new QueryObject; + queryObject->id = id; + queryObject->target = target; + queryObject->created = true; + g_liveQueryObjects[id] = queryObject; + ids[i] = id; + } + } + void DeleteQueries(GLsizei n, const GLuint* ids) { if (n < 0) { RecordQueryError(ErrorCode::InvalidValue, __FUNCTION__, "n cannot be negative."); @@ -228,9 +266,11 @@ namespace MobileGL::MG_Impl::GLImpl { return GL_FALSE; } const std::lock_guard lock(g_queryObjectsMutex); - // Gen'd ids count as query objects here: the registry creates live - // objects at GenQueries time. - return FindQueryObjectLocked(id) != nullptr ? GL_TRUE : GL_FALSE; + // A name from glGenQueries is not yet a query object: it becomes one when it is first + // used with BeginQuery/QueryCounter (which is what a non-zero target records), or + // immediately if it came from glCreateQueries. + const auto* queryObject = FindQueryObjectLocked(id); + return (queryObject != nullptr && (queryObject->created || queryObject->target != 0)) ? GL_TRUE : GL_FALSE; } void BeginQuery(GLenum target, GLuint id) { diff --git a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h index 841e6443..35d79214 100644 --- a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h +++ b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h @@ -11,6 +11,7 @@ namespace MobileGL::MG_Impl::GLImpl { void GenQueries(GLsizei n, GLuint* ids); + void CreateQueries(GLenum target, GLsizei n, GLuint* ids); void DeleteQueries(GLsizei n, const GLuint* ids); GLboolean IsQuery(GLuint id); void BeginQuery(GLenum target, GLuint id);