diff --git a/.github/workflows/apk.yml b/.github/workflows/apk.yml index b9f4f7f7..c4a4759f 100644 --- a/.github/workflows/apk.yml +++ b/.github/workflows/apk.yml @@ -199,6 +199,27 @@ jobs: --fuzz-percent 20 --timeout-seconds 180 || status=1; + sh android-plugin/trace-replay-ci.sh + --apk-file "${apk_file}" + --package top.mobilegl.plugin.espryt.trace + --backend DirectGLES + --result-root android-retrace-result + --fixture-root android-retrace-fixture + --case minecraft-1.21.4-in-world + --trace-archive tools/trace_replay/fixtures/minecraft-1.21.4-in-world.tgz + --trace-file trace.trace + --golden tools/trace_replay/fixtures/minecraft-1.21.4-in-world.0004000686.png + --target-call 4000686 + --width 854 + --height 480 + --tolerance 500 + --crop-x 0 + --crop-y 0 + --crop-width 0 + --crop-height 0 + --fuzz-percent 20 + --timeout-seconds 900 + || status=1; mkdir -p android-retrace-result/status; echo "${status}" > android-retrace-result/status/DirectGLES.status; exit 0 @@ -280,6 +301,27 @@ jobs: --fuzz-percent 20 --timeout-seconds 180 || status=1; + sh android-plugin/trace-replay-ci.sh + --apk-file "${apk_file}" + --package top.mobilegl.plugin.magma.trace + --backend DirectVulkan + --result-root android-retrace-result + --fixture-root android-retrace-fixture + --case minecraft-1.21.4-in-world + --trace-archive tools/trace_replay/fixtures/minecraft-1.21.4-in-world.tgz + --trace-file trace.trace + --golden tools/trace_replay/fixtures/minecraft-1.21.4-in-world.0004000686.png + --target-call 4000686 + --width 854 + --height 480 + --tolerance 500 + --crop-x 0 + --crop-y 0 + --crop-width 0 + --crop-height 0 + --fuzz-percent 20 + --timeout-seconds 900 + || status=1; mkdir -p android-retrace-result/status; echo "${status}" > android-retrace-result/status/DirectVulkan.status; exit 0 diff --git a/MobileGL/Init.cpp b/MobileGL/Init.cpp index 4907ca4a..b23f1635 100644 --- a/MobileGL/Init.cpp +++ b/MobileGL/Init.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace MobileGL { namespace { @@ -66,6 +67,9 @@ namespace MobileGL { } __attribute__((destructor)) static void AutoDestroy() { + if (std::getenv("MOBILEGL_TRACE_SKIP_AUTODESTROY") != nullptr) { + return; + } Destroy(); } #endif 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 ced1528f..1abde701 100644 --- a/android-plugin/app/src/trace/cpp/trace_replay_core.cpp +++ b/android-plugin/app/src/trace/cpp/trace_replay_core.cpp @@ -3,6 +3,7 @@ #include #include "apitrace_exit.hpp" #include "png.h" +#include "trace_parser.hpp" #include #include @@ -113,6 +114,7 @@ std::string JsonEscape(const std::string& value) { 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); void* handle = dlopen(request.mobileGlLibrary.c_str(), RTLD_NOW | RTLD_GLOBAL); if (handle == nullptr) { @@ -345,9 +347,38 @@ std::string SnapshotPathForCall(const Request& request) { return request.outputDir + "/actual." + call + ".png"; } -int RunRetraceMain(const Request& request) { +bool TargetCallSwapsRenderTarget(const Request& request, bool& swapsRenderTarget, std::string& error) { + trace::Parser parser; + if (!parser.open(request.tracePath.c_str())) { + error = "failed to open trace for target call inspection"; + return false; + } + + trace::Call* call = nullptr; + while ((call = parser.parse_call()) != nullptr) { + const long long callNo = static_cast(call->no); + if (callNo == request.targetCall) { + swapsRenderTarget = (call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET) != 0; + delete call; + return true; + } + if (callNo > request.targetCall) { + delete call; + break; + } + delete call; + } + + std::ostringstream message; + message << "target_call " << request.targetCall << " was not found in trace"; + error = message.str(); + return false; +} + +int RunRetraceMain(const Request& request, bool usePresentDump) { std::string prefix = request.outputDir + "/actual."; - std::string callSet = std::to_string(request.targetCall); + const long long snapshotCall = usePresentDump ? request.targetCall + 1 : request.targetCall; + std::string callSet = std::to_string(snapshotCall); std::string arg0 = "mobilegl-glretrace"; std::string argBenchmark = "-b"; @@ -374,11 +405,11 @@ int RunRetraceMain(const Request& request) { return MOBILEGL_APITRACE_RETRACE_MAIN(10, argv); } -bool RunRetrace(const Request& request, Result& result) { +bool RunRetrace(const Request& request, bool usePresentDump, Result& result) { int status = 0; try { ScopedFdRedirect redirect(request.outputDir + "/retrace.log"); - status = RunRetraceMain(request); + status = RunRetraceMain(request, usePresentDump); } catch (const MobileGLRetraceExit& retraceExit) { status = retraceExit.status; } catch (const std::exception& exception) { @@ -402,7 +433,7 @@ bool RunRetrace(const Request& request, Result& result) { std::string snapshotPath = SnapshotPathForCall(request); const std::string presentPath = request.outputDir + "/present.ppm"; const bool hasSnapshot = Exists(snapshotPath); - const bool hasPresentDump = request.backend == "DirectVulkan" && Exists(presentPath); + const bool hasPresentDump = usePresentDump && Exists(presentPath); if (!hasSnapshot && !hasPresentDump) { result.statusCode = STATUS_RETRACE_FAILED; result.message = "retrace completed but did not create expected snapshot: " + snapshotPath; @@ -415,7 +446,7 @@ bool RunRetrace(const Request& request, Result& result) { return false; } } - if (request.backend == "DirectVulkan") { + if (usePresentDump) { if (hasPresentDump) { RgbaImage present; std::string imageError; @@ -648,7 +679,17 @@ Result RunTraceReplay(const Request& request) { return result; } + bool usePresentDump = false; if (request.backend == "DirectVulkan") { + std::string inspectError; + if (!TargetCallSwapsRenderTarget(request, usePresentDump, inspectError)) { + result.statusCode = STATUS_INVALID_ARGUMENT; + result.message = inspectError; + return result; + } + } + + if (usePresentDump) { std::string presentDumpPath = request.outputDir + "/present.ppm"; std::string presentDumpCall = std::to_string(request.targetCall); setenv("MOBILEGL_PRESENT_DUMP_PATH", presentDumpPath.c_str(), 1); @@ -670,7 +711,7 @@ Result RunTraceReplay(const Request& request) { return result; } - if (!RunRetrace(request, result)) { + if (!RunRetrace(request, usePresentDump, result)) { return result; } diff --git a/tools/trace_replay/CMakeLists.txt b/tools/trace_replay/CMakeLists.txt index d06ba214..6d9bb7be 100644 --- a/tools/trace_replay/CMakeLists.txt +++ b/tools/trace_replay/CMakeLists.txt @@ -375,3 +375,13 @@ add_trace_replay_test_for_backends(minecraft-1.21.4-main-menu HEIGHT 480 TOLERANCE 500 FUZZ_PERCENT 20) + +add_trace_replay_test_for_backends(minecraft-1.21.4-in-world + TRACE_ARCHIVE ${MOBILEGL_TRACE_ROOT}/fixtures/minecraft-1.21.4-in-world.tgz + TRACE_FILE trace.trace + GOLDEN ${MOBILEGL_TRACE_ROOT}/fixtures/minecraft-1.21.4-in-world.0004000686.png + TARGET_CALL 4000686 + WIDTH 854 + HEIGHT 480 + TOLERANCE 500 + FUZZ_PERCENT 20) diff --git a/tools/trace_replay/README.md b/tools/trace_replay/README.md index e8a681ee..b10e8107 100644 --- a/tools/trace_replay/README.md +++ b/tools/trace_replay/README.md @@ -11,6 +11,8 @@ The bundled fixtures cover: ![Minecraft 1.21.4 startup golden](fixtures/minecraft-1.21.4-startup.0000092195.png) - minecraft-1.21.4-main-menu: captured from Minecraft 1.21.4's main menu. ![Minecraft 1.21.4 main menu golden](fixtures/minecraft-1.21.4-main-menu.0000481787.png) +- minecraft-1.21.4-in-world: captured from Minecraft 1.21.4 after entering a singleplayer world. + ![Minecraft 1.21.4 in-world golden](fixtures/minecraft-1.21.4-in-world.0004000686.png) Build from the MobileGL repository root: diff --git a/tools/trace_replay/fixtures/minecraft-1.21.4-in-world.0004000686.png b/tools/trace_replay/fixtures/minecraft-1.21.4-in-world.0004000686.png new file mode 100644 index 00000000..eba6a569 Binary files /dev/null and b/tools/trace_replay/fixtures/minecraft-1.21.4-in-world.0004000686.png differ diff --git a/tools/trace_replay/fixtures/minecraft-1.21.4-in-world.tgz b/tools/trace_replay/fixtures/minecraft-1.21.4-in-world.tgz new file mode 100644 index 00000000..1d8eb3b8 Binary files /dev/null and b/tools/trace_replay/fixtures/minecraft-1.21.4-in-world.tgz differ