From 18c1a4d5864a8365fad211c6a54374cfd421da2c Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Wed, 5 Aug 2026 00:36:53 -0400 Subject: [PATCH] [Feat] (MG_Impl): implement the query getters that write into a buffer object glGetQueryBufferObjectiv and its three siblings were stubs. They are the ordinary query getters with the destination changed from client memory to a buffer object, so everything about the query itself - the name, whether it is still active, the parameter - is already answered by the shared GetQueryObjectValue, including the errors it raises. What was left is the destination: a negative offset is INVALID_VALUE, a name that is not a buffer object is INVALID_OPERATION, and so is a write that would run past the end of the buffer. The four differ only in the width they store, so they share one template. direct_state_access.queries_errors passes on both backends, putting the group at 4 of 5. queries_functional now reaches further into the test and ends in an unrelated InternalError rather than a plain failure. --- .../MG_Impl/GLImpl/Exporting/Definitions.cpp | 8 +-- MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp | 56 +++++++++++++++++++ MobileGL/MG_Impl/GLImpl/Query/GL_Query.h | 4 ++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index 4ef984f6..ddac51ef 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -1098,10 +1098,10 @@ DECLARE_GL_FUNCTION_HEAD(void, GetVertexArrayIndexed64iv, GLuint vaobj, GLuint i 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_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) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset) +DECLARE_GL_FUNCTION_HEAD(void, GetQueryBufferObjecti64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetQueryBufferObjecti64v, id, buffer, pname, offset) +DECLARE_GL_FUNCTION_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset) +DECLARE_GL_FUNCTION_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset) +DECLARE_GL_FUNCTION_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset) DECLARE_GL_FUNCTION_HEAD(void, GetTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnCompressedTexImage, GLenum target, GLint lod, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnCompressedTexImage, target, lod, bufSize, pixels) diff --git a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp index 1889823c..e3cfaaf3 100644 --- a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp +++ b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.cpp @@ -62,6 +62,34 @@ namespace MobileGL::MG_Impl::GLImpl { MakeUnique("MG_Impl/GLImpl", function, message)); } + // The by-buffer query getters write the result into a buffer object instead of client + // memory. Everything about the query itself - the name, whether it is still active, the + // parameter - is checked by GetQueryObjectValue; what is left is the destination, so this + // resolves the buffer and confirms the write lands inside it (GL 4.6 core 4.2.1). + Bool ResolveQueryResultDestination(GLuint buffer, GLintptr offset, SizeT writeSize, const char* function, + SharedPtr& outBuffer) { + if (offset < 0) { + RecordQueryError(ErrorCode::InvalidValue, function, "Offset cannot be negative."); + return false; + } + if (!MG_State::pGLContext->ValidateBufferObject(buffer)) { + RecordQueryError(ErrorCode::InvalidOperation, function, "Buffer object does not exist."); + return false; + } + auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + if (!bufferObject) { + RecordQueryError(ErrorCode::InvalidOperation, function, "Buffer object does not exist."); + return false; + } + if (static_cast(offset) + writeSize > bufferObject->GetSize()) { + RecordQueryError(ErrorCode::InvalidOperation, function, + "The query result does not fit in the buffer object at this offset."); + return false; + } + outBuffer = bufferObject; + return true; + } + // Callers must hold g_queryObjectsMutex. QueryObject* FindQueryObjectLocked(GLuint id) { const auto it = g_liveQueryObjects.find(id); @@ -160,6 +188,18 @@ namespace MobileGL::MG_Impl::GLImpl { return false; } } + + template + void GetQueryBufferObject(GLuint id, GLuint buffer, GLenum pname, GLintptr offset, const char* function) { + SharedPtr bufferObject; + if (!ResolveQueryResultDestination(buffer, offset, sizeof(T), function, bufferObject)) return; + + Uint64 value = 0; + if (!GetQueryObjectValue(id, pname, function, value)) return; + + const T narrowed = static_cast(value); + bufferObject->UploadSubData({const_cast(&narrowed), sizeof(T)}, static_cast(offset)); + } } // namespace void GenQueries(GLsizei n, GLuint* ids) { @@ -475,6 +515,22 @@ namespace MobileGL::MG_Impl::GLImpl { } } + void GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname, GLintptr offset) { + GetQueryBufferObject(id, buffer, pname, offset, __FUNCTION__); + } + + void GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname, GLintptr offset) { + GetQueryBufferObject(id, buffer, pname, offset, __FUNCTION__); + } + + void GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname, GLintptr offset) { + GetQueryBufferObject(id, buffer, pname, offset, __FUNCTION__); + } + + void GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname, GLintptr offset) { + GetQueryBufferObject(id, buffer, pname, offset, __FUNCTION__); + } + void GetQueryObjectiv(GLuint id, GLenum pname, GLint* params) { Uint64 value = 0; if (!GetQueryObjectValue(id, pname, __FUNCTION__, value) || !params) { diff --git a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h index 35d79214..b85dfb5e 100644 --- a/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h +++ b/MobileGL/MG_Impl/GLImpl/Query/GL_Query.h @@ -24,5 +24,9 @@ namespace MobileGL::MG_Impl::GLImpl { void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params); void GetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params); void GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params); + void GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); + void GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); + void GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); + void GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); void QueryCounter(GLuint id, GLenum target); } // namespace MobileGL::MG_Impl::GLImpl