diff --git a/MobileGL/Config.h b/MobileGL/Config.h index 8e9962f0..a6ab2850 100644 --- a/MobileGL/Config.h +++ b/MobileGL/Config.h @@ -316,6 +316,37 @@ namespace MobileGL::MG_Config { // immune to the probe's verdict moving), and ForceOff is the negative control that // replays the driver's silence. QuirkOverride MagmaPrimGenQueryReroute = QuirkOverride::Auto; + // --- MGPipe (the disaggregation plan's explicit frontend/backend boundary) --- + // MOBILEGL_PIPE_PUSH: per-subsystem bitmask selecting which state the frontend + // PUSHES over MGPipe instead of leaving the backend to pull it out of GLContext. + // 0 - the default and the only shipped value until the migration lands - is "pull + // everything", i.e. exactly today's behaviour. One bit of it also turns OFF + // client-side content addressing of CSOs, which is the negative control the CSO + // design is measured against. Accepts decimal or 0x-prefixed hex. + Uint64 PipePush = 0; + // MOBILEGL_PIPE_VERIFY: per-draw, per-FIELD shadow comparison of the pushed state + // against a snapshot taken from GLContext the old way, printing the first field + // that differs and the draw serial. Roughly 5-10x slower and never shipped; it is + // the semantic gate that replaces byte identity, and it catches the dangerous + // direction - a dirty bit that fires too RARELY - which no purity gate can see. + Bool PipeVerify = false; + // MOBILEGL_PIPE_STATS: dump the boundary counters (bytes, calls, roundtrips, + // texture pulls, upload shapes, residual-block bytes, index mirror bytes). + Bool PipeStats = false; + // MOBILEGL_PIPE_LEGACY_MEMOS: keep the pre-handle registries and TwinLookupMemos + // alive so the first handle waves have a real old-versus-new arm to be compared + // against. ON by default for the whole migration window, deleted with the pull + // path itself. + Bool PipeLegacyMemos = true; + // MOBILEGL_PIPE_TEXEL_RETAIN_MB: LRU budget for texels retained against a + // server-initiated texture re-send. Default 0, i.e. OFF: MipmapStorage already + // holds a complete CPU shadow, so this cache buys latency, never correctness. + Uint32 PipeTexelRetainMb = 0; + // MOBILEGL_PIPE_INDEX_MIRROR_MB: budget for the server-side index host mirror, + // which is what lets primitive-restart rewriting and multi-draw flattening stay on + // the server without shipping index bytes per draw. Over budget it degrades to + // per-draw staging, counted separately in the stats. + Uint32 PipeIndexMirrorMb = 64; }; extern FeaturesTable Features; } // namespace MobileGL::MG_Config diff --git a/MobileGL/ConfigLoader.cpp b/MobileGL/ConfigLoader.cpp index 47809384..b760b144 100644 --- a/MobileGL/ConfigLoader.cpp +++ b/MobileGL/ConfigLoader.cpp @@ -159,6 +159,28 @@ namespace MobileGL::MG_ConfigLoader { return static_cast(parsedValue); } + // Same contract as QueryEnvUint32, over 64 bits and accepting a 0x prefix: the one + // consumer is a subsystem BITMASK, and a bitmask written in decimal is unreadable. + inline Uint64 QueryEnvUint64(const String& key, Uint64 defaultValue) { + auto it = acceptedEnvVariablesMap->find(key); + if (it == acceptedEnvVariablesMap->end()) { + return defaultValue; + } + + const String& value = it->second; + char* parseEnd = nullptr; + errno = 0; + const unsigned long long parsedValue = std::strtoull(value.c_str(), &parseEnd, 0); + if (parseEnd == value.c_str() || *parseEnd != '\0' || errno == ERANGE) { + MGLOG_W("Config: Ignoring invalid env variable %s='%s'; expected an integer (decimal or " + "0x-prefixed), using default %llu", + key.c_str(), value.c_str(), static_cast(defaultValue)); + return defaultValue; + } + + return static_cast(parsedValue); + } + inline void InitFeatures() { auto& features = MG_Config::Features; features.DisableTimerQuery = QueryEnvFlag("MOBILEGL_DISABLE_TIMERQUERY"); @@ -207,6 +229,19 @@ namespace MobileGL::MG_ConfigLoader { features.EsprytWidenPacked16Storage = QueryEnvQuirkOverride("MOBILEGL_ESPRYT_WIDEN_PACKED16_STORAGE"); features.MagmaPrimGenQueryReroute = QueryEnvQuirkOverride("MOBILEGL_MAGMA_PRIMGEN_QUERY_REROUTE"); + // MGPipe. Nothing here needs adding to an allow-list: InitializeAcceptedEnvVariables + // accepts every MOBILEGL_ / LIBGL_ prefixed variable in the environment, so a name + // that starts with MOBILEGL_ is visible to these queries by construction. + features.PipePush = QueryEnvUint64("MOBILEGL_PIPE_PUSH", 0); + features.PipeVerify = QueryEnvFlag("MOBILEGL_PIPE_VERIFY"); + features.PipeStats = QueryEnvFlag("MOBILEGL_PIPE_STATS"); + // Defaults ON, so the flag has to be read as a tri-state rather than as a plain + // truthy check: unset must keep the memos, and only an explicitly falsy value may + // drop them. + features.PipeLegacyMemos = + QueryEnvQuirkOverride("MOBILEGL_PIPE_LEGACY_MEMOS") != MG_Config::QuirkOverride::ForceOff; + features.PipeTexelRetainMb = QueryEnvUint32("MOBILEGL_PIPE_TEXEL_RETAIN_MB", 0, 0, 4096); + features.PipeIndexMirrorMb = QueryEnvUint32("MOBILEGL_PIPE_INDEX_MIRROR_MB", 64, 0, 4096); } inline void InitBackendType() {