From 252e59334dc21c547e394abdde845f399e53242f Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 22 Jun 2026 12:30:10 +0800 Subject: [PATCH] [Fix] (trace-replay): pass ANGLE path to APK retrace --- .../MG_Util/BackendLoaders/OpenGL/Loader.cpp | 31 ++++++++++++++++--- android-plugin/TRACE_REPLAY.md | 3 +- .../app/src/trace/cpp/trace_replay_core.cpp | 7 +++++ .../app/src/trace/cpp/trace_replay_core.hpp | 1 + .../app/src/trace/cpp/trace_replay_jni.cpp | 2 ++ .../plugin/trace/TraceReplayActivity.java | 9 +++++- 6 files changed, 47 insertions(+), 6 deletions(-) diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index edbb87ee..7def518c 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -15,6 +15,19 @@ namespace MobileGL::MG_Util::BackendLoader { return value != nullptr && std::strcmp(value, "1") == 0; } + static Vector AngleLibNames(const char* name) { + const char* angleDir = std::getenv("MOBILEGL_RETRACE_ANGLE_DIR"); + if (angleDir != nullptr && angleDir[0] != '\0') { + String path = angleDir; + if (!path.empty() && path.back() != '/') { + path += "/"; + } + path += name; + return {path, name}; + } + return {name}; + } + static void* OpenLib(const Vector& names) { #if !defined(__WIN32) && !defined(_WIN32) && !defined(__APPLE__) static const String LibPathPrefixes[] = { @@ -30,6 +43,7 @@ namespace MobileGL::MG_Util::BackendLoader { for (const auto& name : names) { String path_name = prefix + name; if ((lib = dlopen(path_name.c_str(), flags))) { + MGLOG_I("Loaded GL backend library: %s", path_name.c_str()); return lib; } } @@ -438,13 +452,22 @@ namespace MobileGL::MG_Util::BackendLoader { } void AcquireEGLFunctions(MG_External::EGLFunctionsTable& funcs) { - Vector eglLibNames = {"libEGL.so"}; + void* eglLib = nullptr; if (UseRetraceAngle()) { - OpenLib({"libGLESv2_angle.so"}); - eglLibNames = {"libEGL_angle.so", "libEGL.so"}; + void* glesLib = OpenLib(AngleLibNames("libGLESv2_angle.so")); + if (!glesLib) { + MGLOG_E("Failed to open ANGLE libGLESv2_angle.so"); + return; + } + eglLib = OpenLib(AngleLibNames("libEGL_angle.so")); + if (!eglLib) { + MGLOG_E("Failed to open ANGLE libEGL_angle.so"); + return; + } + } else { + eglLib = OpenLib({"libEGL.so"}); } - void* eglLib = OpenLib(eglLibNames); if (!eglLib) { MGLOG_E("Failed to open EGL library"); return; diff --git a/android-plugin/TRACE_REPLAY.md b/android-plugin/TRACE_REPLAY.md index 20710993..3f0f16f2 100644 --- a/android-plugin/TRACE_REPLAY.md +++ b/android-plugin/TRACE_REPLAY.md @@ -39,6 +39,7 @@ crop_y optional compare crop y crop_width optional compare crop width crop_height optional compare crop height use_angle optional boolean; DirectGLES uses packaged ANGLE when true +angle_library_dir optional directory containing libEGL_angle.so and libGLESv2_angle.so; defaults to the APK native library directory ``` Implementation notes: @@ -49,7 +50,7 @@ Implementation notes: - `DirectGLES` replays on an EGL pbuffer by default, avoiding Android `SurfaceView` lifetime coupling. `DirectVulkan` still uses the Activity surface because it needs a native window-backed Vulkan swapchain. - Golden comparison is implemented in native C++ with libpng RGBA decode. 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. The APK must include `libEGL_angle.so` and `libGLESv2_angle.so` under its x86_64 native libraries. +- Set `MOBILEGL_RETRACE_USE_ANGLE=1` when running `trace-replay-ci.sh` to pass `use_angle=true` for DirectGLES. 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`. 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 997f73c1..ee880586 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.cpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.cpp @@ -129,6 +129,12 @@ bool LoadMobileGL(const Request& request, std::string& error) { setenv("MOBILEGL_TRACE_SKIP_AUTODESTROY", "1", 1); if (UseAngleForRequest(request)) { setenv("MOBILEGL_RETRACE_USE_ANGLE", "1", 1); + if (!request.angleLibraryDir.empty()) { + setenv("MOBILEGL_RETRACE_ANGLE_DIR", request.angleLibraryDir.c_str(), 1); + } + } else { + unsetenv("MOBILEGL_RETRACE_USE_ANGLE"); + unsetenv("MOBILEGL_RETRACE_ANGLE_DIR"); } void* handle = dlopen(request.mobileGlLibrary.c_str(), RTLD_NOW | RTLD_GLOBAL); @@ -738,6 +744,7 @@ bool WriteResultJson(const Request& request, const Result& result) { file << " \"actualPath\": \"" << JsonEscape(result.actualPath) << "\",\n"; file << " \"diffPath\": \"" << JsonEscape(result.diffPath) << "\",\n"; file << " \"backend\": \"" << JsonEscape(request.backend) << "\",\n"; + file << " \"angleLibraryDir\": \"" << JsonEscape(request.angleLibraryDir) << "\",\n"; file << " \"targetFrame\": " << request.targetFrame << ",\n"; file << " \"targetCall\": " << request.targetCall << ",\n"; file << " \"width\": " << request.width << ",\n"; diff --git a/android-plugin/app/src/trace/cpp/trace_replay_core.hpp b/android-plugin/app/src/trace/cpp/trace_replay_core.hpp index 5e9dc843..39f1db67 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.hpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.hpp @@ -23,6 +23,7 @@ struct Request { std::string diffPath; std::string backend; std::string mobileGlLibrary = "libMobileGL.so"; + std::string angleLibraryDir; int targetFrame = -1; long long targetCall = -1; int width = 0; diff --git a/android-plugin/app/src/trace/cpp/trace_replay_jni.cpp b/android-plugin/app/src/trace/cpp/trace_replay_jni.cpp index 7cecdf90..cd73d964 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_jni.cpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_jni.cpp @@ -99,6 +99,7 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv* jint cropWidth, jint cropHeight, jint fuzzPercent, + jstring angleLibraryDir, jboolean useAngle) { mobilegl_trace::Request request; request.tracePath = ToString(env, tracePath); @@ -110,6 +111,7 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv* request.outputDir = ToString(env, outputDir); request.diffPath = ToString(env, diffPath); request.backend = ToString(env, backend); + request.angleLibraryDir = ToString(env, angleLibraryDir); request.targetFrame = targetFrame; request.targetCall = targetCall; request.width = width; diff --git a/android-plugin/app/src/trace/java/top/mobilegl/plugin/trace/TraceReplayActivity.java b/android-plugin/app/src/trace/java/top/mobilegl/plugin/trace/TraceReplayActivity.java index 6464b71f..54bc8e91 100644 --- a/android-plugin/app/src/trace/java/top/mobilegl/plugin/trace/TraceReplayActivity.java +++ b/android-plugin/app/src/trace/java/top/mobilegl/plugin/trace/TraceReplayActivity.java @@ -44,6 +44,7 @@ public final class TraceReplayActivity extends Activity { request = TraceReplayRequest.from( intent, getFilesDir(), + getApplicationInfo().nativeLibraryDir, getString(top.mobilegl.plugin.R.string.mobilegl_default_backend) ); statusView = new TextView(this); @@ -111,6 +112,7 @@ public final class TraceReplayActivity extends Activity { request.cropWidth, request.cropHeight, request.fuzzPercent, + request.angleLibraryDir, request.useAngle ); Log.i(TAG, result.toString()); @@ -139,6 +141,7 @@ public final class TraceReplayActivity extends Activity { int cropWidth, int cropHeight, int fuzzPercent, + String angleLibraryDir, boolean useAngle ); @@ -159,6 +162,7 @@ public final class TraceReplayActivity extends Activity { final int cropWidth; final int cropHeight; final int fuzzPercent; + final String angleLibraryDir; final boolean useAngle; private TraceReplayRequest( @@ -178,6 +182,7 @@ public final class TraceReplayActivity extends Activity { int cropWidth, int cropHeight, int fuzzPercent, + String angleLibraryDir, boolean useAngle ) { this.tracePath = tracePath; @@ -196,10 +201,11 @@ public final class TraceReplayActivity extends Activity { this.cropWidth = cropWidth; this.cropHeight = cropHeight; this.fuzzPercent = fuzzPercent; + this.angleLibraryDir = angleLibraryDir; this.useAngle = useAngle; } - static TraceReplayRequest from(Intent intent, File filesDir, String defaultBackend) { + static TraceReplayRequest from(Intent intent, File filesDir, String nativeLibraryDir, String defaultBackend) { String outputDir = readString(intent, "output_dir", new File(filesDir, "trace-replay").getAbsolutePath()); String diffPath = readString(intent, "diff_path", ""); return new TraceReplayRequest( @@ -219,6 +225,7 @@ public final class TraceReplayActivity extends Activity { intent.getIntExtra("crop_width", 0), intent.getIntExtra("crop_height", 0), intent.getIntExtra("fuzz_percent", 20), + readString(intent, "angle_library_dir", nativeLibraryDir), intent.getBooleanExtra("use_angle", false) ); }