From ae418e80a0762df3c79eb38b87e4b0417715fc73 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 20 Sep 2026 20:50:11 -0400 Subject: [PATCH] [MG_Backend] (DirectGLES): the client snapshot's baseInstance shift is the emulated one The element set a divisor'd client array fetches starts at GL's raw baseInstance, but the pointer shift that carries it belongs to this backend's emulation: when the driver applies baseInstance itself (UseNativeBaseInstance), EmulatedFetchBaseInstance answers 0 and shifting the pointer as well would move the fetch twice - instance 0 read element 2 instead of element 1, and the instance that used element 1 read past the snapshot and vanished. Also drops the two 'continue' statements the indirect executors' lambdas cannot carry (a lambda is not a loop; 'return' leaves the pass). --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 7c594fe6..94130347 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -2504,7 +2504,11 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Pipe::MGPipeClientFetchPlan plan; if (!plan.Build(inputs, &ReadClientSnapshotBytes, &sources)) return false; - return twin->SyncClientSideAttributesForDraw(currentVAO, plan, baseInstance); + // The element SET is GL's: a divisor'd array's instance elements start at the raw + // 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)); } // The indirect executors' form: the command's own words ARE the draw's fetch, and a @@ -8436,7 +8440,7 @@ namespace MobileGL::MG_Backend::DirectGLES { ForEachViewportRoutingPass([&] { if (!VertexArrayImpl::SyncClientSideVertexArraysForIndirectFetch( commandBytes, commandOffset, stride, i, static_cast(indexSize), drawIndirectBuffer)) - continue; + return; g_GLESFuncs.glDrawElementsInstancedBaseVertex( mode, static_cast(cmd.count), type, reinterpret_cast(indexByteOffset), static_cast(cmd.instanceCount), cmd.baseVertex); @@ -8518,7 +8522,7 @@ namespace MobileGL::MG_Backend::DirectGLES { ForEachViewportRoutingPass([&] { if (!VertexArrayImpl::SyncClientSideVertexArraysForIndirectFetch( commandBytes, commandOffset, stride, i, 0, drawIndirectBuffer)) - continue; + return; g_GLESFuncs.glDrawArraysInstanced(mode, static_cast(cmd.first), static_cast(cmd.count), static_cast(cmd.instanceCount));