[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.
This commit is contained in:
BZLZHH
2026-08-05 00:01:20 -04:00
parent 95a7b17d45
commit bd710078fc
3 changed files with 47 additions and 1 deletions
@@ -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<SizeT>(offset), static_cast<SizeT>(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<GenericErrorInfo>("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<SizeT>(offset) + static_cast<SizeT>(size) > bufferObject->GetSize()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("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<SizeT>(offset), static_cast<SizeT>(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);
}