[Refactor] (MG_Impl/GLImpl): replace Flywheel dispatch sync hack with MOBILEGL_COHERENT_AS_FLUSH

This commit is contained in:
2026-07-15 21:51:20 -04:00
parent f80f6f4a62
commit 3e4ce5caa7
28 changed files with 295 additions and 62 deletions
+3 -1
View File
@@ -299,7 +299,8 @@ function(add_trace_replay_test CASE_NAME BACKEND)
CROP_X
CROP_Y
CROP_WIDTH
CROP_HEIGHT)
CROP_HEIGHT
COHERENT_AS_FLUSH)
cmake_parse_arguments(TRACE_CASE "" "${oneValueArgs}" "" ${ARGN})
foreach(required TRACE_ARCHIVE GOLDEN TARGET_CALL WIDTH HEIGHT)
if(NOT TRACE_CASE_${required})
@@ -343,6 +344,7 @@ function(add_trace_replay_test CASE_NAME BACKEND)
-DTRACE_CROP_Y=${TRACE_CASE_CROP_Y}
-DTRACE_CROP_WIDTH=${TRACE_CASE_CROP_WIDTH}
-DTRACE_CROP_HEIGHT=${TRACE_CASE_CROP_HEIGHT}
-DTRACE_COHERENT_AS_FLUSH=${TRACE_CASE_COHERENT_AS_FLUSH}
-DTRACE_OUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}/${CASE_NAME}/${BACKEND}
-DTRACE_ARTIFACT_DIR=${CMAKE_CURRENT_BINARY_DIR}/${CASE_NAME}/actual-images
-P ${MOBILEGL_TRACE_ROOT}/run_trace_case.cmake)
+4 -1
View File
@@ -225,4 +225,7 @@ adb exec-out run-as $PKG cat files/trace-replay/output/openra-diff.png > openra-
For the Vulkan backend, build and install `:app:assembleMagmaTraceDebug`, set
`PKG=top.mobilegl.plugin.magma.trace`, and pass `--es backend DirectVulkan`.
DirectGLES also renders to the Activity surface by default; pass
`--ez use_pbuffer true` to use the offscreen pbuffer path.
`--ez use_pbuffer true` to use the offscreen pbuffer path. For cases registered
with `coherent_as_flush` (Flywheel-style unflushed persistent maps, e.g. the
Create fixtures), pass `--ez coherent_as_flush true` so the replay runs with
`MOBILEGL_COHERENT_AS_FLUSH=1`.
@@ -176,6 +176,8 @@ def run_case(case, backend):
command.append("--use-pbuffer")
if backend_info["use_angle"] and case["name"] == BLISS_CASE:
command.append("--avoid-angle-llvmpipe-sampler-mipmap-min-filter")
if case.get("coherent_as_flush"):
command.append("--coherent-as-flush")
env = dict(**__import__("os").environ)
env["PYTHON"] = "python"
env["MSYS2_ARG_CONV_EXCL"] = "/data/*"
@@ -361,6 +361,8 @@ def run_case(case, backend, replay_exe, mobilegl_library, vulkan_icd):
str(case["crop_height"]),
"--window-surface",
]
if case.get("coherent_as_flush"):
command.append("--coherent-as-flush")
env = os.environ.copy()
env["MOBILEGL_BACKEND_TYPE"] = backend
env["MOBILEGL_MAGMA_R11G11B10F_FALLBACK"] = "1"
+5
View File
@@ -23,6 +23,10 @@ set(alternate_golden_args)
if(DEFINED TRACE_ALTERNATE_GOLDEN AND NOT "${TRACE_ALTERNATE_GOLDEN}" STREQUAL "")
list(APPEND alternate_golden_args --alternate-golden "${TRACE_ALTERNATE_GOLDEN}")
endif()
set(coherent_as_flush_args)
if(TRACE_COHERENT_AS_FLUSH)
list(APPEND coherent_as_flush_args --coherent-as-flush)
endif()
if(EXISTS "${TRACE_OUTPUT_DIR}")
file(REMOVE_RECURSE "${TRACE_OUTPUT_DIR}")
@@ -64,6 +68,7 @@ execute_process(
--crop-y "${TRACE_CROP_Y}"
--crop-width "${TRACE_CROP_WIDTH}"
--crop-height "${TRACE_CROP_HEIGHT}"
${coherent_as_flush_args}
RESULT_VARIABLE replay_result
OUTPUT_VARIABLE replay_stdout
ERROR_VARIABLE replay_stderr)
@@ -121,7 +121,10 @@ depends on them - the symptom is geometry that renders live but disappears in
replay. The in-tree fork shadow-tracks persistent mappings unconditionally;
if a replay of `full.trace` is already missing content that the live run
showed, fix capture (wrapper) first - no amount of trimming will bring the
data back, and the case must be recaptured.
data back, and the case must be recaptured. There is also a replay-side
requirement: MobileGL only forwards such never-flushed writes when
`MOBILEGL_COHERENT_AS_FLUSH=1`, so register the case with
`"coherent_as_flush": true` (see "Register the case").
## Select target frame
@@ -288,8 +291,12 @@ Values matching the `defaults` block (854x480, `trace.trace`, ssim 0.99, zero
crop, 900 s timeout) may be omitted. Available per-case keys: `name`,
`trace_archive`, `trace_file`, `golden`, `alternate_golden`, `target_call`,
`width`, `height`, `ssim_threshold`, `crop_x/y/width/height`,
`timeout_seconds`, `ci`. Long single-frame replays of heavy in-world scenes
need a raised `timeout_seconds` (the Create fixtures use 1800).
`timeout_seconds`, `ci`, `coherent_as_flush`. Long single-frame replays of
heavy in-world scenes need a raised `timeout_seconds` (the Create fixtures
use 1800). Set `"coherent_as_flush": true` for Flywheel-style engines that
let the GPU read persistent `GL_MAP_FLUSH_EXPLICIT_BIT` mappings they never
flush (both Create fixtures need it); the case then replays with
`MOBILEGL_COHERENT_AS_FLUSH=1` on every runner.
Update `tools/trace_replay/README.md` with one fixture sentence and one golden
image link.
+4 -2
View File
@@ -263,14 +263,16 @@
"trace_archive": "minecraft-1.21.1-neoforge-create-indirect-in-world.tgz",
"golden": "minecraft-1.21.1-neoforge-create-indirect-in-world.0000504631.png",
"target_call": 504631,
"timeout_seconds": 1800
"timeout_seconds": 1800,
"coherent_as_flush": true
},
{
"name": "minecraft-1.21.1-neoforge-create-instancing-in-world",
"trace_archive": "minecraft-1.21.1-neoforge-create-instancing-in-world.tgz",
"golden": "minecraft-1.21.1-neoforge-create-instancing-in-world.0000530333.png",
"target_call": 530333,
"timeout_seconds": 1800
"timeout_seconds": 1800,
"coherent_as_flush": true
}
]
}
+1
View File
@@ -91,6 +91,7 @@ def emit_cmake(cases, fixture_root):
("CROP_Y", "crop_y", False),
("CROP_WIDTH", "crop_width", False),
("CROP_HEIGHT", "crop_height", False),
("COHERENT_AS_FLUSH", "coherent_as_flush", False),
]
for case in cases:
lines.append(f"add_trace_replay_test_for_backends({cmake_quote(case['name'])}")
+4 -1
View File
@@ -27,7 +27,8 @@ void PrintUsage(const char *argv0) {
<< " --crop-x N Compare crop x\n"
<< " --crop-y N Compare crop y\n"
<< " --crop-width N Compare crop width\n"
<< " --crop-height N Compare crop height\n";
<< " --crop-height N Compare crop height\n"
<< " --coherent-as-flush Set MOBILEGL_COHERENT_AS_FLUSH=1 for the replay\n";
}
bool ReadValue(int argc, char **argv, int &index, std::string &out) {
@@ -113,6 +114,8 @@ bool ParseArgs(int argc, char **argv, mobilegl_trace::Request &request) {
if (!ReadInt(argc, argv, i, request.cropWidth)) return false;
} else if (arg == "--crop-height") {
if (!ReadInt(argc, argv, i, request.cropHeight)) return false;
} else if (arg == "--coherent-as-flush") {
request.coherentAsFlush = true;
} else if (arg == "--help" || arg == "-h") {
return false;
} else {