diff --git a/tools/trace_replay/skills/trace-fixture-authoring.md b/tools/trace_replay/skills/trace-fixture-authoring.md new file mode 100644 index 00000000..4d803d12 --- /dev/null +++ b/tools/trace_replay/skills/trace-fixture-authoring.md @@ -0,0 +1,327 @@ +# Trace fixture authoring + +## Variables + +```sh +export REPO="$PWD" +export WORK="$PWD/.trace-work" +export CASE="case-name" +export WIDTH=854 +export HEIGHT=480 +export TARGET_CALL=0 +``` + +## Prerequisites + +```sh +git clone --recursive MobileGL +cd MobileGL +git lfs install +git lfs pull +``` + +Install: + +- CMake +- Ninja +- C++ compiler +- Python 3 +- Mesa OpenGL/EGL runtime +- Vulkan loader and ICD for `DirectVulkan` +- Pillow or ImageMagick for alpha cleanup +- Android SDK, Android NDK, JDK, Gradle, and `adb` for Android replay + +## Build apitrace + +```sh +cmake -S "$REPO/3rdparty/apitrace" -B "$WORK/build-apitrace" -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_GUI=OFF +cmake --build "$WORK/build-apitrace" --target apitrace glretrace --parallel + +export APITRACE="$(find "$WORK/build-apitrace" -type f -name apitrace -perm -111 | head -n 1)" +export GLRETRACE="$(find "$WORK/build-apitrace" -type f -name glretrace -perm -111 | head -n 1)" +test -n "$APITRACE" +test -n "$GLRETRACE" +``` + +On Windows, set `APITRACE` and `GLRETRACE` to the corresponding `.exe` files. + +## Prepare the capture + +- Set the target window size to `WIDTH` x `HEIGHT`. +- Disable unintended overlays, frame counters, notifications, and launcher UI. +- Fix language, resource packs, mods, shader pack, world seed, time, weather, + player position, camera direction, FOV, GUI scale, and render distance. +- Trace the final OpenGL process, not the launcher. +- For Minecraft, document version, mod loader, mods, shader pack, language, + world, time, and camera setup. + +## Capture + +```sh +mkdir -p "$WORK/$CASE" +"$APITRACE" trace --api=gl \ + --output "$WORK/$CASE/full.trace" \ + -- +``` + +For Java: + +```sh +"$APITRACE" trace --api=gl \ + --output "$WORK/$CASE/full.trace" \ + -- "$JAVA_EXE" +``` + +Keep `full.trace` until both backends are validated. + +## Select target call + +```sh +mkdir -p "$WORK/$CASE/probe" +for call in $(seq "$START_CALL" "$STEP_CALL" "$END_CALL"); do + "$APITRACE" replay --headless \ + --snapshot-prefix "$WORK/$CASE/probe/$CASE." \ + --snapshot="$call" \ + --call-nos \ + "$WORK/$CASE/full.trace" || true +done +``` + +Inspect the PNGs and set: + +```sh +export TARGET_CALL= +``` + +## Trim and package + +```sh +"$APITRACE" trim \ + --calls="$TARGET_CALL" \ + --output "$WORK/$CASE/trace.trace" \ + "$WORK/$CASE/full.trace" +``` + +## Generate golden + +Generate the golden from the trimmed trace: + +```sh +mkdir -p "$WORK/$CASE/golden" +"$APITRACE" replay --headless \ + --snapshot-prefix "$WORK/$CASE/golden/$CASE." \ + --snapshot="$TARGET_CALL" \ + --call-nos \ + "$WORK/$CASE/trace.trace" + +GOLDEN_SRC="$WORK/$CASE/golden/$CASE.$(printf '%010d' "$TARGET_CALL").png" +``` + +Remove unintended alpha: + +```sh +python3 - "$GOLDEN_SRC" "$WORK/$CASE/$CASE.$(printf '%010d' "$TARGET_CALL").png" <<'PY' +import sys +from PIL import Image + +src, dst = sys.argv[1], sys.argv[2] +img = Image.open(src).convert("RGBA") +bg = Image.new("RGBA", img.size, (0, 0, 0, 255)) +bg.alpha_composite(img) +bg.convert("RGB").save(dst) +PY +``` + +Or copy directly: + +```sh +cp "$GOLDEN_SRC" "$WORK/$CASE/$CASE.$(printf '%010d' "$TARGET_CALL").png" +``` + +Package: + +```sh +mkdir -p "$WORK/$CASE/archive" +cp "$WORK/$CASE/trace.trace" "$WORK/$CASE/archive/trace.trace" +tar -czf "$REPO/tools/trace_replay/fixtures/$CASE.tgz" \ + -C "$WORK/$CASE/archive" trace.trace +cp "$WORK/$CASE/$CASE.$(printf '%010d' "$TARGET_CALL").png" \ + "$REPO/tools/trace_replay/fixtures/" +``` + +Track with Git LFS: + +```sh +git lfs track "tools/trace_replay/fixtures/*.tgz" +git lfs track "tools/trace_replay/fixtures/*.png" +git add .gitattributes tools/trace_replay/fixtures/$CASE.tgz \ + tools/trace_replay/fixtures/$CASE.$(printf '%010d' "$TARGET_CALL").png +git lfs status +``` + +## Register Linux replay + +Edit `tools/trace_replay/CMakeLists.txt`: + +```cmake +add_trace_replay_test_for_backends(case-name + TRACE_ARCHIVE ${MOBILEGL_TRACE_ROOT}/fixtures/case-name.tgz + TRACE_FILE trace.trace + GOLDEN ${MOBILEGL_TRACE_ROOT}/fixtures/case-name.0000000000.png + TARGET_CALL 0 + WIDTH 854 + HEIGHT 480 + TOLERANCE 20 + FUZZ_PERCENT 20) +``` + +Optional crop: + +```cmake + CROP_X 1 + CROP_Y 1 + CROP_WIDTH 852 + CROP_HEIGHT 478 +``` + +## Register Android replay + +Edit `.github/workflows/apk.yml` `TRACE_REPLAY_CASES`: + +```text +case-name|tools/trace_replay/fixtures/case-name.tgz|trace.trace|tools/trace_replay/fixtures/case-name.0000000000.png|0|854|480|20|0|0|0|0|20|900 +``` + +Field order: + +```text +case|trace archive|trace file|golden|target call|width|height|tolerance|crop x|crop y|crop width|crop height|fuzz percent|timeout seconds +``` + +Update `tools/trace_replay/README.md` with one fixture sentence and one golden +image link. + +## Validate on Linux + +```sh +cmake -S "$REPO" -B "$WORK/build-linux" -G Ninja \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DMOBILEGL_BUILD_TEST=ON \ + -DMOBILEGL_BUILD_BENCHMARK=OFF \ + -DMOBILEGL_BUILD_TRACE_REPLAY=ON \ + -DMOBILEGL_LOG_ACTIVE_LEVEL=MOBILEGL_LOG_LEVEL_INFO +cmake --build "$WORK/build-linux" --target mobilegl_trace_replay --parallel +``` + +Run the registered case: + +```sh +ctest --test-dir "$WORK/build-linux/tools/trace_replay" -V \ + -R "MobileGLTraceReplay\\.$CASE\\." +``` + +Run one backend manually: + +```sh +cmake \ + -DTRACE_REPLAY_EXE="$WORK/build-linux/tools/trace_replay/mobilegl_trace_replay" \ + -DMOBILEGL_LIBRARY="$WORK/build-linux/libMobileGL.so" \ + -DTRACE_CASE_NAME="$CASE" \ + -DTRACE_ARCHIVE="$REPO/tools/trace_replay/fixtures/$CASE.tgz" \ + -DTRACE_FILE=trace.trace \ + -DTRACE_GOLDEN="$REPO/tools/trace_replay/fixtures/$CASE.$(printf '%010d' "$TARGET_CALL").png" \ + -DTRACE_BACKEND=DirectGLES \ + -DTRACE_TARGET_CALL="$TARGET_CALL" \ + -DTRACE_WIDTH="$WIDTH" \ + -DTRACE_HEIGHT="$HEIGHT" \ + -DTRACE_TOLERANCE=20 \ + -DTRACE_CROP_X=0 \ + -DTRACE_CROP_Y=0 \ + -DTRACE_CROP_WIDTH=0 \ + -DTRACE_CROP_HEIGHT=0 \ + -DTRACE_FUZZ_PERCENT=20 \ + -DTRACE_OUTPUT_DIR="$WORK/$CASE/linux-DirectGLES" \ + -DTRACE_ARTIFACT_DIR="$WORK/$CASE/linux-artifacts" \ + -P "$REPO/tools/trace_replay/run_trace_case.cmake" +``` + +DirectGLES CI env: + +```sh +export EGL_PLATFORM=surfaceless +export LIBGL_ALWAYS_SOFTWARE=1 +export MESA_GL_VERSION_OVERRIDE=3.3 +export MESA_GLSL_VERSION_OVERRIDE=330 +``` + +DirectVulkan check: + +```sh +vulkaninfo | grep -E 'deviceName|VK_EXT_headless_surface' +``` + +## Validate on Android + +Build trace APKs: + +```sh +gradle --no-daemon -p "$REPO/android-plugin" \ + :app:assembleEsprytTraceRelease \ + :app:assembleMagmaTraceRelease \ + -Pmobilegl.abis=all \ + -Pmobilegl.debuggableRelease=true \ + -Pmobilegl.logLevel=MOBILEGL_LOG_LEVEL_INFO \ + --parallel +``` + +Run DirectGLES: + +```sh +sh "$REPO/android-plugin/trace-replay-ci.sh" \ + --apk-file "$REPO/android-plugin/app/build/outputs/apk/esprytTrace/release/MobileGL-EsprytTrace-release.apk" \ + --package top.mobilegl.plugin.espryt.trace \ + --backend DirectGLES \ + --result-root "$WORK/$CASE/android-result" \ + --fixture-root "$WORK/$CASE/android-fixture" \ + --case "$CASE" \ + --trace-archive "$REPO/tools/trace_replay/fixtures/$CASE.tgz" \ + --trace-file trace.trace \ + --golden "$REPO/tools/trace_replay/fixtures/$CASE.$(printf '%010d' "$TARGET_CALL").png" \ + --target-call "$TARGET_CALL" \ + --width "$WIDTH" \ + --height "$HEIGHT" \ + --tolerance 20 \ + --crop-x 0 \ + --crop-y 0 \ + --crop-width 0 \ + --crop-height 0 \ + --fuzz-percent 20 \ + --timeout-seconds 900 +``` + +Run DirectVulkan with: + +- APK: `MobileGL-MagmaTrace-release.apk` +- package: `top.mobilegl.plugin.magma.trace` +- backend: `DirectVulkan` + +Inspect: + +- `$WORK/$CASE/android-result/$CASE-DirectGLES/result.json` +- `$WORK/$CASE/android-result/$CASE-DirectGLES/$CASE-DirectGLES-actual.png` +- `$WORK/$CASE/android-result/$CASE-DirectGLES/$CASE-DirectGLES-diff.png` +- `$WORK/$CASE/android-result/$CASE-DirectGLES/retrace.log` +- `$WORK/$CASE/android-result/$CASE-DirectGLES/logcat.txt` + +## Checklist + +- Golden matches the committed trace and target call. +- Archive contains only `trace.trace`. +- Both Linux backends pass before Linux CI registration. +- Both Android backends pass before APK CI registration. +- `actual.png` and `case-diff.png` are inspected. +- Fixture `.tgz` and `.png` files are tracked by Git LFS. +- No build output, extracted trace directory, temporary report, or debug text is + staged.