mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Feat] (trace-replay): add Minecraft main menu trace
This commit is contained in:
@@ -443,6 +443,59 @@ int ChannelValue(const RgbaImage& image, int x, int y, int channel) {
|
||||
return image.pixels[(static_cast<std::size_t>(y) * image.width + x) * 4 + channel];
|
||||
}
|
||||
|
||||
bool WriteDifferenceImage(const Result& result,
|
||||
const RgbaImage& actual,
|
||||
const RgbaImage& golden,
|
||||
int x0,
|
||||
int y0,
|
||||
int compareWidth,
|
||||
int compareHeight,
|
||||
int fuzz,
|
||||
std::string& error) {
|
||||
if (result.diffPath.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr int kDiffScale = 8;
|
||||
RgbaImage diff;
|
||||
diff.width = actual.width;
|
||||
diff.height = actual.height;
|
||||
diff.pixels.assign(static_cast<std::size_t>(diff.width) * diff.height * 4, 0);
|
||||
for (int y = 0; y < diff.height; ++y) {
|
||||
for (int x = 0; x < diff.width; ++x) {
|
||||
std::uint8_t* dst = diff.pixels.data() + (static_cast<std::size_t>(y) * diff.width + x) * 4;
|
||||
dst[3] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < compareHeight; ++y) {
|
||||
for (int x = 0; x < compareWidth; ++x) {
|
||||
int imageX = x0 + x;
|
||||
int imageY = y0 + y;
|
||||
int dr = std::abs(ChannelValue(actual, imageX, imageY, 0) -
|
||||
ChannelValue(golden, imageX, imageY, 0));
|
||||
int dg = std::abs(ChannelValue(actual, imageX, imageY, 1) -
|
||||
ChannelValue(golden, imageX, imageY, 1));
|
||||
int db = std::abs(ChannelValue(actual, imageX, imageY, 2) -
|
||||
ChannelValue(golden, imageX, imageY, 2));
|
||||
bool different = dr > fuzz || dg > fuzz || db > fuzz;
|
||||
std::uint8_t* dst = diff.pixels.data() +
|
||||
(static_cast<std::size_t>(imageY) * diff.width + imageX) * 4;
|
||||
if (different) {
|
||||
dst[0] = 0xff;
|
||||
dst[1] = static_cast<std::uint8_t>(std::min(255, dg * kDiffScale));
|
||||
dst[2] = static_cast<std::uint8_t>(std::min(255, db * kDiffScale));
|
||||
} else {
|
||||
dst[0] = static_cast<std::uint8_t>(std::min(255, dr * kDiffScale));
|
||||
dst[1] = static_cast<std::uint8_t>(std::min(255, dg * kDiffScale));
|
||||
dst[2] = static_cast<std::uint8_t>(std::min(255, db * kDiffScale));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return WritePngRgba(result.diffPath, diff, error);
|
||||
}
|
||||
|
||||
bool CompareWithGolden(const Request& request, Result& result) {
|
||||
if (request.goldenPath.empty()) {
|
||||
result.passed = true;
|
||||
@@ -511,6 +564,13 @@ bool CompareWithGolden(const Request& request, Result& result) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string diffError;
|
||||
if (!WriteDifferenceImage(result, actual, golden, x0, y0, compareWidth, compareHeight, fuzz, diffError)) {
|
||||
result.statusCode = STATUS_IO_ERROR;
|
||||
result.message = diffError.empty() ? "failed to write diff PNG" : diffError;
|
||||
return false;
|
||||
}
|
||||
|
||||
result.mismatchPixels = mismatch;
|
||||
result.passed = mismatch <= request.tolerance;
|
||||
result.statusCode = result.passed ? STATUS_OK : STATUS_COMPARE_FAILED;
|
||||
@@ -540,6 +600,7 @@ bool WriteResultJson(const Request& request, const Result& result) {
|
||||
file << " \"tracePath\": \"" << JsonEscape(request.tracePath) << "\",\n";
|
||||
file << " \"goldenPath\": \"" << JsonEscape(request.goldenPath) << "\",\n";
|
||||
file << " \"actualPath\": \"" << JsonEscape(result.actualPath) << "\",\n";
|
||||
file << " \"diffPath\": \"" << JsonEscape(result.diffPath) << "\",\n";
|
||||
file << " \"backend\": \"" << JsonEscape(request.backend) << "\",\n";
|
||||
file << " \"targetFrame\": " << request.targetFrame << ",\n";
|
||||
file << " \"targetCall\": " << request.targetCall << ",\n";
|
||||
@@ -560,6 +621,7 @@ Result RunTraceReplay(const Request& request) {
|
||||
Result result;
|
||||
result.resultPath = request.outputDir + "/result.json";
|
||||
result.actualPath = request.outputDir + "/actual.png";
|
||||
result.diffPath = request.diffPath;
|
||||
const std::string mobileGlLogPath = request.outputDir + "/mobilegl.log";
|
||||
|
||||
if (!EnsureDirectory(request.outputDir)) {
|
||||
|
||||
@@ -18,6 +18,7 @@ struct Request {
|
||||
std::string tracePath;
|
||||
std::string goldenPath;
|
||||
std::string outputDir;
|
||||
std::string diffPath;
|
||||
std::string backend;
|
||||
std::string mobileGlLibrary = "libMobileGL.so";
|
||||
int targetFrame = -1;
|
||||
@@ -38,6 +39,7 @@ struct Result {
|
||||
std::string message;
|
||||
std::string resultPath;
|
||||
std::string actualPath;
|
||||
std::string diffPath;
|
||||
long long mismatchPixels = -1;
|
||||
};
|
||||
|
||||
|
||||
@@ -365,3 +365,13 @@ add_trace_replay_test_for_backends(minecraft-1.21.4-startup
|
||||
HEIGHT 480
|
||||
TOLERANCE 20
|
||||
FUZZ_PERCENT 20)
|
||||
|
||||
add_trace_replay_test_for_backends(minecraft-1.21.4-main-menu
|
||||
TRACE_ARCHIVE ${MOBILEGL_TRACE_ROOT}/fixtures/minecraft-1.21.4-main-menu.tgz
|
||||
TRACE_FILE trace.trace
|
||||
GOLDEN ${MOBILEGL_TRACE_ROOT}/fixtures/minecraft-1.21.4-main-menu.0000481787.png
|
||||
TARGET_CALL 481787
|
||||
WIDTH 854
|
||||
HEIGHT 480
|
||||
TOLERANCE 500
|
||||
FUZZ_PERCENT 20)
|
||||
|
||||
@@ -9,6 +9,8 @@ The bundled fixtures cover:
|
||||
traces rejected because they rely on compatibility/fixed-function OpenGL.
|
||||
- `minecraft-1.21.4-startup`: captured from Minecraft 1.21.4's Mojang Studios startup screen. The fixture is trimmed
|
||||
to call 92195, immediately after the startup screen draw into Minecraft's offscreen framebuffer.
|
||||
- `minecraft-1.21.4-main-menu`: captured from Minecraft 1.21.4's English (US) main menu. The fixture is trimmed to
|
||||
call 481787, immediately after the main menu draw into Minecraft's offscreen framebuffer.
|
||||
|
||||
Build from the MobileGL repository root:
|
||||
|
||||
@@ -48,6 +50,10 @@ build-test/tools/trace_replay/mobilegl_trace_replay \
|
||||
|
||||
The Minecraft startup fixture uses `tools/trace_replay/fixtures/minecraft-1.21.4-startup.tgz`, golden image
|
||||
`minecraft-1.21.4-startup.0000092195.png`, `--target-call 92195`, `--width 854`, and `--height 480`.
|
||||
The Minecraft main-menu fixture uses `tools/trace_replay/fixtures/minecraft-1.21.4-main-menu.tgz`, golden image
|
||||
`minecraft-1.21.4-main-menu.0000481787.png`, `--target-call 481787`, `--width 854`, `--height 480`, and
|
||||
`--tolerance 500`.
|
||||
Each replay that has a golden image writes `${case}-diff.png` in the backend output directory.
|
||||
|
||||
The Linux runner loads MobileGL by path with `dlopen`. It uses an EGL pbuffer for `DirectGLES` and maps the pbuffer
|
||||
path to `VK_EXT_headless_surface` for `DirectVulkan`, so CI does not need an X11 or Wayland window.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 402 KiB |
Binary file not shown.
@@ -50,6 +50,7 @@ execute_process(
|
||||
COMMAND "${TRACE_REPLAY_EXE}"
|
||||
--trace "${trace_path}"
|
||||
--golden "${TRACE_GOLDEN}"
|
||||
--diff "${TRACE_OUTPUT_DIR}/output/${TRACE_CASE_NAME}-diff.png"
|
||||
--output "${TRACE_OUTPUT_DIR}/output"
|
||||
--backend "${TRACE_BACKEND}"
|
||||
--mobilegl-library "${MOBILEGL_LIBRARY}"
|
||||
|
||||
@@ -14,6 +14,7 @@ void PrintUsage(const char *argv0) {
|
||||
<< "\n"
|
||||
<< "Options:\n"
|
||||
<< " --golden PATH Golden PNG to compare against\n"
|
||||
<< " --diff PATH Difference PNG output path\n"
|
||||
<< " --backend NAME DirectGLES or DirectVulkan (default: DirectGLES)\n"
|
||||
<< " --mobilegl-library PATH libMobileGL.so path (default: libMobileGL.so)\n"
|
||||
<< " --width N Replay surface width override\n"
|
||||
@@ -63,6 +64,8 @@ bool ParseArgs(int argc, char **argv, mobilegl_trace::Request &request) {
|
||||
if (!ReadValue(argc, argv, i, request.tracePath)) return false;
|
||||
} else if (arg == "--golden") {
|
||||
if (!ReadValue(argc, argv, i, request.goldenPath)) return false;
|
||||
} else if (arg == "--diff") {
|
||||
if (!ReadValue(argc, argv, i, request.diffPath)) return false;
|
||||
} else if (arg == "--output") {
|
||||
if (!ReadValue(argc, argv, i, request.outputDir)) return false;
|
||||
} else if (arg == "--backend") {
|
||||
@@ -131,6 +134,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
std::cout << result.message << "\n"
|
||||
<< "result: " << result.resultPath << "\n"
|
||||
<< "actual: " << result.actualPath << "\n";
|
||||
<< "actual: " << result.actualPath << "\n"
|
||||
<< "diff: " << result.diffPath << "\n";
|
||||
return result.passed ? 0 : result.statusCode;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user