diff --git a/.github/workflows/apk.yml b/.github/workflows/apk.yml index be2e0a95..bdbe32d3 100644 --- a/.github/workflows/apk.yml +++ b/.github/workflows/apk.yml @@ -75,6 +75,16 @@ jobs: SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }} SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }} + - name: Download ANGLE x86_64 libraries + run: | + angle_dir="android-plugin/app/src/trace/jniLibs/x86_64" + angle_base="https://raw.githubusercontent.com/FCL-Team/FoldCraftLauncher/main/FCLauncher/src/main/jniLibs/x86_64" + mkdir -p "${angle_dir}" + curl -L --fail --retry 3 -o "${angle_dir}/libEGL_angle.so" "${angle_base}/libEGL_angle.so" + curl -L --fail --retry 3 -o "${angle_dir}/libGLESv2_angle.so" "${angle_base}/libGLESv2_angle.so" + test -s "${angle_dir}/libEGL_angle.so" + test -s "${angle_dir}/libGLESv2_angle.so" + - name: Build retrace APKs run: gradle --no-daemon -p android-plugin :app:assembleEsprytTraceRelease :app:assembleMagmaTraceRelease -Pmobilegl.abis=all -Pmobilegl.debuggableRelease=true -Pmobilegl.logLevel=MOBILEGL_LOG_LEVEL_INFO --parallel --max-workers "$(nproc)" env: @@ -444,6 +454,8 @@ jobs: --boot-timeout 300 - name: Retrace and validate + env: + MOBILEGL_RETRACE_USE_ANGLE: ${{ matrix.backend.name == 'DirectGLES' && '1' || '0' }} run: | apk_file="$(find android-retrace-apks -name '${{ matrix.backend.apk }}' -print -quit)" timeout "$(( ${{ matrix.case.timeout_seconds }} + 300 ))" sh android-plugin/trace-replay-ci.sh \ diff --git a/.gitignore b/.gitignore index a53f2a64..6e3d096b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ MobileGL/MG*/cmake-build* /android-plugin/.gradle /android-plugin/build /android-plugin/app/build +/android-plugin/app/src/trace/jniLibs tools/trace_replay/work/ diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index 8510b59f..edbb87ee 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -10,6 +10,11 @@ #include "MG_Util/Types.h" namespace MobileGL::MG_Util::BackendLoader { + static Bool UseRetraceAngle() { + const char* value = std::getenv("MOBILEGL_RETRACE_USE_ANGLE"); + return value != nullptr && std::strcmp(value, "1") == 0; + } + static void* OpenLib(const Vector& names) { #if !defined(__WIN32) && !defined(_WIN32) && !defined(__APPLE__) static const String LibPathPrefixes[] = { @@ -433,10 +438,15 @@ namespace MobileGL::MG_Util::BackendLoader { } void AcquireEGLFunctions(MG_External::EGLFunctionsTable& funcs) { - static const Vector EGLLibNames = {"libEGL.so"}; - void* eglLib = OpenLib(EGLLibNames); + Vector eglLibNames = {"libEGL.so"}; + if (UseRetraceAngle()) { + OpenLib({"libGLESv2_angle.so"}); + eglLibNames = {"libEGL_angle.so", "libEGL.so"}; + } + + void* eglLib = OpenLib(eglLibNames); if (!eglLib) { - MGLOG_E("Failed to open libEGL.so"); + MGLOG_E("Failed to open EGL library"); return; } diff --git a/android-plugin/TRACE_REPLAY.md b/android-plugin/TRACE_REPLAY.md index cd75a8d2..20710993 100644 --- a/android-plugin/TRACE_REPLAY.md +++ b/android-plugin/TRACE_REPLAY.md @@ -38,6 +38,7 @@ crop_x optional compare crop x 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 ``` Implementation notes: @@ -48,6 +49,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. 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 d3b0392c..997f73c1 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.cpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.cpp @@ -74,6 +74,17 @@ bool Exists(const std::string& path) { return !path.empty() && stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode); } +bool UseAngleForRequest(const Request& request) { + if (request.backend != "DirectGLES") { + return false; + } + if (request.useAngle) { + return true; + } + const char* value = getenv("MOBILEGL_RETRACE_USE_ANGLE"); + return value != nullptr && strcmp(value, "1") == 0; +} + bool EnsureDirectory(const std::string& path) { if (path.empty()) { return false; @@ -116,6 +127,9 @@ bool LoadMobileGL(const Request& request, std::string& error) { setenv("MOBILEGL_BACKEND_TYPE", request.backend.c_str(), 1); setenv("MOBILEGL_TRACE_LIBRARY", request.mobileGlLibrary.c_str(), 1); setenv("MOBILEGL_TRACE_SKIP_AUTODESTROY", "1", 1); + if (UseAngleForRequest(request)) { + setenv("MOBILEGL_RETRACE_USE_ANGLE", "1", 1); + } void* handle = dlopen(request.mobileGlLibrary.c_str(), RTLD_NOW | RTLD_GLOBAL); if (handle == nullptr) { @@ -734,6 +748,7 @@ bool WriteResultJson(const Request& request, const Result& result) { file << " \"cropHeight\": " << request.cropHeight << ",\n"; file << " \"tolerance\": " << request.tolerance << ",\n"; file << " \"fuzzPercent\": " << request.fuzzPercent << ",\n"; + file << " \"useAngle\": " << (UseAngleForRequest(request) ? "true" : "false") << ",\n"; file << " \"mismatchPixels\": " << result.mismatchPixels << "\n"; file << "}\n"; return true; 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 6882fe8d..5e9dc843 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.hpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.hpp @@ -33,6 +33,7 @@ struct Request { int cropHeight = 0; int tolerance = 0; int fuzzPercent = 20; + bool useAngle = false; }; struct Result { 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 9455e949..7cecdf90 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_jni.cpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_jni.cpp @@ -98,7 +98,8 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv* jint cropY, jint cropWidth, jint cropHeight, - jint fuzzPercent) { + jint fuzzPercent, + jboolean useAngle) { mobilegl_trace::Request request; request.tracePath = ToString(env, tracePath); request.goldenPath = ToString(env, goldenPath); @@ -119,6 +120,7 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv* request.cropWidth = cropWidth; request.cropHeight = cropHeight; request.fuzzPercent = fuzzPercent; + request.useAngle = useAngle == JNI_TRUE; ScopedTraceReplayState replayState; mobilegl_trace_set_requested_size(request.width, request.height); 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 b18578cd..6464b71f 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 @@ -110,7 +110,8 @@ public final class TraceReplayActivity extends Activity { request.cropY, request.cropWidth, request.cropHeight, - request.fuzzPercent + request.fuzzPercent, + request.useAngle ); Log.i(TAG, result.toString()); TraceReplayResult finalResult = result; @@ -137,7 +138,8 @@ public final class TraceReplayActivity extends Activity { int cropY, int cropWidth, int cropHeight, - int fuzzPercent + int fuzzPercent, + boolean useAngle ); private static final class TraceReplayRequest { @@ -157,6 +159,7 @@ public final class TraceReplayActivity extends Activity { final int cropWidth; final int cropHeight; final int fuzzPercent; + final boolean useAngle; private TraceReplayRequest( String tracePath, @@ -174,7 +177,8 @@ public final class TraceReplayActivity extends Activity { int cropY, int cropWidth, int cropHeight, - int fuzzPercent + int fuzzPercent, + boolean useAngle ) { this.tracePath = tracePath; this.goldenPath = goldenPath; @@ -192,6 +196,7 @@ public final class TraceReplayActivity extends Activity { this.cropWidth = cropWidth; this.cropHeight = cropHeight; this.fuzzPercent = fuzzPercent; + this.useAngle = useAngle; } static TraceReplayRequest from(Intent intent, File filesDir, String defaultBackend) { @@ -213,7 +218,8 @@ public final class TraceReplayActivity extends Activity { intent.getIntExtra("crop_y", 0), intent.getIntExtra("crop_width", 0), intent.getIntExtra("crop_height", 0), - intent.getIntExtra("fuzz_percent", 20) + intent.getIntExtra("fuzz_percent", 20), + intent.getBooleanExtra("use_angle", false) ); } diff --git a/android-plugin/trace-replay-ci.sh b/android-plugin/trace-replay-ci.sh index 4464eeed..ccfd330d 100644 --- a/android-plugin/trace-replay-ci.sh +++ b/android-plugin/trace-replay-ci.sh @@ -28,6 +28,9 @@ Usage: --crop-height N \ --fuzz-percent N \ --timeout-seconds N + +Set MOBILEGL_RETRACE_USE_ANGLE=1 to run DirectGLES replay with packaged ANGLE +instead of the device system GLES driver. EOF } @@ -195,9 +198,13 @@ copy_fixture_to_app() { run_retrace() { result_dir="${result_root}/${safe_case}-${backend}" alternate_golden_app_path="" + use_angle=0 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 + use_angle=1 + fi mkdir -p "${result_dir}" "${ADB}" install -r "${apk_file}" @@ -211,6 +218,9 @@ run_retrace() { if [ -n "${alternate_golden_app_path}" ]; then set -- "$@" --es alternate_golden_path "${alternate_golden_app_path}" fi + if [ "${use_angle}" -eq 1 ]; then + set -- "$@" --ez use_angle true + fi set -- "$@" \ --es output_dir "${app_dir}/output" \ --es diff_path "${app_dir}/output/${safe_case}-diff.png" \