[Feat] (MG_Impl, MG_Backend, MG_State): implement glMultiDrawArrays and glGetBufferSubData

Two previously-stubbed GL 3.3 Core entry points.

glMultiDrawArrays: mirrors the existing glMultiDrawElements(BaseVertex)
architecture end to end -- a new MultiDrawArrays backend function-table
slot dispatched from the frontend after program/primitive-mode validation
(plus a drawcount < 0 -> GL_INVALID_VALUE guard).
- DirectGLES: PrepareForDraw once, then loop native glDrawArrays with the
  same per-range client-side array upload the single DrawArrays does.
- DirectVulkan: build a MultiDrawCmd payload and hand it to a new
  VulkanRenderer::MultiDrawArrays, which does one SetupDraw over the union
  of the sub-draw vertex ranges and then a vkCmdDraw per range (mirrors
  VulkanRenderer::MultiDrawElements).

glGetBufferSubData: reads a range of the bound buffer's CPU shadow into
client memory via a new BufferObject::DownloadSubData, with the same
validation shape as BufferSubData (INVALID_VALUE for negative/overflowing
range, INVALID_OPERATION for no bound buffer or a non-persistent mapped
buffer). The shadow reflects CPU writes and backend write-backs but not
arbitrary GPU-side writes, which is documented on the method.

Tests: 2 BufferTest cases for glGetBufferSubData (round-trip read of a
middle range and the whole buffer, plus out-of-range/negative/no-buffer
errors). BufferTest 32/32, SanityTest 30/30, VertexArrayTest 42/42;
library builds clean. (The glMultiDrawArrays draw paths are not
runtime-testable on this host and are compile-verified against the tested
MultiDrawElements pattern.)
This commit is contained in:
2026-07-10 23:46:14 -04:00
parent 4dd2b2216c
commit dc3c2cc5c7
17 changed files with 217 additions and 2 deletions
@@ -1363,6 +1363,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glDrawElementsBaseVertex(mode, count, type, indices, basevertex);
}
void MultiDrawArrays(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__);
#endif
DrawSyncBit syncBit = DrawSyncBit::None;
PrepareForDraw(syncBit);
const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray();
for (GLsizei i = 0; i < drawcount; ++i) {
// Client-side arrays are uploaded per sub-draw range, like the single DrawArrays path.
if (currentVAO) {
const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO.get());
if (backendVAOIt != VertexArrayImpl::g_backendVertexArrayObjects.end()) {
backendVAOIt->second->SyncClientSideAttributesForDrawArrays(currentVAO, first[i], count[i]);
}
}
g_GLESFuncs.glDrawArrays(mode, first[i], count[i]);
}
}
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER