Files
MobileGL/tools/trace_replay/skills/trace-fixture-authoring.md
T

8.2 KiB

Trace fixture authoring

Variables

export REPO="$PWD"
export WORK="$PWD/.trace-work"
export CASE="case-name"
export WIDTH=854
export HEIGHT=480
export TARGET_CALL=0

Prerequisites

git clone --recursive <mobilegl-repo-url> 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

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

mkdir -p "$WORK/$CASE"
"$APITRACE" trace --api=gl \
  --output "$WORK/$CASE/full.trace" \
  -- <application-command> <application-args>

For Java:

"$APITRACE" trace --api=gl \
  --output "$WORK/$CASE/full.trace" \
  -- "$JAVA_EXE" <jvm-args> <main-class-or-jar> <game-args>

Keep full.trace until both backends are validated.

Select target call

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:

export TARGET_CALL=<chosen-call-number>

Trim and package

"$APITRACE" trim \
  --calls="$TARGET_CALL" \
  --output "$WORK/$CASE/trace.trace" \
  "$WORK/$CASE/full.trace"

Generate golden

Generate the golden from the trimmed trace:

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:

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:

cp "$GOLDEN_SRC" "$WORK/$CASE/$CASE.$(printf '%010d' "$TARGET_CALL").png"

Package:

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:

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:

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:

        CROP_X 1
        CROP_Y 1
        CROP_WIDTH 852
        CROP_HEIGHT 478

Register Android replay

Edit .github/workflows/apk.yml TRACE_REPLAY_CASES:

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:

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

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:

ctest --test-dir "$WORK/build-linux/tools/trace_replay" -V \
  -R "MobileGLTraceReplay\\.$CASE\\."

Run one backend manually:

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:

export EGL_PLATFORM=surfaceless
export LIBGL_ALWAYS_SOFTWARE=1
export MESA_GL_VERSION_OVERRIDE=3.3
export MESA_GLSL_VERSION_OVERRIDE=330

DirectVulkan check:

vulkaninfo | grep -E 'deviceName|VK_EXT_headless_surface'

Validate on Android

Build trace APKs:

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 "$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.