[Refactor] (MG_Config): centralize env-var and driver-feature reads

MG_Config::FeaturesTable snapshots every MOBILEGL_* toggle once in
ConfigLoader::Init with a single truthy rule (non-empty, not '0', not
'false' case-insensitively), replacing 13 scattered std::getenv sites
that used four different parsing conventions. Renderer-derived bits
(IsAngleRenderer/IsAngleLlvmpipeRenderer/AvoidSamplerMipmapMinFilter)
move into GLESCapabilities, set once in FillInGLESCapabilities, so hot
paths (glMemoryBarrier ANGLE flush, sampler min-filter sync) stop doing
per-call string scans. MOBILEGL_PRESENT_DUMP_CALL/_CURRENT_CALL stay
live getenv (the retrace harness mutates them at runtime) and
MOBILEGL_LOG_FILE_PATH stays in Log.cpp (log init precedes config
init); both are documented in Config.h. Known semantic unification:
MOBILEGL_DISABLE_SUBGROUP previously required exactly 'true' and
MOBILEGL_PRESENT_STATS exactly '1'; both now follow the shared rule
(CI's 0/1 values parse identically). Also bumps CoreVersion to 26.07.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 01:08:06 +00:00
co-authored by Claude Fable 5
parent 096d6f591b
commit 7d31a6fcd7
7 changed files with 97 additions and 15 deletions
+44 -1
View File
@@ -14,9 +14,52 @@ 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, 6, 0, "-dev", VersionType::Development};
inline const Version CoreVersion = {26, 7, 0, "-dev", VersionType::Development};
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
inline const Uint64 CacheVersion = 0;
extern BackendType ActiveBackendType;
// 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):
// - MOBILEGL_PRESENT_DUMP_CALL / MOBILEGL_PRESENT_CURRENT_CALL: the retrace harness
// mutates them at runtime via setenv, so a one-shot snapshot would go stale.
// - 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_RETRACE_USE_ANGLE: load ANGLE EGL/GLES libraries for retrace runs.
Bool RetraceUseAngle = false;
// MOBILEGL_RETRACE_ANGLE_DIR: directory searched first for the ANGLE libraries.
String RetraceAngleDir;
// MOBILEGL_DISABLE_SUBGROUP: force-disable Vulkan shader subgroup support.
Bool DisableSubgroup = false;
// MOBILEGL_VULKAN_R11G11B10F_FALLBACK: use fallback format for R11G11B10F on Vulkan.
Bool VulkanR11G11B10FFallback = false;
// MOBILEGL_GLES_PRESENT_STATS: log present pixel statistics (DirectGLES backend).
Bool GlesPresentStats = false;
// MOBILEGL_ANGLE_LLVMPIPE_AVOID_SAMPLER_MIPMAP_MIN_FILTER: avoid mipmap min
// filters in samplers on ANGLE/llvmpipe renderers.
Bool AvoidAngleLlvmpipeSamplerMipmapMinFilter = false;
// MOBILEGL_DESCRIPTOR_STATS: log descriptor binding statistics (DirectVulkan).
Bool DescriptorStats = false;
// MOBILEGL_TEXTURE_UPLOAD_STATS: log texture upload statistics (DirectVulkan).
Bool TextureUploadStats = false;
// MOBILEGL_VERTEX_INPUT_STATS: log vertex input statistics (DirectVulkan).
Bool VertexInputStats = false;
// MOBILEGL_PRESENT_DUMP_PATH: directory for present frame dumps (DirectVulkan).
String PresentDumpPath;
// MOBILEGL_PRESENT_STATS: log present pixel statistics (DirectVulkan backend).
Bool PresentStats = false;
// MOBILEGL_TRACE_SKIP_AUTODESTROY: skip teardown in the ELF destructor (Init.cpp).
Bool TraceSkipAutodestroy = false;
};
extern FeaturesTable Features;
} // namespace MobileGL::MG_Config
+42
View File
@@ -12,6 +12,12 @@
extern char** environ;
#endif
namespace MobileGL::MG_Config {
// Zero/default-initialized at static-init time (all fields have constexpr-friendly
// defaults), so it is safe to read even if MG_ConfigLoader::Init has not run yet.
FeaturesTable Features;
} // namespace MobileGL::MG_Config
namespace MobileGL::MG_ConfigLoader {
static UniquePtr<UnorderedMap<String, String>> acceptedEnvVariablesMap;
@@ -60,6 +66,41 @@ namespace MobileGL::MG_ConfigLoader {
}
}
// Unified truthy rule for boolean feature env variables: set, non-empty, not "0",
// and not "false" (case-insensitive).
static Bool IsTruthyValue(const String& value) {
if (value.empty() || value == "0") {
return false;
}
String lowered = value;
std::transform(lowered.begin(), lowered.end(), lowered.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return lowered != "false";
}
inline Bool QueryEnvFlag(const String& key) {
auto it = acceptedEnvVariablesMap->find(key);
return it != acceptedEnvVariablesMap->end() && IsTruthyValue(it->second);
}
inline void InitFeatures() {
auto& features = MG_Config::Features;
features.DisableTimerQuery = QueryEnvFlag("MOBILEGL_DISABLE_TIMERQUERY");
features.RetraceUseAngle = QueryEnvFlag("MOBILEGL_RETRACE_USE_ANGLE");
QueryEnvVariable("MOBILEGL_RETRACE_ANGLE_DIR", features.RetraceAngleDir, "");
features.DisableSubgroup = QueryEnvFlag("MOBILEGL_DISABLE_SUBGROUP");
features.VulkanR11G11B10FFallback = QueryEnvFlag("MOBILEGL_VULKAN_R11G11B10F_FALLBACK");
features.GlesPresentStats = QueryEnvFlag("MOBILEGL_GLES_PRESENT_STATS");
features.AvoidAngleLlvmpipeSamplerMipmapMinFilter =
QueryEnvFlag("MOBILEGL_ANGLE_LLVMPIPE_AVOID_SAMPLER_MIPMAP_MIN_FILTER");
features.DescriptorStats = QueryEnvFlag("MOBILEGL_DESCRIPTOR_STATS");
features.TextureUploadStats = QueryEnvFlag("MOBILEGL_TEXTURE_UPLOAD_STATS");
features.VertexInputStats = QueryEnvFlag("MOBILEGL_VERTEX_INPUT_STATS");
QueryEnvVariable("MOBILEGL_PRESENT_DUMP_PATH", features.PresentDumpPath, "");
features.PresentStats = QueryEnvFlag("MOBILEGL_PRESENT_STATS");
features.TraceSkipAutodestroy = QueryEnvFlag("MOBILEGL_TRACE_SKIP_AUTODESTROY");
}
inline void InitBackendType() {
String backendTypeStr;
QueryEnvVariable("MOBILEGL_BACKEND_TYPE", backendTypeStr, "DirectGLES");
@@ -81,6 +122,7 @@ namespace MobileGL::MG_ConfigLoader {
InitializeAcceptedEnvVariables();
InitBackendType();
InitFeatures();
// Destroy the map since we won't need it anymore
acceptedEnvVariablesMap.reset();
+1 -2
View File
@@ -13,7 +13,6 @@
#include <MG_State/EGLState/Core.h>
#include <MG_Impl/GLImpl/Texture/ProxyTexture.h>
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
#include <cstdlib>
namespace MobileGL {
namespace {
@@ -75,7 +74,7 @@ namespace MobileGL {
}
__attribute__((destructor)) static void AutoDestroy() {
if (std::getenv("MOBILEGL_TRACE_SKIP_AUTODESTROY") != nullptr) {
if (MG_Config::Features.TraceSkipAutodestroy) {
return;
}
#if defined(__APPLE__)
+5 -4
View File
@@ -41,13 +41,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
constexpr const char* ZERO_BASED_INSTANCE_ID_NAME = "mg_ZeroBasedInstanceID";
static Bool IsAngleLlvmpipeRenderer() {
return g_GLESCapabilities.GLESRendererString.find("ANGLE") != String::npos &&
g_GLESCapabilities.GLESRendererString.find("llvmpipe") != String::npos;
return g_GLESCapabilities.IsAngleLlvmpipeRenderer;
}
static Bool ShouldAvoidSamplerMipmapMinFilterOnAngleLlvmpipe() {
const char* value = std::getenv("MOBILEGL_ANGLE_LLVMPIPE_AVOID_SAMPLER_MIPMAP_MIN_FILTER");
return value != nullptr && std::strcmp(value, "1") == 0 && IsAngleLlvmpipeRenderer();
// IsAngleLlvmpipeRenderer combined with the
// MOBILEGL_ANGLE_LLVMPIPE_AVOID_SAMPLER_MIPMAP_MIN_FILTER feature toggle,
// both resolved in FillInGLESCapabilities.
return g_GLESCapabilities.AvoidSamplerMipmapMinFilter;
}
static GLenum ResolveBackendMinFilter(const SamplerParameters& samplerParams,
+1 -1
View File
@@ -23,7 +23,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace {
Flags<PixelFormatNormalizeOptionBit> GetForcedPixelFormatNormalizeOptions() {
Flags<PixelFormatNormalizeOptionBit> options;
if (g_GLESCapabilities.GLESRendererString.find("ANGLE") != String::npos) {
if (g_GLESCapabilities.IsAngleRenderer) {
options |= PixelFormatNormalizeOptionBit::NoRgb16;
options |= PixelFormatNormalizeOptionBit::NoSnorm16;
options |= PixelFormatNormalizeOptionBit::NoSnorm8;
@@ -8,8 +8,7 @@
#include "Loader.h"
#include <cstdlib>
#include <cstring>
#include <Config.h>
namespace MobileGL::MG_Util::BackendLoader {
namespace {
@@ -61,11 +60,7 @@ namespace MobileGL::MG_Util::BackendLoader {
}
Bool IsShaderSubgroupForcedDisabled() {
const char* value = std::getenv("MOBILEGL_DISABLE_SUBGROUP");
if (!value) {
return false;
}
return std::strcmp(value, "true") == 0 || std::strcmp(value, "TRUE") == 0;
return MG_Config::Features.DisableSubgroup;
}
} // namespace
+2
View File
@@ -63,6 +63,8 @@ namespace MobileGL {
void InitFile() {
#if MOBILEGL_LOG_ENABLE_FILE
if (!s_logFile) {
// MOBILEGL_LOG_FILE_PATH must stay a raw getenv (not MG_Config::Features):
// InitFile() runs before MG_ConfigLoader::Init() in MobileGL::Initialize().
const char* logPath = std::getenv("MOBILEGL_LOG_FILE_PATH");
if (!logPath || !*logPath) {
logPath = MOBILEGL_LOG_FILE_PATH;