diff --git a/.github/workflows/apk.yml b/.github/workflows/apk.yml index 8733c7c7..5230ae3d 100644 --- a/.github/workflows/apk.yml +++ b/.github/workflows/apk.yml @@ -145,89 +145,43 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Retrace and validate Espryt (DirectGLES) - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 35 - target: google_apis - arch: x86_64 - profile: pixel_6 - disable-animations: true - emulator-options: -no-window -gpu swiftshader -no-snapshot -noaudio -no-boot-anim -camera-back none -camera-front none - script: | - set +e - status=0 - apk_file="$(find android-retrace-apks -name 'MobileGL-EsprytTrace-release.apk' -print -quit)" - printf '%s\n' "${TRACE_REPLAY_CASES}" > android-retrace-cases.txt - while IFS='|' read -r case_name trace_archive trace_file golden target_call width height tolerance crop_x crop_y crop_width crop_height fuzz_percent timeout_seconds; do - [ -n "${case_name}" ] || continue - 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 "${case_name}" \ - --trace-archive "${trace_archive}" \ - --trace-file "${trace_file}" \ - --golden "${golden}" \ - --target-call "${target_call}" \ - --width "${width}" \ - --height "${height}" \ - --tolerance "${tolerance}" \ - --crop-x "${crop_x}" \ - --crop-y "${crop_y}" \ - --crop-width "${crop_width}" \ - --crop-height "${crop_height}" \ - --fuzz-percent "${fuzz_percent}" \ - --timeout-seconds "${timeout_seconds}" \ - || status=1 - done < android-retrace-cases.txt - mkdir -p android-retrace-result/status - echo "${status}" > android-retrace-result/status/DirectGLES.status - exit 0 + run: | + printf '%s\n' "${TRACE_REPLAY_CASES}" > android-retrace-cases.txt + apk_file="$(find android-retrace-apks -name 'MobileGL-EsprytTrace-release.apk' -print -quit)" + sh android-plugin/run-avd-ci.sh \ + --api-level 35 \ + --target google_apis \ + --arch x86_64 \ + --profile pixel_6 \ + --gpu swiftshader \ + --avd-name mobilegl-espryt \ + -- sh android-plugin/run-trace-replay-cases-ci.sh \ + --apk-file "${apk_file}" \ + --package top.mobilegl.plugin.espryt.trace \ + --backend DirectGLES \ + --cases-file android-retrace-cases.txt \ + --result-root android-retrace-result \ + --fixture-root android-retrace-fixture - name: Retrace and validate Magma (DirectVulkan) if: always() - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 35 - target: google_apis - arch: x86_64 - profile: pixel_6 - disable-animations: true - emulator-options: -no-window -gpu angle -no-snapshot -noaudio -no-boot-anim -camera-back none -camera-front none - script: | - set +e - status=0 - apk_file="$(find android-retrace-apks -name 'MobileGL-MagmaTrace-release.apk' -print -quit)" - printf '%s\n' "${TRACE_REPLAY_CASES}" > android-retrace-cases.txt - while IFS='|' read -r case_name trace_archive trace_file golden target_call width height tolerance crop_x crop_y crop_width crop_height fuzz_percent timeout_seconds; do - [ -n "${case_name}" ] || continue - 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 "${case_name}" \ - --trace-archive "${trace_archive}" \ - --trace-file "${trace_file}" \ - --golden "${golden}" \ - --target-call "${target_call}" \ - --width "${width}" \ - --height "${height}" \ - --tolerance "${tolerance}" \ - --crop-x "${crop_x}" \ - --crop-y "${crop_y}" \ - --crop-width "${crop_width}" \ - --crop-height "${crop_height}" \ - --fuzz-percent "${fuzz_percent}" \ - --timeout-seconds "${timeout_seconds}" \ - || status=1 - done < android-retrace-cases.txt - mkdir -p android-retrace-result/status - echo "${status}" > android-retrace-result/status/DirectVulkan.status - exit 0 + run: | + printf '%s\n' "${TRACE_REPLAY_CASES}" > android-retrace-cases.txt + apk_file="$(find android-retrace-apks -name 'MobileGL-MagmaTrace-release.apk' -print -quit)" + sh android-plugin/run-avd-ci.sh \ + --api-level 35 \ + --target google_apis \ + --arch x86_64 \ + --profile pixel_6 \ + --gpu angle \ + --avd-name mobilegl-magma \ + -- sh android-plugin/run-trace-replay-cases-ci.sh \ + --apk-file "${apk_file}" \ + --package top.mobilegl.plugin.magma.trace \ + --backend DirectVulkan \ + --cases-file android-retrace-cases.txt \ + --result-root android-retrace-result \ + --fixture-root android-retrace-fixture - name: Upload Android retrace result if: always() diff --git a/android-plugin/run-avd-ci.sh b/android-plugin/run-avd-ci.sh new file mode 100644 index 00000000..7d61c79c --- /dev/null +++ b/android-plugin/run-avd-ci.sh @@ -0,0 +1,115 @@ +#!/bin/sh +set -eu + +usage() { + cat <<'EOF' +Usage: + sh android-plugin/run-avd-ci.sh \ + --api-level N \ + --target TARGET \ + --arch ARCH \ + --profile PROFILE \ + --gpu GPU \ + --avd-name NAME \ + -- COMMAND [ARGS ...] +EOF +} + +die() { + echo "run-avd-ci.sh: $*" >&2 + usage >&2 + exit 2 +} + +next_arg() { + if [ "$#" -lt 2 ]; then + die "$1 requires a value" + fi + printf '%s' "$2" +} + +require_value() { + value="$1" + name="$2" + if [ -z "${value}" ]; then + die "missing ${name}" + fi +} + +api_level="" +target="" +arch="" +profile="" +gpu="" +avd_name="" + +while [ "$#" -gt 0 ]; do + case "$1" in + --api-level) api_level="$(next_arg "$@")"; shift 2 ;; + --target) target="$(next_arg "$@")"; shift 2 ;; + --arch) arch="$(next_arg "$@")"; shift 2 ;; + --profile) profile="$(next_arg "$@")"; shift 2 ;; + --gpu) gpu="$(next_arg "$@")"; shift 2 ;; + --avd-name) avd_name="$(next_arg "$@")"; shift 2 ;; + --) shift; break ;; + -h|--help) usage; exit 0 ;; + *) die "unknown argument: $1" ;; + esac +done + +require_value "${api_level}" "--api-level" +require_value "${target}" "--target" +require_value "${arch}" "--arch" +require_value "${profile}" "--profile" +require_value "${gpu}" "--gpu" +require_value "${avd_name}" "--avd-name" + +if [ "$#" -eq 0 ]; then + die "missing command" +fi + +system_image="system-images;android-${api_level};${target};${arch}" +sdkmanager "platform-tools" "emulator" "platforms;android-${api_level}" "${system_image}" +echo no | avdmanager create avd --force --name "${avd_name}" --package "${system_image}" --device "${profile}" + +emulator_log="${RUNNER_TEMP:-.}/${avd_name}-emulator.log" +emulator -avd "${avd_name}" \ + -no-window \ + -gpu "${gpu}" \ + -no-snapshot \ + -noaudio \ + -no-boot-anim \ + -camera-back none \ + -camera-front none \ + > "${emulator_log}" 2>&1 & +emulator_pid="$!" + +cleanup() { + if kill -0 "${emulator_pid}" 2>/dev/null; then + adb -s emulator-5554 emu kill >/dev/null 2>&1 || kill "${emulator_pid}" >/dev/null 2>&1 || true + fi +} +trap cleanup EXIT INT TERM + +adb wait-for-device + +booted="" +for _ in $(seq 1 300); do + booted="$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r' || true)" + if [ "${booted}" = "1" ]; then + break + fi + sleep 1 +done + +if [ "${booted}" != "1" ]; then + cat "${emulator_log}" >&2 || true + die "emulator did not boot" +fi + +adb shell settings put global window_animation_scale 0 +adb shell settings put global transition_animation_scale 0 +adb shell settings put global animator_duration_scale 0 +adb shell input keyevent 82 || true + +"$@" diff --git a/android-plugin/run-trace-replay-cases-ci.sh b/android-plugin/run-trace-replay-cases-ci.sh new file mode 100644 index 00000000..585d8102 --- /dev/null +++ b/android-plugin/run-trace-replay-cases-ci.sh @@ -0,0 +1,105 @@ +#!/bin/sh +set -eu + +usage() { + cat <<'EOF' +Usage: + sh android-plugin/run-trace-replay-cases-ci.sh \ + --apk-file FILE \ + --package PACKAGE \ + --backend BACKEND \ + --cases-file FILE \ + --result-root DIR \ + --fixture-root DIR +EOF +} + +die() { + echo "run-trace-replay-cases-ci.sh: $*" >&2 + usage >&2 + exit 2 +} + +next_arg() { + if [ "$#" -lt 2 ]; then + die "$1 requires a value" + fi + printf '%s' "$2" +} + +require_value() { + value="$1" + name="$2" + if [ -z "${value}" ]; then + die "missing ${name}" + fi +} + +apk_file="" +package_name="" +backend="" +cases_file="" +result_root="" +fixture_root="" + +while [ "$#" -gt 0 ]; do + case "$1" in + --apk-file) apk_file="$(next_arg "$@")"; shift 2 ;; + --package) package_name="$(next_arg "$@")"; shift 2 ;; + --backend) backend="$(next_arg "$@")"; shift 2 ;; + --cases-file) cases_file="$(next_arg "$@")"; shift 2 ;; + --result-root) result_root="$(next_arg "$@")"; shift 2 ;; + --fixture-root) fixture_root="$(next_arg "$@")"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) die "unknown argument: $1" ;; + esac +done + +require_value "${apk_file}" "--apk-file" +require_value "${package_name}" "--package" +require_value "${backend}" "--backend" +require_value "${cases_file}" "--cases-file" +require_value "${result_root}" "--result-root" +require_value "${fixture_root}" "--fixture-root" + +status=0 +mkdir -p "${result_root}/status" + +if [ ! -f "${apk_file}" ]; then + echo "APK does not exist: ${apk_file}" >&2 + echo 1 > "${result_root}/status/${backend}.status" + exit 0 +fi + +if [ ! -f "${cases_file}" ]; then + echo "cases file does not exist: ${cases_file}" >&2 + echo 1 > "${result_root}/status/${backend}.status" + exit 0 +fi + +while IFS='|' read -r case_name trace_archive trace_file golden target_call width height tolerance crop_x crop_y crop_width crop_height fuzz_percent timeout_seconds; do + [ -n "${case_name}" ] || continue + sh android-plugin/trace-replay-ci.sh \ + --apk-file "${apk_file}" \ + --package "${package_name}" \ + --backend "${backend}" \ + --result-root "${result_root}" \ + --fixture-root "${fixture_root}" \ + --case "${case_name}" \ + --trace-archive "${trace_archive}" \ + --trace-file "${trace_file}" \ + --golden "${golden}" \ + --target-call "${target_call}" \ + --width "${width}" \ + --height "${height}" \ + --tolerance "${tolerance}" \ + --crop-x "${crop_x}" \ + --crop-y "${crop_y}" \ + --crop-width "${crop_width}" \ + --crop-height "${crop_height}" \ + --fuzz-percent "${fuzz_percent}" \ + --timeout-seconds "${timeout_seconds}" \ + || status=1 +done < "${cases_file}" + +echo "${status}" > "${result_root}/status/${backend}.status"