mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-13 06:38:31 +09:00
iterationRP's Program 203 declares shared vec2 prefixSumCache[32] for a 512-invocation workgroup indexed by gl_SubgroupID; any device narrower than 16 lanes partitions into more than 32 subgroups and the pack writes shared memory out of bounds (heap corruption on lavapipe's CPU rasterizer, ssim 0.028 on the CI retrace). Fix it where the fault lies - in the fixture - and keep the GL contract sound everywhere else: - FixIterationRPSubgroupScratchPass: fingerprint-gated SPIR-V pass that grows exactly that array to ceil(invocations/width) entries on sub-16-lane devices; every other module passes through byte-identical. - DeriveNumSubgroupsPass stays default-on for the Adreno topology bug and is made spec-sound: pipelines request REQUIRE_FULL_SUBGROUPS whenever the workgroup shape makes the flag legal (computeFullSubgroups enabled, local_size_x a multiple of the native width, subgroup count within maxComputeWorkgroupSubgroups). - EmulateSubgroupsPass: 32-lane virtual-subgroup lowering kept in-tree as a last resort, enabled only by MOBILEGL_MAGMA_EMULATE_SUBGROUP=1 on devices with no native subgroup support; fails closed on extended subgroup instructions and on modules whose added scratch would exceed maxComputeSharedMemorySize. - IterationRPFirstReductionScenario skips gracefully outside the pack's 16..256-lane source domain; the new IterationRPScratchFixScenario runs the fixture-shaped reduction on any width and asserts the exact width-independent total. DriverPost keeps reporting FAIL on out-of-domain devices. - Program203 -> IterationRP rename throughout; the per-trace num_subgroups_quirk plumbing is removed from the trace replayer, JNI chain, and CI workflows.
205 lines
14 KiB
C++
205 lines
14 KiB
C++
// MobileGL - MobileGL/Config.h
|
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
// Licensed under the GNU Lesser General Public License v3.0:
|
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
// End of Source File Header
|
|
|
|
#pragma once
|
|
#include <Includes.h>
|
|
#include <MG_Backend/BackendObjects.h>
|
|
|
|
namespace MobileGL::MG_Config {
|
|
inline const String ProjectName = "MobileGL";
|
|
inline const String CoreName = "MobileGL Core";
|
|
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
|
|
inline const Version CoreVersion = {26, 8, 0, "-dev", VersionType::Development};
|
|
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
|
|
inline const Uint64 CacheVersion = 0;
|
|
|
|
extern BackendType ActiveBackendType;
|
|
|
|
// Tri-state override for device-specific quirks: Auto lets the detected device decide,
|
|
// ForceOn/ForceOff bypass the detection in either direction. ForceOn only bypasses the
|
|
// device gate - each quirk keeps its structural safety checks.
|
|
enum class QuirkOverride : Uint8 {
|
|
Auto = 0,
|
|
ForceOn,
|
|
ForceOff,
|
|
};
|
|
|
|
// Preferred DirectVulkan dispatch tier for the glMultiDraw* families. A preference,
|
|
// never a demand: the renderer clamps it to what the device supports at device
|
|
// creation, falling down the chain ext -> indirect -> unroll with one log line.
|
|
enum class MultiDrawMode : Uint8 {
|
|
Auto = 0, // unset: best supported tier
|
|
Ext, // VK_EXT_multi_draw: one vkCmdDrawMultiEXT / vkCmdDrawMultiIndexedEXT
|
|
Indirect, // multiDrawIndirect feature: one vkCmdDraw*Indirect over a transient command array
|
|
Unroll, // one vkCmdDraw* per sub-draw
|
|
};
|
|
|
|
// Preferred DirectGLES emulation tier for glMultiDrawElements(BaseVertex). GLES has no
|
|
// such entry point in core, so every tier below is an emulation; they differ only in
|
|
// which driver capability they lean on and how many driver calls a batch costs. Like
|
|
// the Magma knob this is a preference, clamped at resolution time to what the ES
|
|
// driver actually supports, with one log line when it falls back.
|
|
enum class GLESMultiDrawMode : Uint8 {
|
|
Auto = 0, // unset: best supported tier
|
|
Ext, // one glMultiDrawElementsBaseVertexEXT
|
|
MultiIndirect, // one glMultiDrawElementsIndirectEXT over a scratch command buffer
|
|
Indirect, // one glDrawElementsIndirect per sub-draw over that same buffer
|
|
BaseVertex, // one glDrawElementsBaseVertex per sub-draw
|
|
DrawElements, // baseVertex folded into a scratch index buffer on the CPU, then plain
|
|
// glDrawElements per sub-draw (for drivers with no base-vertex draw at all)
|
|
Compute, // a compute shader flattens every sub-draw into one rebased index buffer,
|
|
// drawn by a single glDrawElements
|
|
};
|
|
|
|
// Feature toggles parsed once from environment variables in MG_ConfigLoader::Init()
|
|
// (ConfigLoader.cpp), before the accepted-env map is destroyed. All Bool fields share
|
|
// one truthy rule: the variable is set, non-empty, not "0", and not "false"
|
|
// (case-insensitive).
|
|
//
|
|
// Env variables intentionally NOT mirrored here (kept as live std::getenv at their
|
|
// call sites):
|
|
// - DISPLAY: X11 session variable, not MobileGL configuration.
|
|
// - MOBILEGL_LOG_FILE_PATH: log-file init runs before MG_ConfigLoader::Init
|
|
// (see MG_Util/Debug/Log.cpp).
|
|
struct FeaturesTable {
|
|
// MOBILEGL_DISABLE_TIMERQUERY: do not advertise or use GPU timer queries.
|
|
Bool DisableTimerQuery = false;
|
|
// MOBILEGL_ENABLE_SPIRV_VALIDATION: validate generated and transformed SPIR-V.
|
|
// Disabled by default because validation is a diagnostics-only cost.
|
|
Bool EnableSpirvValidation = false;
|
|
// MOBILEGL_USE_ANGLE: load ANGLE EGL/GLES libraries.
|
|
Bool UseAngle = false;
|
|
#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS)
|
|
// MOBILEGL_TRACE_ANGLE_VARIANT: signed trace-APK ANGLE build short hash.
|
|
String TraceAngleVariant;
|
|
#endif
|
|
// MOBILEGL_DISABLE_SUBGROUP: force-disable Vulkan shader subgroup support,
|
|
// including the opt-in emulated compute path below.
|
|
Bool DisableSubgroup = false;
|
|
// MOBILEGL_MAGMA_EMULATE_SUBGROUP: implement GL_KHR_shader_subgroup's compute
|
|
// stage on a 32-lane VIRTUAL subgroup lowered to workgroup-shared memory
|
|
// (ShaderTranspiler::EmulateSubgroupsPass). Strictly a last resort: it only ever
|
|
// engages when this flag is set AND the device has no native subgroup support at
|
|
// all - a device with real subgroup operations always uses them natively,
|
|
// whatever their width (the known iterationRP defect is patched by
|
|
// FixIterationRPSubgroupScratch below instead). Off by default.
|
|
Bool MagmaEmulateSubgroup = false;
|
|
// MOBILEGL_FIX_ITERATIONRP_SUBGROUP_SCRATCH: patch iterationRP's own bug - the
|
|
// pack declares `shared vec2 prefixSumCache[32]` for a 512-invocation exposure
|
|
// reduction and indexes it by gl_SubgroupID, so any device with sub-16-lane
|
|
// subgroups (8-lane lavapipe -> 64 subgroups) writes shared memory out of
|
|
// bounds. The pass grows that one array to what the device's topology needs and
|
|
// touches nothing else; it only rewrites modules positively matching the pack's
|
|
// reduction fingerprint (ShaderTranspiler::FixIterationRPSubgroupScratchPass),
|
|
// so every other shader passes through byte-identical - as does iterationRP
|
|
// itself on >= 16-lane devices. Auto is ON; ForceOff replays the pack's bug
|
|
// verbatim.
|
|
QuirkOverride FixIterationRPSubgroupScratch = QuirkOverride::Auto;
|
|
// MOBILEGL_DERIVE_NUM_SUBGROUPS: replace compute gl_NumSubgroups loads with
|
|
// ceil(workgroup invocations / gl_SubgroupSize) on the NATIVE subgroup path
|
|
// (ShaderTranspiler::DeriveNumSubgroupsPass). Auto is ON: GL requires
|
|
// gl_SubgroupID < gl_NumSubgroups, Adreno's builtin reports 1 while the same
|
|
// dispatch emits IDs 0..7, and the derived value is the one Vulkan guarantees
|
|
// whenever the pipeline can request REQUIRE_FULL_SUBGROUPS (which the renderer
|
|
// does whenever local_size_x is a multiple of the native width). ForceOff returns
|
|
// to the raw driver builtin.
|
|
QuirkOverride DeriveNumSubgroups = QuirkOverride::Auto;
|
|
// MOBILEGL_ADVERTISE_FP64: add GL_ARB_gpu_shader_fp64 to the advertised extension
|
|
// string. `double` in a shader always WORKS - it is narrowed to 32 bits before any
|
|
// module reaches a backend (ShaderTranspiler::DemoteFloat64Pass) - but the extension
|
|
// promises 64-bit precision, and that is the one thing the narrowing cannot deliver.
|
|
// Off by default so an application that checks the string before using doubles keeps
|
|
// its float path; on for measuring what the conformance suite makes of the demoted
|
|
// precision. See the DemoteFloat64Pass header and the "fp64" POST row.
|
|
Bool AdvertiseFp64 = false;
|
|
// MOBILEGL_MAGMA_R11G11B10F_FALLBACK: use fallback format for R11G11B10F on Vulkan.
|
|
Bool MagmaR11G11B10FFallback = false;
|
|
// MOBILEGL_MAGMA_FRAMESINFLIGHT: requested Magma frames in flight, defaulting to 3.
|
|
Uint32 MagmaFramesInFlight = 3;
|
|
// MOBILEGL_AVOID_SAMPLER_MIPMAP_MIN_FILTER: avoid mipmap min filters in samplers,
|
|
// resolves certain rendering bugs on ANGLE + llvmpipe.
|
|
Bool AvoidSamplerMipmapMinFilter = false;
|
|
// MOBILEGL_AVOID_EXPLICIT_LOD_BIAS: leave an already-explicit LOD argument alone when
|
|
// emulating GL_TEXTURE_LOD_BIAS, instead of adding the bias uniform to it. Injecting
|
|
// the uniform turns a compile-time-constant LOD into a runtime expression, which
|
|
// sends ANGLE + llvmpipe down a mip-selection path that dereferences a NULL
|
|
// descriptor and kills the process. Deviates from spec (Vulkan adds the bias to
|
|
// OpImageSampleExplicitLod), so it is an avoidance for that stack only.
|
|
Bool AvoidExplicitLodBias = false;
|
|
// MOBILEGL_COHERENT_AS_FLUSH: app-compat for engines (e.g. Flywheel) that write
|
|
// GPU-read data through persistent GL_MAP_FLUSH_EXPLICIT_BIT maps they never
|
|
// flush. Persistent FLUSH_EXPLICIT map requests are rewritten to coherent
|
|
// semantics: writes reach the backend without glFlushMappedBufferRange, and
|
|
// flush calls on rewritten maps become error-free no-ops. Non-persistent maps
|
|
// keep spec FLUSH_EXPLICIT behavior.
|
|
Bool CoherentAsFlush = false;
|
|
// MOBILEGL_TRACE_SKIP_AUTODESTROY: skip teardown in the ELF destructor (Init.cpp).
|
|
Bool TraceSkipAutodestroy = false;
|
|
// MOBILEGL_DISABLE_UBO_RING: force the DirectGLES global-UBO upload back to the
|
|
// per-draw glBufferSubData path instead of the persistent-mapped ring allocator
|
|
// (negative control / driver-bug escape hatch).
|
|
Bool DisableUboRing = false;
|
|
// MOBILEGL_ESPRYT_FORCE_DS_READBACK_EMULATION: make DirectGLES skip the native ES
|
|
// depth/stencil reads and always go through the shader-sampling emulation. Core GL
|
|
// ES has no depth or stencil readback, but some drivers accept it anyway (Mesa does,
|
|
// Adreno does not), which means the emulation is dead code on exactly the stack the
|
|
// headless suite runs on. This forces it live so the scenarios and the CTS can
|
|
// exercise the path, and gives the device an A/B lever over the same choice.
|
|
Bool EsprytForceDepthStencilReadbackEmulation = false;
|
|
// MOBILEGL_RELAXED_SEMANTICS: relax strict core-profile rules (e.g. VAO-0 draws,
|
|
// texture-name reuse after delete) even on contexts that explicitly requested a core
|
|
// profile. Without it, relaxed semantics still apply to every context that did not
|
|
// explicitly request a core profile via EGL_CONTEXT_OPENGL_PROFILE_MASK / a >=3.1
|
|
// version request.
|
|
Bool RelaxedSemantics = false;
|
|
// MOBILEGL_MAGMA_DISABLE_BLENDED_DEPTH_WRITE: overrides the DirectVulkan quirk that
|
|
// strips depth writes from accumulation-blended pipelines (MIN/MAX or additive
|
|
// ONE+ONE - the multi-pass depth-equality signature) on drivers without
|
|
// cross-pipeline vertex position invariance. Sorted-transparency "over" blends,
|
|
// gl_FragDepth writers, and fully color-masked attachments are exempt (see
|
|
// PipelineFactory::ShouldSuppressDepthWrite). Auto detects Qualcomm.
|
|
QuirkOverride MagmaDisableBlendedDepthWriteQuirk = QuirkOverride::Auto;
|
|
// MOBILEGL_DISABLE_ROBUST_BUFFER_ACCESS: leave the Vulkan robustBufferAccess device
|
|
// feature off. It is enabled by default to match GL's defined out-of-range fetch
|
|
// behavior; this escape hatch exists to measure or dodge its GPU cost on a device.
|
|
Bool DisableRobustBufferAccess = false;
|
|
// MOBILEGL_MAGMA_MULTIDRAW_MODE: preferred DirectVulkan multi-draw dispatch tier
|
|
// ("ext" | "indirect" | "unroll", see MultiDrawMode). Clamped to device support;
|
|
// unset picks the best supported tier.
|
|
MultiDrawMode MagmaMultiDrawMode = MultiDrawMode::Auto;
|
|
// MOBILEGL_ESPRYT_MULTIDRAW_MODE: preferred DirectGLES glMultiDrawElements emulation
|
|
// tier ("ext" | "multiindirect" | "indirect" | "basevertex" | "drawelements" |
|
|
// "compute", see GLESMultiDrawMode). Clamped to driver support; unset picks the best
|
|
// supported tier, which never includes "compute" - see the note on its resolution.
|
|
GLESMultiDrawMode EsprytMultiDrawMode = GLESMultiDrawMode::Auto;
|
|
// MOBILEGL_ASYNC_SHADER_COMPILE: overrides asynchronous shader compilation. Unset
|
|
// keeps the built-in default (MG_Util::Async::kAsyncShaderCompileDefault); falsy
|
|
// forces every glCompileShader/glLinkProgram to run synchronously on the calling
|
|
// thread AND withdraws GL_KHR_parallel_shader_compile, so the single switch reverts
|
|
// both the threading and the application-visible behaviour change.
|
|
QuirkOverride AsyncShaderCompile = QuirkOverride::Auto;
|
|
// MOBILEGL_ASYNC_SHADER_COMPILE_THREADS: shader-compile worker count. 0 (unset) means
|
|
// auto, which is min(4, big cores); an explicit value is honoured as given.
|
|
Uint32 AsyncShaderCompileThreads = 0;
|
|
// MOBILEGL_ASYNC_OPTIMISTIC_SHADER_STATUS: while a compile job is still in flight,
|
|
// glGetShaderiv(GL_COMPILE_STATUS) answers GL_TRUE and the shader info log reads
|
|
// empty, WITHOUT joining the job (latched per compile - see
|
|
// ShaderObject::TakeOptimisticCompileAnswer). A deliberate, bounded spec violation:
|
|
// a real failure still fails the program link with the compile log quoted. It
|
|
// exists for applications that compile hundreds of shaders serially and read the
|
|
// status right after each glCompileShader - Iris's shader-pack load - where those
|
|
// per-shader joins are what serializes the batch on its main path (Iris's gbuffer
|
|
// phase issues no program-level query between programs; program-level LINK_STATUS
|
|
// and the program info log still join truthfully, so paths that check each link
|
|
// immediately stay serial by their own construction). Off by default; never
|
|
// advertise it.
|
|
QuirkOverride AsyncOptimisticShaderStatus = QuirkOverride::Auto;
|
|
};
|
|
extern FeaturesTable Features;
|
|
} // namespace MobileGL::MG_Config
|