[MG_Backend, MG_Impl] (DirectGLES, Magma): the monolith arm's client fetch bounds

DirectGLES: the client snapshot's baseInstance shift belongs to the backend's
emulation, not to the element set. A driver that applies baseInstance itself
(UseNativeBaseInstance) must not also receive a shifted pointer - doing both
moved instance 0 from element 1 to element 2 and left the instance that reads
element 1 outside the snapshot. EmulatedFetchBaseInstance is not declared this
early in the file, so the wrapper states the same answer inline.

Magma: ResolveIndirectCommandBytes reconciles a GPU-written command block before
the callers read it. Every one of them reads the words on the CPU - the
per-command expansion, the baseInstance the shader emulation is fed, and the
range a client-memory vertex array's upload is bounded by - so a command a
compute shader wrote this frame was expanded as the poison the shadow still
held, which is no draw at all for glDrawArraysIndirect.

Magma: a client-memory INSTANCE-RATE binding is bounded by its instances
(baseInstance + (instanceCount - 1) / divisor), not by the vertex range; the
upload now covers the union of the two, which is what instances shifted off the
front of the array needed.
This commit is contained in:
2026-09-20 20:51:09 -04:00
parent ae418e80a0
commit cf7366276e
3 changed files with 35 additions and 2 deletions
@@ -2508,7 +2508,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
// baseInstance. The POINTER shift is not - it is this backend's emulation of what the
// driver does natively when it can (EmulatedFetchBaseInstance is the same answer the
// attribute walk uses), and applying both would shift the fetch twice.
return twin->SyncClientSideAttributesForDraw(currentVAO, plan, EmulatedFetchBaseInstance(baseInstance));
// EmulatedFetchBaseInstance, which is declared with the draw entry points far below:
// a native-baseInstance driver applies the shift itself, so the pointer carries none.
const Uint32 fetchBaseInstance =
g_GLESCapabilities.SupportsBaseInstance ? 0u : static_cast<Uint32>(baseInstance);
return twin->SyncClientSideAttributesForDraw(currentVAO, plan, fetchBaseInstance);
}
// The indirect executors' form: the command's own words ARE the draw's fetch, and a