From bd710078fce23307b927d949607506523df1f82b Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Wed, 5 Aug 2026 00:01:20 -0400 Subject: [PATCH] [Feat] (MG_Impl): implement glGetNamedBufferSubData The by-name read was a stub, so it left the caller's buffer untouched and a test comparing it against a reference saw whatever that memory already held. Its by-target sibling glGetBufferSubData was already implemented, so this is that function with the buffer resolved by name instead of through a binding: the same non-negative offset and size check, the same bound-by-the-buffer's-size check, the same refusal to read a buffer mapped without GL_MAP_PERSISTENT_BIT, and the same SyncGpuWrites before the download so a GPU-side write that has not landed yet is not missed. Resolving by name reports INVALID_OPERATION for a name that is not a buffer, which the by-target form expresses as "target is bound to no buffer object" instead. direct_state_access.buffers_get_named_buffer_subdata passes on both backends. --- MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp | 45 +++++++++++++++++++ MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h | 1 + .../MG_Impl/GLImpl/Exporting/Definitions.cpp | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp index e9f0136a..15f28580 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp @@ -38,6 +38,7 @@ namespace MobileGL::MG_Impl::GLImpl { GetNamedBufferParameteriv, GetNamedBufferParameteri64v, GetNamedBufferPointerv, + GetNamedBufferSubData, }; const char* GetBufferOpName(BufferOp op) { @@ -76,6 +77,8 @@ namespace MobileGL::MG_Impl::GLImpl { return "UnmapNamedBuffer"; case BufferOp::FlushMappedNamedBufferRange: return "FlushMappedNamedBufferRange"; + case BufferOp::GetNamedBufferSubData: + return "GetNamedBufferSubData"; case BufferOp::GetNamedBufferParameteriv: return "GetNamedBufferParameteriv"; case BufferOp::GetNamedBufferParameteri64v: @@ -891,6 +894,44 @@ namespace MobileGL::MG_Impl::GLImpl { bufferObject->DownloadSubData(data, static_cast(offset), static_cast(size)); } + void GetNamedBufferSubData_State(GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) { + if (!data) { + // Match GetBufferSubData_State: a null pointer is a caller bug, not a GL-specified error. + return; + } + + if (size < 0 || offset < 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "GetNamedBufferSubData_State", + "Offset and size must be non-negative.")); + return; + } + + auto bufferObject = GetNamedBufferObject(buffer, BufferOp::GetNamedBufferSubData); + if (!bufferObject) return; + + if (static_cast(offset) + static_cast(size) > bufferObject->GetSize()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", "GetNamedBufferSubData_State", + "Offset and size exceed buffer size.")); + return; + } + + if (bufferObject->IsMapped() && + !(bufferObject->GetMappingAccess() & BufferMappingAccessBit::Persistent)) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", "GetNamedBufferSubData_State", + "Cannot read from a buffer object mapped without GL_MAP_PERSISTENT_BIT.")); + return; + } + + bufferObject->SyncGpuWrites(); + bufferObject->DownloadSubData(data, static_cast(offset), static_cast(size)); + } + void BufferData_State(GLenum target, GLsizeiptr size, const void* data, GLenum usage) { MGLOG_D("%s: %s, size = %d, data = %p, usage = %s", __func__, MG_Util::ConvertGLEnumToString(target).c_str(), size, data, MG_Util::ConvertGLEnumToString(usage).c_str()); @@ -1553,6 +1594,10 @@ namespace MobileGL::MG_Impl::GLImpl { BufferSubData_State(target, offset, size, data); } + void GetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) { + GetNamedBufferSubData_State(buffer, offset, size, data); + } + void GetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void* data) { GetBufferSubData_State(target, offset, size, data); } diff --git a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h index a408189c..3a24dfc2 100644 --- a/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h +++ b/MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.h @@ -41,6 +41,7 @@ namespace MobileGL::MG_Impl::GLImpl { GLsizeiptr size); void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); void GetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void* data); + void GetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, void* data); void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage); void BindBuffer(GLenum target, GLuint buffer); void GenBuffers(GLsizei n, GLuint* buffers); diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index f8c36028..97798a54 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -1025,7 +1025,7 @@ DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLint DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params) -DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data) +DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param)