diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index 7f0c8a23..6e0128b0 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -932,6 +932,9 @@ namespace MobileGL::MG_Util::BackendLoader { if (std::strcmp(extension, "GL_EXT_clip_cull_distance") == 0) { caps.SupportsClipDistance = true; } + if (std::strcmp(extension, "GL_OES_viewport_array") == 0) { + caps.SupportsViewportArray = true; + } } } // The pointer check on top of the extension check makes each flag sufficient on its own @@ -989,6 +992,8 @@ namespace MobileGL::MG_Util::BackendLoader { MGLOG_I(" base instance (EXT_base_instance; emulated by attribute offsets when absent): %s", caps.SupportsBaseInstance ? "yes" : "no"); MGLOG_I(" clip distances (EXT_clip_cull_distance): %s", caps.SupportsClipDistance ? "yes" : "no"); + MGLOG_I(" viewport array (OES_viewport_array; gl_ViewportIndex collapses to viewport 0 when absent): %s", + caps.SupportsViewportArray ? "yes" : "no"); // LOAD-BEARING STRING, not just a banner. android-plugin/trace-replay-ci.sh's // is_angle_surface_lost() greps mobilegl.log for exactly "OpenGL ES capabilities:" to diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h index 64f6cef2..2d986489 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h @@ -1182,6 +1182,21 @@ namespace MobileGL { // compile and the per-distance enables have nowhere to go - clipping silently never // happens, which is exactly what KHR-GLxx.clip_distance.functional catches. Bool SupportsClipDistance = false; + // GL_OES_viewport_array is present: the driver knows gl_ViewportIndex in ESSL - and + // only then. ESSL has no core spelling for it at ANY version, while SPIRV-Cross prints + // the identifier bare and requests nothing for it (contrast gl_Layer, which it backs + // with GL_NV_viewport_array2 on ES), so the `#extension GL_OES_viewport_array : + // require` line has to be inserted into the emitted source - see + // RequestViewportArrayExtension. Without the extension the stage does not compile at + // all and the whole program becomes unusable, which on DirectGLES means every draw + // using it silently renders nothing; LowerViewportIndexPass is the fallback that + // demotes the builtin so the program still links and degrades to viewport 0. + // + // Extension string only, deliberately: DirectGLES does not call any of the indexed + // OES entry points yet, so there is no pointer to require. When that forwarding lands + // this must gain the pointer check as well - the rule everywhere else in this struct, + // because eglGetProcAddress can hand back a stub that silently drops every call. + Bool SupportsViewportArray = false; // GL_RENDERER contains "ANGLE". Bool IsAngleRenderer = false; // GL_RENDERER contains both "ANGLE" and "llvmpipe".