From 2395a6ded29b4da54fde0f31ec4c601ac01e8958 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Wed, 8 Jul 2026 13:47:45 +0000 Subject: [PATCH] [Fix] (MG_Backend/DirectGLES): always use native indirect draws with a bound buffer Adreno (830) exposes no GL_EXT_base_instance, and gating the native path on it sent Flywheel's whole MDI call to the CPU loop, which reads the stale shadow instanceCount (0) and draws nothing. A non-zero reserved word is benign on mobile drivers, instanced arrays were never baseInstance-offset in the emulation anyway, and the CPU loop can never see GPU-written commands - native is strictly better. Co-Authored-By: Claude Fable 5 --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 41 ++++--------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 8c5007e7..d310a5e6 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -1042,26 +1042,16 @@ namespace MobileGL::MG_Backend::DirectGLES { // execute natively on the GPU so commands written by compute shaders (e.g. Flywheel's // culling pipeline updating instanceCount) are honored; the CPU shadow is still consulted // for the per-command baseInstance, which is CPU-authored, to feed the mg_BaseInstance - // shader emulation. Falls back to the CPU per-command loop for client-memory commands or - // when the driver cannot consume the command's baseInstance field (no GL_EXT_base_instance). + // shader emulation. Without GL_EXT_base_instance a non-zero baseInstance in the command is + // technically undefined in ES; mobile drivers ignore the reserved word, instanced-array + // fetches were never baseInstance-offset here anyway, and the CPU fallback cannot see + // GPU-written command fields at all - so native is never worse. Only client-memory + // commands take the CPU per-command loop. static void ExecuteIndexedIndirectCommands(GLenum mode, GLenum type, SizeT indexSize, const Uint8* commandBytes, SizeT commandOffset, Bool hasIndirectBuffer, GLsizei drawcount, GLsizei stride, const char* label) { - Bool useNative = hasIndirectBuffer && SupportsNativeIndirectDraws(); - if (useNative && !g_GLESCapabilities.SupportsBaseInstance) { - for (GLsizei i = 0; i < drawcount; ++i) { - DrawElementsIndirectCommand cmd{}; - std::memcpy(&cmd, commandBytes + static_cast(i) * stride, sizeof(cmd)); - if (cmd.baseInstance != 0) { - useNative = false; - MGLOG_W("%s: non-zero baseInstance without GL_EXT_base_instance, falling back to CPU " - "emulation (GPU-written command fields will not be honored)", - label); - break; - } - } - } - + (void)label; + const Bool useNative = hasIndirectBuffer && SupportsNativeIndirectDraws(); if (useNative) { for (GLsizei i = 0; i < drawcount; ++i) { DrawElementsIndirectCommand cmd{}; @@ -1093,21 +1083,8 @@ namespace MobileGL::MG_Backend::DirectGLES { static void ExecuteArraysIndirectCommands(GLenum mode, const Uint8* commandBytes, SizeT commandOffset, Bool hasIndirectBuffer, GLsizei drawcount, GLsizei stride, const char* label) { - Bool useNative = hasIndirectBuffer && SupportsNativeIndirectDraws(); - if (useNative && !g_GLESCapabilities.SupportsBaseInstance) { - for (GLsizei i = 0; i < drawcount; ++i) { - DrawArraysIndirectCommand cmd{}; - std::memcpy(&cmd, commandBytes + static_cast(i) * stride, sizeof(cmd)); - if (cmd.baseInstance != 0) { - useNative = false; - MGLOG_W("%s: non-zero baseInstance without GL_EXT_base_instance, falling back to CPU " - "emulation (GPU-written command fields will not be honored)", - label); - break; - } - } - } - + (void)label; + const Bool useNative = hasIndirectBuffer && SupportsNativeIndirectDraws(); if (useNative) { for (GLsizei i = 0; i < drawcount; ++i) { DrawArraysIndirectCommand cmd{};