[Feat] (trace-replay): add Minecraft in-world fixture

This commit is contained in:
2026-06-17 00:05:09 +08:00
parent 7c81906459
commit 44c3ea7844
7 changed files with 106 additions and 7 deletions
+42
View File
@@ -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
+4
View File
@@ -13,6 +13,7 @@
#include <MG_State/EGLState/Core.h>
#include <MG_Impl/GLImpl/Texture/ProxyTexture.h>
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
#include <cstdlib>
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
@@ -3,6 +3,7 @@
#include <dlfcn.h>
#include "apitrace_exit.hpp"
#include "png.h"
#include "trace_parser.hpp"
#include <algorithm>
#include <cerrno>
@@ -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<long long>(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;
}
+10
View File
@@ -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)
+2
View File
@@ -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:
Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB