From 533219ede7d83e913011b9fd163942e1150fd27f Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 13 Jul 2026 21:20:02 -0400 Subject: [PATCH] [Fix] (Retrace): load ANGLE through LD_LIBRARY_PATH --- .github/workflows/apk.yml | 2 +- MobileGL/Config.h | 6 ++--- MobileGL/ConfigLoader.cpp | 3 +-- .../MG_Util/BackendLoaders/OpenGL/Loader.cpp | 25 +++++-------------- android-plugin/TRACE_REPLAY.md | 2 +- .../app/src/trace/cpp/trace_replay_core.cpp | 23 +++++++++++++---- android-plugin/trace-replay-ci.sh | 4 +-- .../trace_replay/run_android_retrace_local.py | 4 +-- .../skills/trace-fixture-authoring.md | 2 +- 9 files changed, 34 insertions(+), 37 deletions(-) diff --git a/.github/workflows/apk.yml b/.github/workflows/apk.yml index a626d752..9b4092dd 100644 --- a/.github/workflows/apk.yml +++ b/.github/workflows/apk.yml @@ -336,7 +336,7 @@ jobs: - name: Retrace and validate env: - MOBILEGL_RETRACE_USE_ANGLE: ${{ matrix.backend.name == 'DirectGLES' && '1' || '0' }} + MOBILEGL_USE_ANGLE: ${{ matrix.backend.name == 'DirectGLES' && '1' || '0' }} MOBILEGL_MAGMA_R11G11B10F_FALLBACK: ${{ matrix.backend.name == 'DirectVulkan' && '1' || '0' }} run: | apk_file="$(find android-retrace-apks -name '${{ matrix.backend.apk }}' -print -quit)" diff --git a/MobileGL/Config.h b/MobileGL/Config.h index 0de4c3ca..5933c14a 100644 --- a/MobileGL/Config.h +++ b/MobileGL/Config.h @@ -35,10 +35,8 @@ namespace MobileGL::MG_Config { 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_USE_ANGLE: load ANGLE EGL/GLES libraries. + Bool UseAngle = false; // MOBILEGL_DISABLE_SUBGROUP: force-disable Vulkan shader subgroup support. Bool DisableSubgroup = false; // MOBILEGL_MAGMA_R11G11B10F_FALLBACK: use fallback format for R11G11B10F on Vulkan. diff --git a/MobileGL/ConfigLoader.cpp b/MobileGL/ConfigLoader.cpp index 3b58eb39..f2de7fe7 100644 --- a/MobileGL/ConfigLoader.cpp +++ b/MobileGL/ConfigLoader.cpp @@ -110,8 +110,7 @@ namespace MobileGL::MG_ConfigLoader { 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.UseAngle = QueryEnvFlag("MOBILEGL_USE_ANGLE"); features.DisableSubgroup = QueryEnvFlag("MOBILEGL_DISABLE_SUBGROUP"); features.MagmaR11G11B10FFallback = QueryEnvFlag("MOBILEGL_MAGMA_R11G11B10F_FALLBACK"); features.MagmaFramesInFlight = QueryEnvUint32("MOBILEGL_MAGMA_FRAMESINFLIGHT", 3, 1, 64); diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index d1009636..ec46fbbd 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -14,21 +14,8 @@ #endif namespace MobileGL::MG_Util::BackendLoader { - static Bool UseRetraceAngle() { - return MG_Config::Features.RetraceUseAngle; - } - - static Vector AngleLibNames(const char* name) { - const String& angleDir = MG_Config::Features.RetraceAngleDir; - if (!angleDir.empty()) { - String path = angleDir; - if (path.back() != '/') { - path += "/"; - } - path += name; - return {path, name}; - } - return {name}; + static Bool UseAngle() { + return MG_Config::Features.UseAngle; } static void* OpenLib(const Vector& names) { @@ -40,7 +27,7 @@ namespace MobileGL::MG_Util::BackendLoader { "/opt/vc/lib/", "/usr/local/lib/", "/usr/lib/", "/usr/lib/x86_64-linux-gnu/", "/usr/lib64/", "/lib64/", #endif - "" // We should put this to the end of the list to avoid breaking `LD_LIBRARY_PATH` usage + "" // Keep this last so the dynamic loader can use LD_LIBRARY_PATH. }; void* lib = nullptr; @@ -473,13 +460,13 @@ namespace MobileGL::MG_Util::BackendLoader { void AcquireEGLFunctions(MG_External::EGLFunctionsTable& funcs) { void* eglLib = nullptr; - if (UseRetraceAngle()) { - void* glesLib = OpenLib(AngleLibNames("libGLESv2_angle.so")); + if (UseAngle()) { + void* glesLib = OpenLib({"libGLESv2_angle.so"}); if (!glesLib) { MGLOG_E("Failed to open ANGLE libGLESv2_angle.so"); return; } - eglLib = OpenLib(AngleLibNames("libEGL_angle.so")); + eglLib = OpenLib({"libEGL_angle.so"}); if (!eglLib) { MGLOG_E("Failed to open ANGLE libEGL_angle.so"); return; diff --git a/android-plugin/TRACE_REPLAY.md b/android-plugin/TRACE_REPLAY.md index 923ce085..d0df5356 100644 --- a/android-plugin/TRACE_REPLAY.md +++ b/android-plugin/TRACE_REPLAY.md @@ -50,7 +50,7 @@ Implementation notes: - `DirectGLES` and `DirectVulkan` replay on the Activity `SurfaceView` by default. DirectGLES can still use the old offscreen EGL pbuffer path by passing `use_pbuffer=true`. - Golden comparison is implemented in native C++ with libpng RGBA decode and SSIM validation. The Java Activity only passes arguments and displays the native result, so the replay/compare core is not tied to Android UI or Bitmap APIs and can be ported to Linux. - The plugin profile still excludes `libtrace_replay_runner.so`; normal plugin APK behavior is preserved. -- Set `MOBILEGL_RETRACE_USE_ANGLE=1` when running `trace-replay-ci.sh` to pass `use_angle=true` for DirectGLES. Set `MOBILEGL_RETRACE_USE_PBUFFER=1` or pass `--use-pbuffer` to keep DirectGLES offscreen. The APK must include `libEGL_angle.so` and `libGLESv2_angle.so` under its x86_64 native libraries. The Activity passes Android's `nativeLibraryDir` to native code as `MOBILEGL_RETRACE_ANGLE_DIR`. +- Set `MOBILEGL_USE_ANGLE=1` when running `trace-replay-ci.sh` to pass `use_angle=true` for DirectGLES. Set `MOBILEGL_RETRACE_USE_PBUFFER=1` or pass `--use-pbuffer` to keep DirectGLES offscreen. The APK must include `libEGL_angle.so` and `libGLESv2_angle.so` under its x86_64 native libraries. The native runner prepends the ANGLE directory to `LD_LIBRARY_PATH` before loading MobileGL. Example core-profile trace smoke command for a debug trace APK: diff --git a/android-plugin/app/src/trace/cpp/trace_replay_core.cpp b/android-plugin/app/src/trace/cpp/trace_replay_core.cpp index f974f673..ed3bd464 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.cpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.cpp @@ -88,10 +88,24 @@ bool UseAngleForRequest(const Request& request) { if (request.useAngle) { return true; } - const char* value = getenv("MOBILEGL_RETRACE_USE_ANGLE"); + const char* value = getenv("MOBILEGL_USE_ANGLE"); return value != nullptr && strcmp(value, "1") == 0; } +void PrependLibraryPath(const std::string& directory) { + if (directory.empty()) { + return; + } + + const char* current = getenv("LD_LIBRARY_PATH"); + std::string value = directory; + if (current != nullptr && current[0] != '\0') { + value += ":"; + value += current; + } + setenv("LD_LIBRARY_PATH", value.c_str(), 1); +} + bool EnsureDirectory(const std::string& path) { if (path.empty()) { return false; @@ -141,13 +155,12 @@ bool LoadMobileGL(const Request& request, std::string& error) { unsetenv("MOBILEGL_MAGMA_R11G11B10F_FALLBACK"); } if (UseAngleForRequest(request)) { - setenv("MOBILEGL_RETRACE_USE_ANGLE", "1", 1); + setenv("MOBILEGL_USE_ANGLE", "1", 1); if (!request.angleLibraryDir.empty()) { - setenv("MOBILEGL_RETRACE_ANGLE_DIR", request.angleLibraryDir.c_str(), 1); + PrependLibraryPath(request.angleLibraryDir); } } else { - unsetenv("MOBILEGL_RETRACE_USE_ANGLE"); - unsetenv("MOBILEGL_RETRACE_ANGLE_DIR"); + unsetenv("MOBILEGL_USE_ANGLE"); } if (request.avoidAngleLlvmpipeSamplerMipmapMinFilter) { setenv("MOBILEGL_AVOID_SAMPLER_MIPMAP_MIN_FILTER", "1", 1); diff --git a/android-plugin/trace-replay-ci.sh b/android-plugin/trace-replay-ci.sh index f9604305..224fb2ff 100644 --- a/android-plugin/trace-replay-ci.sh +++ b/android-plugin/trace-replay-ci.sh @@ -31,7 +31,7 @@ Usage: [--avoid-angle-llvmpipe-sampler-mipmap-min-filter] \ --timeout-seconds N -Set MOBILEGL_RETRACE_USE_ANGLE=1 to run DirectGLES replay with packaged ANGLE +Set MOBILEGL_USE_ANGLE=1 to run DirectGLES replay with packaged ANGLE instead of the device system GLES driver. Set MOBILEGL_RETRACE_USE_PBUFFER=1 or pass --use-pbuffer to run DirectGLES against an offscreen EGL pbuffer instead of the Activity surface. @@ -245,7 +245,7 @@ run_retrace() { if [ -n "${alternate_golden_path}" ]; then alternate_golden_app_path="${app_dir}/input/alternate-golden.png" fi - if [ "${MOBILEGL_RETRACE_USE_ANGLE:-}" = "1" ] && [ "${backend}" = "DirectGLES" ]; then + if [ "${MOBILEGL_USE_ANGLE:-}" = "1" ] && [ "${backend}" = "DirectGLES" ]; then use_angle=1 fi if [ "${MOBILEGL_RETRACE_USE_PBUFFER:-}" = "1" ] && [ "${backend}" = "DirectGLES" ]; then diff --git a/tools/trace_replay/run_android_retrace_local.py b/tools/trace_replay/run_android_retrace_local.py index dc5c1d62..705ce596 100644 --- a/tools/trace_replay/run_android_retrace_local.py +++ b/tools/trace_replay/run_android_retrace_local.py @@ -172,9 +172,9 @@ def run_case(case, backend): env["PYTHON"] = "python" env["MSYS2_ARG_CONV_EXCL"] = "/data/*" if backend_info["use_angle"]: - env["MOBILEGL_RETRACE_USE_ANGLE"] = "1" + env["MOBILEGL_USE_ANGLE"] = "1" else: - env.pop("MOBILEGL_RETRACE_USE_ANGLE", None) + env.pop("MOBILEGL_USE_ANGLE", None) result = subprocess.run(command, cwd=ROOT, env=env) copy_goldens(case, backend) return result.returncode diff --git a/tools/trace_replay/skills/trace-fixture-authoring.md b/tools/trace_replay/skills/trace-fixture-authoring.md index 804869b0..f8f46c64 100644 --- a/tools/trace_replay/skills/trace-fixture-authoring.md +++ b/tools/trace_replay/skills/trace-fixture-authoring.md @@ -375,7 +375,7 @@ device or emulator has a trace package from a different keystore, uninstall or the install fails with `INSTALL_FAILED_UPDATE_INCOMPATIBLE`. Match the CI environment (`.github/workflows/apk.yml` matrix): the emulator -boots with `--gpu software` + `MOBILEGL_RETRACE_USE_ANGLE=1` for `DirectGLES` +boots with `--gpu software` + `MOBILEGL_USE_ANGLE=1` for `DirectGLES` and `--gpu lavapipe` + `MOBILEGL_MAGMA_R11G11B10F_FALLBACK=1` for `DirectVulkan`. The emulator's ANGLE-on-Vulkan GLES stack exercises genuinely different driver semantics than physical devices (e.g. indirect-draw