diff --git a/.github/workflows/apk.yml b/.github/workflows/apk.yml index 9b4092dd..047eeaec 100644 --- a/.github/workflows/apk.yml +++ b/.github/workflows/apk.yml @@ -53,7 +53,7 @@ jobs: - name: Install ccache run: | sudo apt-get update - sudo apt-get install -y ccache + sudo apt-get install -y ccache patchelf ccache --version - name: Setup Android SDK @@ -83,15 +83,39 @@ jobs: - name: Download ANGLE x86_64 libraries run: | angle_dir="android-plugin/app/src/trace/jniLibs/x86_64" - angle_commit="f2a3d510dffd8f6540a52e1a7d0c5787d151075b" - angle_base="https://raw.githubusercontent.com/FCL-Team/FoldCraftLauncher/${angle_commit}/FCLauncher/src/main/jniLibs/x86_64" + rm -rf "${angle_dir}" 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" - echo "c41828768d089899fa058ec0bee711a91be88347f29bdb935223da6be1149c40 ${angle_dir}/libEGL_angle.so" | sha256sum -c - - echo "e4f820d99f94365c66df868c7740fef142fe5c0cd7c941790a9e30638857ca4d ${angle_dir}/libGLESv2_angle.so" | sha256sum -c - + + package_angle_variant() { + variant="$1" + commit="$2" + egl_sha="$3" + gles_sha="$4" + source_dir="${RUNNER_TEMP}/mobilegl-angle-${variant}" + base="https://raw.githubusercontent.com/FCL-Team/FoldCraftLauncher/${commit}/FCLauncher/src/main/jniLibs/x86_64" + mkdir -p "${source_dir}" + curl -L --fail --retry 3 -o "${source_dir}/libEGL_angle.so" "${base}/libEGL_angle.so" + curl -L --fail --retry 3 -o "${source_dir}/libGLESv2_angle.so" "${base}/libGLESv2_angle.so" + echo "${egl_sha} ${source_dir}/libEGL_angle.so" | sha256sum -c - + echo "${gles_sha} ${source_dir}/libGLESv2_angle.so" | sha256sum -c - + for library in libEGL_angle libGLESv2_angle; do + filename="${library}_${variant}.so" + cp "${source_dir}/${library}.so" "${angle_dir}/${filename}" + patchelf --set-soname "${filename}" "${angle_dir}/${filename}" + test "$(patchelf --print-soname "${angle_dir}/${filename}")" = "${filename}" + done + } + + package_angle_variant \ + ec889e6ea831 \ + f2a3d510dffd8f6540a52e1a7d0c5787d151075b \ + c41828768d089899fa058ec0bee711a91be88347f29bdb935223da6be1149c40 \ + e4f820d99f94365c66df868c7740fef142fe5c0cd7c941790a9e30638857ca4d + package_angle_variant \ + 90a62123d794 \ + bdcc96ac11c79001018ae4375eb73cb54a9f682f \ + d0f4298ccc770cc801fc52e21733521646161e8a4adb3bd0052d9a1b57ee0ca8 \ + 66fdc867e552192d553d59095ea2e3cef4829de65c356f1fd826027b1905972e - 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)" @@ -100,6 +124,73 @@ jobs: SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }} SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }} + - name: Verify trace ANGLE packaging + run: | + expected=( + lib/x86_64/libEGL_angle_ec889e6ea831.so + lib/x86_64/libGLESv2_angle_ec889e6ea831.so + lib/x86_64/libEGL_angle_90a62123d794.so + lib/x86_64/libGLESv2_angle_90a62123d794.so + ) + trace_markers=( + MOBILEGL_TRACE_ANGLE_VARIANT + ec889e6ea831 + 90a62123d794 + 'Rejected trace ANGLE variant' + 'Loaded signed trace ANGLE library' + ) + mapfile -t trace_apks < <(find android-plugin/app/build/outputs/apk -name 'MobileGL-*Trace-release.apk' | sort) + mapfile -t plugin_apks < <(find android-plugin/app/build/outputs/apk -name 'MobileGL-*Plugin-release.apk' | sort) + test "${#trace_apks[@]}" -eq 2 + test "${#plugin_apks[@]}" -eq 2 + + extract_dir="${RUNNER_TEMP}/mobilegl-packaged-angle" + rm -rf "${extract_dir}" + mkdir -p "${extract_dir}" + for apk in "${trace_apks[@]}"; do + entries="$(unzip -Z1 "${apk}")" + packaged_angle_count="$(printf '%s\n' "${entries}" | grep -Ec 'lib/[^/]+/lib(EGL|GLESv2)_angle(_[0-9a-f]+)?\.so$')" + test "${packaged_angle_count}" -eq 4 + for entry in "${expected[@]}"; do + printf '%s\n' "${entries}" | grep -Fx "${entry}" + extracted="${extract_dir}/$(basename "${apk}")-$(basename "${entry}")" + unzip -p "${apk}" "${entry}" > "${extracted}" + test "$(patchelf --print-soname "${extracted}")" = "$(basename "${entry}")" + done + if printf '%s\n' "${entries}" | grep -Eq 'lib/[^/]+/lib(EGL|GLESv2)_angle\.so$'; then + echo "Unsuffixed ANGLE library found in ${apk}" >&2 + exit 1 + fi + mapfile -t mobilegl_entries < <(printf '%s\n' "${entries}" | grep -E '^lib/[^/]+/libMobileGL\.so$') + test "${#mobilegl_entries[@]}" -eq 2 + for entry in "${mobilegl_entries[@]}"; do + extracted="${extract_dir}/$(basename "${apk}")-${entry//\//-}" + unzip -p "${apk}" "${entry}" > "${extracted}" + for marker in "${trace_markers[@]}"; do + grep -aFq "${marker}" "${extracted}" + done + done + done + for apk in "${plugin_apks[@]}"; do + entries="$(unzip -Z1 "${apk}")" + if printf '%s\n' "${entries}" | grep -Eq 'lib/[^/]+/lib(EGL|GLESv2)_angle(_[0-9a-f]+)?\.so$'; then + echo "ANGLE library found in plugin APK ${apk}" >&2 + exit 1 + fi + mapfile -t mobilegl_entries < <(printf '%s\n' "${entries}" | grep -E '^lib/[^/]+/libMobileGL\.so$') + test "${#mobilegl_entries[@]}" -ge 1 + for entry in "${mobilegl_entries[@]}"; do + extracted="${extract_dir}/$(basename "${apk}")-${entry//\//-}" + unzip -p "${apk}" "${entry}" > "${extracted}" + for marker in "${trace_markers[@]}"; do + if grep -aFq "${marker}" "${extracted}"; then + echo "Trace ANGLE marker '${marker}' found in plugin APK ${apk}" >&2 + exit 1 + fi + done + done + done + - name: Show ccache stats if: always() run: ccache --show-stats @@ -337,22 +428,14 @@ jobs: - name: Retrace and validate env: MOBILEGL_USE_ANGLE: ${{ matrix.backend.name == 'DirectGLES' && '1' || '0' }} + MOBILEGL_TRACE_ANGLE_VARIANT: ${{ matrix.case.name == 'minecraft-1.21.4-fabric-iris-bliss-in-world' && '90a62123d794' || 'ec889e6ea831' }} MOBILEGL_MAGMA_R11G11B10F_FALLBACK: ${{ matrix.backend.name == 'DirectVulkan' && '1' || '0' }} run: | apk_file="$(find android-retrace-apks -name '${{ matrix.backend.apk }}' -print -quit)" extra_retrace_args=() - # Bliss-specific workaround: this trace needs the newer ANGLE build - # plus sampler mipmap min-filter downgrading on ANGLE llvmpipe. + # Bliss needs the newer signed ANGLE variant plus sampler mipmap + # min-filter downgrading on ANGLE llvmpipe. if [ "${{ matrix.backend.name }}" = "DirectGLES" ] && [ "${{ matrix.case.name }}" = "minecraft-1.21.4-fabric-iris-bliss-in-world" ]; then - angle_override_dir="${RUNNER_TEMP}/mobilegl-angle-bliss-x86_64" - angle_override_commit="bdcc96ac11c79001018ae4375eb73cb54a9f682f" - angle_override_base="https://raw.githubusercontent.com/FCL-Team/FoldCraftLauncher/${angle_override_commit}/FCLauncher/src/main/jniLibs/x86_64" - mkdir -p "${angle_override_dir}" - curl -L --fail --retry 3 -o "${angle_override_dir}/libEGL_angle.so" "${angle_override_base}/libEGL_angle.so" - curl -L --fail --retry 3 -o "${angle_override_dir}/libGLESv2_angle.so" "${angle_override_base}/libGLESv2_angle.so" - echo "d0f4298ccc770cc801fc52e21733521646161e8a4adb3bd0052d9a1b57ee0ca8 ${angle_override_dir}/libEGL_angle.so" | sha256sum -c - - echo "66fdc867e552192d553d59095ea2e3cef4829de65c356f1fd826027b1905972e ${angle_override_dir}/libGLESv2_angle.so" | sha256sum -c - - extra_retrace_args+=(--angle-library-dir "${angle_override_dir}") extra_retrace_args+=(--avoid-angle-llvmpipe-sampler-mipmap-min-filter) fi timeout "$(( ${{ matrix.case.timeout_seconds }} + 300 ))" sh android-plugin/trace-replay-ci.sh \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 15d15252..bae83295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ option(MOBILEGL_BUILD_BENCHMARK "Build MobileGL benchmarks" option(MOBILEGL_FORCE_RELEASE_OPT "Enable Release optimization flags in Debug build" ON ) option(MOBILEGL_ENABLE_TRACY "Enable tracy for profiling" OFF) option(MOBILEGL_BUILD_TRACE_REPLAY "Build desktop apitrace replay runner" OFF) +option(MOBILEGL_TRACE_ANGLE_VARIANTS "Enable signed trace-APK ANGLE variant loading" OFF) option(MOBILEGL_IOS "Build MobileGL for iOS instead of macOS when APPLE is set" OFF) set(MOBILEGL_LOG_ACTIVE_LEVEL "MOBILEGL_LOG_LEVEL_INFO" CACHE STRING "MobileGL active log level macro") set(MOBILEGL_VULKAN_LIBRARY "" CACHE FILEPATH "Vulkan loader/MoltenVK library to link for iOS builds") @@ -357,6 +358,7 @@ target_compile_definitions(${CMAKE_PROJECT_NAME} PUBLIC ${MOBILEGL_COMPILE_DEF} MOBILEGL_LOG_ACTIVE_LEVEL=${MOBILEGL_LOG_ACTIVE_LEVEL} + $<$:MOBILEGL_TRACE_ANGLE_VARIANTS=1> ) if(UNIX AND NOT APPLE AND NOT ANDROID) diff --git a/MobileGL/Config.h b/MobileGL/Config.h index c0f32c52..923a9ef8 100644 --- a/MobileGL/Config.h +++ b/MobileGL/Config.h @@ -35,6 +35,10 @@ namespace MobileGL::MG_Config { Bool DisableTimerQuery = false; // MOBILEGL_USE_ANGLE: load ANGLE EGL/GLES libraries. Bool UseAngle = false; +#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS) + // MOBILEGL_TRACE_ANGLE_VARIANT: signed trace-APK ANGLE build short hash. + String TraceAngleVariant; +#endif // 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 a7b0b515..6c8f2bc1 100644 --- a/MobileGL/ConfigLoader.cpp +++ b/MobileGL/ConfigLoader.cpp @@ -111,6 +111,9 @@ namespace MobileGL::MG_ConfigLoader { auto& features = MG_Config::Features; features.DisableTimerQuery = QueryEnvFlag("MOBILEGL_DISABLE_TIMERQUERY"); features.UseAngle = QueryEnvFlag("MOBILEGL_USE_ANGLE"); +#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS) + QueryEnvVariable("MOBILEGL_TRACE_ANGLE_VARIANT", features.TraceAngleVariant, ""); +#endif 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 ec46fbbd..5e6df140 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -9,7 +9,7 @@ #include "Loader.h" #include "MG_Util/Types.h" #include -#if defined(MOBILEGL_IOS) +#if !defined(__WIN32) && !defined(_WIN32) #include #endif @@ -18,6 +18,47 @@ namespace MobileGL::MG_Util::BackendLoader { return MG_Config::Features.UseAngle; } +#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS) && defined(__ANDROID__) + static Bool IsTraceAngleLibrary(const String& name) { + return name == "libGLESv2_angle.so" || name == "libEGL_angle.so"; + } + + static Bool IsAllowedTraceAngleVariant(const String& variant) { + return variant == "ec889e6ea831" || variant == "90a62123d794"; + } + + static Bool ResolveTraceAngleLibraryPath(const String& name, String& path) { + const String& variant = MG_Config::Features.TraceAngleVariant; + if (!IsAllowedTraceAngleVariant(variant)) { + MGLOG_F("Rejected trace ANGLE variant '%s'", variant.c_str()); + return false; + } + + Dl_info mobileGlInfo{}; + if (dladdr(reinterpret_cast(&ResolveTraceAngleLibraryPath), &mobileGlInfo) == 0 || + mobileGlInfo.dli_fname == nullptr) { + MGLOG_F("Failed to resolve signed trace native library directory"); + return false; + } + + String nativeLibraryPath = mobileGlInfo.dli_fname; + const SizeT separator = nativeLibraryPath.find_last_of('/'); + if (separator == String::npos) { + MGLOG_F("Invalid MobileGL library path: %s", nativeLibraryPath.c_str()); + return false; + } + + const SizeT extension = name.rfind(".so"); + if (extension == String::npos) { + MGLOG_F("Invalid trace ANGLE library name: %s", name.c_str()); + return false; + } + path = nativeLibraryPath.substr(0, separator + 1) + name.substr(0, extension) + "_" + variant + ".so"; + return true; + } + +#endif + static void* OpenLib(const Vector& names) { #if !defined(__WIN32) && !defined(_WIN32) && (!defined(__APPLE__) || defined(MOBILEGL_IOS)) static const String LibPathPrefixes[] = { @@ -35,6 +76,22 @@ namespace MobileGL::MG_Util::BackendLoader { Int flags = RTLD_LOCAL | RTLD_NOW; for (const auto& prefix : LibPathPrefixes) { for (const auto& name : names) { +#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS) && defined(__ANDROID__) + if (UseAngle() && IsTraceAngleLibrary(name)) { + String signedPath; + if (!ResolveTraceAngleLibraryPath(name, signedPath)) { + return nullptr; + } + lib = dlopen(signedPath.c_str(), flags); + if (lib == nullptr) { + MGLOG_F("Failed to open signed trace ANGLE library %s: %s", + signedPath.c_str(), dlerror()); + return nullptr; + } + MGLOG_I("Loaded signed trace ANGLE library: %s", signedPath.c_str()); + return lib; + } +#endif String path_name = prefix + name; if ((lib = dlopen(path_name.c_str(), flags))) { MGLOG_I("Loaded GL backend library: %s", path_name.c_str()); @@ -460,12 +517,18 @@ namespace MobileGL::MG_Util::BackendLoader { void AcquireEGLFunctions(MG_External::EGLFunctionsTable& funcs) { void* eglLib = nullptr; +#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS) && defined(__ANDROID__) + void* angleGlesLib = nullptr; +#endif if (UseAngle()) { void* glesLib = OpenLib({"libGLESv2_angle.so"}); if (!glesLib) { MGLOG_E("Failed to open ANGLE libGLESv2_angle.so"); return; } +#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS) && defined(__ANDROID__) + angleGlesLib = glesLib; +#endif eglLib = OpenLib({"libEGL_angle.so"}); if (!eglLib) { MGLOG_E("Failed to open ANGLE libEGL_angle.so"); @@ -484,9 +547,22 @@ namespace MobileGL::MG_Util::BackendLoader { return; } + auto resolveEGLProc = [&](const char* name) -> void* { +#if defined(MOBILEGL_TRACE_ANGLE_VARIANTS) && defined(__ANDROID__) + if (UseAngle()) { + // Avoid the wrapper's canonical libGLESv2_angle.so lookup: + // resolve its forwarding target from the verified variant. + String target = "EGL_"; + target += name + 3; + return ProcAddress(angleGlesLib, target.c_str()); + } +#endif + return ProcAddress(eglLib, name); + }; + #define INIT_EGL_FUNC(name) \ do { \ - funcs.name = (MG_External::EGL::name##_PTR)ProcAddress(eglLib, #name); \ + funcs.name = (MG_External::EGL::name##_PTR)resolveEGLProc(#name); \ if (!funcs.name) { \ MGLOG_E("Failed to load EGL function: %s", #name); \ } \ diff --git a/android-plugin/TRACE_REPLAY.md b/android-plugin/TRACE_REPLAY.md index a40c1178..696831e5 100644 --- a/android-plugin/TRACE_REPLAY.md +++ b/android-plugin/TRACE_REPLAY.md @@ -39,7 +39,7 @@ crop_width optional compare crop width crop_height optional compare crop height use_angle optional boolean; DirectGLES uses packaged ANGLE when true use_pbuffer optional boolean; DirectGLES uses an offscreen EGL pbuffer when true -angle_library_dir optional directory containing libEGL_angle.so and libGLESv2_angle.so; defaults to the APK native library directory +angle_variant required with use_angle; signed packaged ANGLE short hash (`ec889e6ea831` or `90a62123d794`) ``` Implementation notes: @@ -51,7 +51,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_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. +- Set `MOBILEGL_USE_ANGLE=1` and `MOBILEGL_TRACE_ANGLE_VARIANT=` when running `trace-replay-ci.sh` for DirectGLES. The trace APK contains both allowlisted ANGLE builds with short-hash filenames and SONAMEs; MobileGL resolves its signed native library directory and loads the selected pair by absolute path. Set `MOBILEGL_RETRACE_USE_PBUFFER=1` or pass `--use-pbuffer` to keep DirectGLES offscreen. Example core-profile trace smoke command for a debug trace APK: @@ -68,6 +68,8 @@ adb shell am start -a top.mobilegl.plugin.TRACE_REPLAY \ --es output_dir /data/user/0/top.mobilegl.plugin.espryt.trace/files/trace-replay/output \ --es diff_path /data/user/0/top.mobilegl.plugin.espryt.trace/files/trace-replay/output/app-diff.png \ --es backend DirectGLES \ + --ez use_angle true \ + --es angle_variant ec889e6ea831 \ --el target_call 31249 \ --es ssim_threshold 0.99 adb shell run-as top.mobilegl.plugin.espryt.trace cat files/trace-replay/output/result.json 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 845d9961..71d42ef2 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.cpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.cpp @@ -89,20 +89,6 @@ bool UseAngleForRequest(const Request& request) { 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; @@ -153,11 +139,10 @@ bool LoadMobileGL(const Request& request, std::string& error) { } if (UseAngleForRequest(request)) { setenv("MOBILEGL_USE_ANGLE", "1", 1); - if (!request.angleLibraryDir.empty()) { - PrependLibraryPath(request.angleLibraryDir); - } + setenv("MOBILEGL_TRACE_ANGLE_VARIANT", request.angleVariant.c_str(), 1); } else { unsetenv("MOBILEGL_USE_ANGLE"); + unsetenv("MOBILEGL_TRACE_ANGLE_VARIANT"); } if (request.avoidAngleLlvmpipeSamplerMipmapMinFilter) { setenv("MOBILEGL_AVOID_SAMPLER_MIPMAP_MIN_FILTER", "1", 1); @@ -755,7 +740,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 << " \"angleVariant\": \"" << JsonEscape(request.angleVariant) << "\",\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 64930731..c417d141 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.hpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.hpp @@ -23,7 +23,7 @@ struct Request { std::string diffPath; std::string backend; std::string mobileGlLibrary = "libMobileGL.so"; - std::string angleLibraryDir; + std::string angleVariant; 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 791ce121..d0414867 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,7 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv* jint cropY, jint cropWidth, jint cropHeight, - jstring angleLibraryDir, + jstring angleVariant, jboolean useAngle, jboolean usePbuffer, jboolean avoidAngleLlvmpipeSamplerMipmapMinFilter) { @@ -112,7 +112,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.angleVariant = ToString(env, angleVariant); 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 6c521e35..1f9b4fc1 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,7 +44,6 @@ 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,7 +110,7 @@ public final class TraceReplayActivity extends Activity { request.cropY, request.cropWidth, request.cropHeight, - request.angleLibraryDir, + request.angleVariant, request.useAngle, request.usePbuffer, request.avoidAngleLlvmpipeSamplerMipmapMinFilter @@ -141,7 +140,7 @@ public final class TraceReplayActivity extends Activity { int cropY, int cropWidth, int cropHeight, - String angleLibraryDir, + String angleVariant, boolean useAngle, boolean usePbuffer, boolean avoidAngleLlvmpipeSamplerMipmapMinFilter @@ -163,7 +162,7 @@ public final class TraceReplayActivity extends Activity { final int cropY; final int cropWidth; final int cropHeight; - final String angleLibraryDir; + final String angleVariant; final boolean useAngle; final boolean usePbuffer; final boolean avoidAngleLlvmpipeSamplerMipmapMinFilter; @@ -184,7 +183,7 @@ public final class TraceReplayActivity extends Activity { int cropY, int cropWidth, int cropHeight, - String angleLibraryDir, + String angleVariant, boolean useAngle, boolean usePbuffer, boolean avoidAngleLlvmpipeSamplerMipmapMinFilter @@ -204,13 +203,13 @@ public final class TraceReplayActivity extends Activity { this.cropY = cropY; this.cropWidth = cropWidth; this.cropHeight = cropHeight; - this.angleLibraryDir = angleLibraryDir; + this.angleVariant = angleVariant; this.useAngle = useAngle; this.usePbuffer = usePbuffer; this.avoidAngleLlvmpipeSamplerMipmapMinFilter = avoidAngleLlvmpipeSamplerMipmapMinFilter; } - static TraceReplayRequest from(Intent intent, File filesDir, String nativeLibraryDir, String defaultBackend) { + static TraceReplayRequest from(Intent intent, File filesDir, String defaultBackend) { String outputDir = readString(intent, "output_dir", new File(filesDir, "trace-replay").getAbsolutePath()); String diffPath = readString(intent, "diff_path", ""); return new TraceReplayRequest( @@ -229,7 +228,7 @@ public final class TraceReplayActivity extends Activity { intent.getIntExtra("crop_y", 0), intent.getIntExtra("crop_width", 0), intent.getIntExtra("crop_height", 0), - readString(intent, "angle_library_dir", nativeLibraryDir), + readString(intent, "angle_variant", ""), intent.getBooleanExtra("use_angle", false), intent.getBooleanExtra("use_pbuffer", false), intent.getBooleanExtra("avoid_angle_llvmpipe_sampler_mipmap_min_filter", false) diff --git a/android-plugin/trace-replay-ci.sh b/android-plugin/trace-replay-ci.sh index 224fb2ff..05722a21 100644 --- a/android-plugin/trace-replay-ci.sh +++ b/android-plugin/trace-replay-ci.sh @@ -18,7 +18,6 @@ Usage: --trace-file FILE_IN_ARCHIVE \ --golden FILE \ [--alternate-golden FILE] \ - [--angle-library-dir DIR] \ --target-call N \ --width N \ --height N \ @@ -33,6 +32,8 @@ Usage: Set MOBILEGL_USE_ANGLE=1 to run DirectGLES replay with packaged ANGLE instead of the device system GLES driver. +Set MOBILEGL_TRACE_ANGLE_VARIANT to the packaged ANGLE short hash used by +DirectGLES replay. Set MOBILEGL_RETRACE_USE_PBUFFER=1 or pass --use-pbuffer to run DirectGLES against an offscreen EGL pbuffer instead of the Activity surface. Pass --avoid-angle-llvmpipe-sampler-mipmap-min-filter for DirectGLES traces that @@ -83,7 +84,6 @@ trace_archive="" trace_file="" golden_path="" alternate_golden_path="" -angle_library_dir="" target_call="" width="" height="" @@ -116,7 +116,6 @@ while [ "$#" -gt 0 ]; do shift 2 fi ;; - --angle-library-dir) angle_library_dir="$(next_arg "$@")"; shift 2 ;; --target-call) target_call="$(next_arg "$@")"; shift 2 ;; --width) width="$(next_arg "$@")"; shift 2 ;; --height) height="$(next_arg "$@")"; shift 2 ;; @@ -161,11 +160,6 @@ test -f "${golden_path}" || die "golden image does not exist: ${golden_path}" if [ -n "${alternate_golden_path}" ]; then test -f "${alternate_golden_path}" || die "alternate golden image does not exist: ${alternate_golden_path}" fi -if [ -n "${angle_library_dir}" ]; then - test -f "${angle_library_dir}/libEGL_angle.so" || die "ANGLE override is missing libEGL_angle.so: ${angle_library_dir}" - test -f "${angle_library_dir}/libGLESv2_angle.so" || die "ANGLE override is missing libGLESv2_angle.so: ${angle_library_dir}" -fi - safe_case="$(printf '%s' "${case_name}" | sed 's/[^A-Za-z0-9._-]/_/g')" app_dir="/data/user/0/${package_name}/files/trace-replay" @@ -203,18 +197,10 @@ prepare_fixture() { if [ -n "${alternate_golden_path}" ]; then adb_device_path push "$(host_path_for_adb "${alternate_golden_path}")" "/data/local/tmp/mobilegl-${safe_case}.alternate-golden.png" fi - if [ -n "${angle_library_dir}" ]; then - adb_device_path push "$(host_path_for_adb "${angle_library_dir}/libEGL_angle.so")" "/data/local/tmp/mobilegl-${safe_case}.libEGL_angle.so" - adb_device_path push "$(host_path_for_adb "${angle_library_dir}/libGLESv2_angle.so")" "/data/local/tmp/mobilegl-${safe_case}.libGLESv2_angle.so" - fi adb_device_path shell chmod 0644 "/data/local/tmp/mobilegl-${safe_case}.trace" "/data/local/tmp/mobilegl-${safe_case}.golden.png" if [ -n "${alternate_golden_path}" ]; then adb_device_path shell chmod 0644 "/data/local/tmp/mobilegl-${safe_case}.alternate-golden.png" fi - if [ -n "${angle_library_dir}" ]; then - adb_device_path shell chmod 0644 "/data/local/tmp/mobilegl-${safe_case}.libEGL_angle.so" \ - "/data/local/tmp/mobilegl-${safe_case}.libGLESv2_angle.so" - fi } copy_fixture_to_app() { @@ -229,13 +215,6 @@ copy_fixture_to_app() { if [ -n "${alternate_golden_path}" ]; then adb_device_path shell run-as "${package_name}" cp "${alternate_golden_tmp}" "${app_dir}/input/alternate-golden.png" fi - if [ -n "${angle_library_dir}" ]; then - adb_device_path shell run-as "${package_name}" mkdir -p "${app_dir}/angle" - adb_device_path shell run-as "${package_name}" cp "/data/local/tmp/mobilegl-${safe_case}.libEGL_angle.so" \ - "${app_dir}/angle/libEGL_angle.so" - adb_device_path shell run-as "${package_name}" cp "/data/local/tmp/mobilegl-${safe_case}.libGLESv2_angle.so" \ - "${app_dir}/angle/libGLESv2_angle.so" - fi } run_retrace() { @@ -247,6 +226,7 @@ run_retrace() { fi if [ "${MOBILEGL_USE_ANGLE:-}" = "1" ] && [ "${backend}" = "DirectGLES" ]; then use_angle=1 + test -n "${MOBILEGL_TRACE_ANGLE_VARIANT:-}" || die "MOBILEGL_TRACE_ANGLE_VARIANT is required for DirectGLES ANGLE replay" fi if [ "${MOBILEGL_RETRACE_USE_PBUFFER:-}" = "1" ] && [ "${backend}" = "DirectGLES" ]; then use_pbuffer=1 @@ -266,9 +246,7 @@ run_retrace() { fi if [ "${use_angle}" -eq 1 ]; then set -- "$@" --ez use_angle true - if [ -n "${angle_library_dir}" ]; then - set -- "$@" --es angle_library_dir "${app_dir}/angle" - fi + set -- "$@" --es angle_variant "${MOBILEGL_TRACE_ANGLE_VARIANT}" fi if [ "${use_pbuffer}" -eq 1 ] && [ "${backend}" = "DirectGLES" ]; then set -- "$@" --ez use_pbuffer true diff --git a/build.gradle b/build.gradle index 87c465aa..effb0d2d 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ apply plugin: 'com.android.library' def mobileGlLogActiveLevel = { (rootProject.findProperty('mobilegl.logLevel') ?: System.getenv('MOBILEGL_LOG_ACTIVE_LEVEL') ?: 'MOBILEGL_LOG_LEVEL_INFO') as String } +def standalonePluginBuild = rootProject.name == 'MobileGLPlugin' android { namespace 'top.mobilegl.mobilegl' @@ -32,6 +33,22 @@ android { debuggable true } } + if (standalonePluginBuild) { + flavorDimensions 'profile' + productFlavors { + plugin { + dimension 'profile' + } + trace { + dimension 'profile' + externalNativeBuild { + cmake { + arguments '-DMOBILEGL_TRACE_ANGLE_VARIANTS=ON' + } + } + } + } + } externalNativeBuild { cmake { path "CMakeLists.txt" diff --git a/tools/trace_replay/run_android_retrace_local.py b/tools/trace_replay/run_android_retrace_local.py index 705ce596..174e072a 100644 --- a/tools/trace_replay/run_android_retrace_local.py +++ b/tools/trace_replay/run_android_retrace_local.py @@ -15,6 +15,9 @@ RESULT_ROOT = ROOT / ".trace-work" / "android-retrace-result" FIXTURE_ROOT = ROOT / ".trace-work" / "android-retrace-fixture" SUMMARY_DIR = ROOT / ".trace-work" / "android-retrace-summary" SUMMARY_HTML = "mobilegl-android-retrace-overview.html" +DEFAULT_ANGLE_VARIANT = "ec889e6ea831" +BLISS_ANGLE_VARIANT = "90a62123d794" +BLISS_CASE = "minecraft-1.21.4-fabric-iris-bliss-in-world" BACKENDS = { "DirectGLES": { @@ -63,6 +66,9 @@ def mark_skipped(case, backend, reason): "actualPath": "", "diffPath": "", "backend": backend, + "angleVariant": ( + BLISS_ANGLE_VARIANT if case["name"] == BLISS_CASE else DEFAULT_ANGLE_VARIANT + ) if BACKENDS[backend]["use_angle"] else "", "targetCall": case["target_call"], "width": case["width"], "height": case["height"], @@ -168,13 +174,19 @@ def run_case(case, backend): command[command.index("--target-call"):command.index("--target-call")] = ["--alternate-golden", bash_path(alternate)] if backend_info["use_pbuffer"]: command.append("--use-pbuffer") + if backend_info["use_angle"] and case["name"] == BLISS_CASE: + command.append("--avoid-angle-llvmpipe-sampler-mipmap-min-filter") env = dict(**__import__("os").environ) env["PYTHON"] = "python" env["MSYS2_ARG_CONV_EXCL"] = "/data/*" if backend_info["use_angle"]: env["MOBILEGL_USE_ANGLE"] = "1" + env["MOBILEGL_TRACE_ANGLE_VARIANT"] = ( + BLISS_ANGLE_VARIANT if case["name"] == BLISS_CASE else DEFAULT_ANGLE_VARIANT + ) else: env.pop("MOBILEGL_USE_ANGLE", None) + env.pop("MOBILEGL_TRACE_ANGLE_VARIANT", None) result = subprocess.run(command, cwd=ROOT, env=env) copy_goldens(case, backend) return result.returncode