name: MobileGL APK on: push: branches: - dev - Feat/Backend-Direct-GLES - Feat/Backend-Direct-Vulkan workflow_dispatch: jobs: build: runs-on: ubuntu-latest env: CCACHE_BASEDIR: ${{ github.workspace }} CCACHE_COMPRESS: "true" CCACHE_DIR: ${{ github.workspace }}/.ccache CCACHE_MAXSIZE: 4G CCACHE_NOHASHDIR: "true" MOBILEGL_CMAKE_COMPILER_LAUNCHER: ccache steps: - name: Checkout repo uses: actions/checkout@v4 with: submodules: recursive - name: Set artifact metadata run: | echo "date_today=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV" echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_ENV" - name: Set up JDK uses: actions/setup-java@v4 with: distribution: zulu java-version: '17' - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 with: gradle-version: 8.10.2 - name: Restore ccache uses: actions/cache@v4 with: path: .ccache key: ${{ runner.os }}-apk-${{ github.job }}-ccache-${{ github.ref_name }}-${{ github.run_id }} restore-keys: | ${{ runner.os }}-apk-${{ github.job }}-ccache-${{ github.ref_name }}- ${{ runner.os }}-apk-${{ github.job }}-ccache- - name: Install ccache run: | sudo apt-get update sudo apt-get install -y ccache ccache --version - name: Setup Android SDK uses: android-actions/setup-android@v3 with: accept-android-sdk-licenses: false - name: Accept Android SDK licenses run: yes | sdkmanager --licenses >/dev/null - name: Install Android NDK run: | sdkmanager "ndk;27.3.13750724" echo "ndk.dir=$ANDROID_HOME/ndk/27.3.13750724" >> android-plugin/local.properties - name: Update glslang external sources working-directory: 3rdparty/glslang run: python update_glslang_sources.py - name: Build plugin APKs run: gradle --no-daemon -p android-plugin :app:assembleEsprytPluginRelease :app:assembleMagmaPluginRelease -Pmobilegl.logLevel=MOBILEGL_LOG_LEVEL_INFO --parallel --max-workers "$(nproc)" env: SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }} SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }} SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }} - name: Download ANGLE x86_64 libraries run: | angle_dir="android-plugin/app/src/trace/jniLibs/x86_64" angle_commit="f2a3d510dffd8f6540a52e1a7d0c5787d151075b" angle_base="https://raw.githubusercontent.com/FCL-Team/FoldCraftLauncher/${angle_commit}/FCLauncher/src/main/jniLibs/x86_64" mkdir -p "${angle_dir}" curl -L --fail --retry 3 -o "${angle_dir}/libEGL_angle.so" "${angle_base}/libEGL_angle.so" curl -L --fail --retry 3 -o "${angle_dir}/libGLESv2_angle.so" "${angle_base}/libGLESv2_angle.so" test -s "${angle_dir}/libEGL_angle.so" test -s "${angle_dir}/libGLESv2_angle.so" echo "c41828768d089899fa058ec0bee711a91be88347f29bdb935223da6be1149c40 ${angle_dir}/libEGL_angle.so" | sha256sum -c - echo "e4f820d99f94365c66df868c7740fef142fe5c0cd7c941790a9e30638857ca4d ${angle_dir}/libGLESv2_angle.so" | sha256sum -c - - name: Build retrace APKs run: gradle --no-daemon -p android-plugin :app:assembleEsprytTraceRelease :app:assembleMagmaTraceRelease -Pmobilegl.abis=all -Pmobilegl.debuggableRelease=true -Pmobilegl.logLevel=MOBILEGL_LOG_LEVEL_INFO --parallel --max-workers "$(nproc)" env: SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }} SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }} SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }} - name: Show ccache stats if: always() run: ccache --show-stats - name: Verify signed APKs run: | APKSIGNER="$(find "$ANDROID_HOME/build-tools" -name apksigner -type f | sort -V | tail -n 1)" mapfile -t APKS < <(find android-plugin/app/build/outputs/apk -type f -path '*/release/*.apk' | sort) if [ "${#APKS[@]}" -eq 0 ]; then echo "::error::No release APKs found under android-plugin/app/build/outputs/apk" find android-plugin/app/build/outputs/apk -type f -print || true exit 1 fi for APK in "${APKS[@]}"; do if [[ "$APK" == *-unsigned.apk ]]; then echo "::error::Unsigned release APK produced: $APK" exit 1 fi "$APKSIGNER" verify --verbose "$APK" done - name: Upload plugin APK uses: actions/upload-artifact@v4 with: name: MobileGL-plugin-${{ env.date_today }}-${{ env.short_sha }} path: android-plugin/app/build/outputs/apk/*Plugin/release/*.apk if-no-files-found: error - name: Upload retrace APK uses: actions/upload-artifact@v4 with: name: MobileGL-retrace-apk-${{ env.date_today }}-${{ env.short_sha }} path: android-plugin/app/build/outputs/apk/*Trace/release/*.apk if-no-files-found: error trace-cases: name: trace case matrix runs-on: ubuntu-latest needs: build outputs: android: ${{ steps.trace-cases.outputs.android }} names: ${{ steps.trace-cases.outputs.names }} steps: - name: Checkout repo uses: actions/checkout@v4 - name: Load trace cases id: trace-cases run: | echo "android=$(python3 tools/trace_replay/trace_cases.py --ci --format github-apk)" >> "$GITHUB_OUTPUT" echo "names=$(python3 tools/trace_replay/trace_cases.py --ci --format names)" >> "$GITHUB_OUTPUT" trace-fixtures: name: trace fixture (${{ matrix.case }}) runs-on: ubuntu-latest needs: trace-cases strategy: fail-fast: false max-parallel: 4 matrix: case: ${{ fromJSON(needs.trace-cases.outputs.names) }} steps: - name: Checkout repo uses: actions/checkout@v4 - name: Fetch trace fixture run: bash .github/scripts/fetch-trace-fixture-lfs.sh '${{ matrix.case }}' - name: Stage trace fixture run: | safe_case="$(printf '%s' '${{ matrix.case }}' | sed 's/[^A-Za-z0-9._-]/_/g')" stage_dir="trace-fixtures/${safe_case}" mkdir -p "${stage_dir}" python3 tools/trace_replay/trace_cases.py --format fixture-files --case '${{ matrix.case }}' | while IFS= read -r file; do cp "${file}" "${stage_dir}/" done - name: Upload trace fixture uses: actions/upload-artifact@v4 with: name: MobileGL-trace-fixture-${{ matrix.case }} path: trace-fixtures/** if-no-files-found: error android-avd: name: android avd image runs-on: ubuntu-latest env: AVD_NAME: mobilegl-ci ANDROID_AVD_HOME: ${{ github.workspace }}/.android/avd steps: - name: Checkout repo uses: actions/checkout@v4 - name: Setup Android SDK uses: android-actions/setup-android@v3 with: accept-android-sdk-licenses: false - name: Accept Android SDK licenses run: yes | sdkmanager --licenses >/dev/null - name: Restore Android AVD cache id: android-avd-cache uses: actions/cache@v4 with: path: | ${{ env.ANDROID_AVD_HOME }} /usr/local/lib/android/sdk/emulator /usr/local/lib/android/sdk/platform-tools /usr/local/lib/android/sdk/platforms/android-35 /usr/local/lib/android/sdk/system-images/android-35/google_apis/x86_64 key: ${{ runner.os }}-mobilegl-avd-api35-google_apis-x86_64-pixel_6-v1-${{ hashFiles('android-plugin/run-avd-ci.sh') }} - name: Create AVD if: steps.android-avd-cache.outputs.cache-hit != 'true' run: | sh android-plugin/run-avd-ci.sh create \ --api-level 35 \ --target google_apis \ --arch x86_64 \ --profile pixel_6 \ --avd-name "${AVD_NAME}" retrace: name: retrace (${{ matrix.backend.name }}, ${{ matrix.case.name }}) runs-on: ubuntu-latest needs: - build - android-avd - trace-cases - trace-fixtures if: ${{ always() && needs.build.result == 'success' && needs.android-avd.result == 'success' && needs.trace-cases.result == 'success' }} timeout-minutes: 75 env: AVD_NAME: mobilegl-ci ANDROID_AVD_HOME: ${{ github.workspace }}/.android/avd strategy: fail-fast: false max-parallel: 4 matrix: backend: - name: DirectGLES id: espryt apk: MobileGL-EsprytTrace-release.apk package: top.mobilegl.plugin.espryt.trace gpu: software - name: DirectVulkan id: magma apk: MobileGL-MagmaTrace-release.apk package: top.mobilegl.plugin.magma.trace gpu: lavapipe case: ${{ fromJSON(needs.trace-cases.outputs.android) }} steps: - name: Set Swap Space uses: pierotofy/set-swap-space@master with: swap-size-gb: 16 - name: Checkout repo uses: actions/checkout@v4 - name: Download trace fixture uses: actions/download-artifact@v4 with: name: MobileGL-trace-fixture-${{ matrix.case.name }} path: trace-fixture-download - name: Install trace fixture run: | mkdir -p tools/trace_replay/fixtures find trace-fixture-download -type f -exec cp {} tools/trace_replay/fixtures/ \; - name: Set artifact metadata run: | echo "date_today=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV" echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_ENV" echo "EMULATOR_LOG=${RUNNER_TEMP}/mobilegl-emulator.log" >> "$GITHUB_ENV" echo "EMULATOR_PID_FILE=${RUNNER_TEMP}/mobilegl-emulator.pid" >> "$GITHUB_ENV" - name: Setup Android SDK uses: android-actions/setup-android@v3 with: accept-android-sdk-licenses: false - name: Accept Android SDK licenses run: yes | sdkmanager --licenses >/dev/null - name: Restore Android AVD cache id: android-avd-cache uses: actions/cache/restore@v4 with: path: | ${{ env.ANDROID_AVD_HOME }} /usr/local/lib/android/sdk/emulator /usr/local/lib/android/sdk/platform-tools /usr/local/lib/android/sdk/platforms/android-35 /usr/local/lib/android/sdk/system-images/android-35/google_apis/x86_64 key: ${{ runner.os }}-mobilegl-avd-api35-google_apis-x86_64-pixel_6-v1-${{ hashFiles('android-plugin/run-avd-ci.sh') }} - name: Download retrace APKs uses: actions/download-artifact@v4 with: pattern: MobileGL-retrace-apk-* path: android-retrace-apks merge-multiple: true - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - name: Create AVD if: steps.android-avd-cache.outputs.cache-hit != 'true' run: | sh android-plugin/run-avd-ci.sh create \ --api-level 35 \ --target google_apis \ --arch x86_64 \ --profile pixel_6 \ --avd-name "${AVD_NAME}" - name: Launch Emulator run: | sh android-plugin/run-avd-ci.sh start \ --avd-name "${AVD_NAME}" \ --gpu "${{ matrix.backend.gpu }}" \ --emulator-log "${EMULATOR_LOG}" \ --pid-file "${EMULATOR_PID_FILE}" \ --boot-timeout 300 - name: Retrace and validate env: MOBILEGL_RETRACE_USE_ANGLE: ${{ matrix.backend.name == 'DirectGLES' && '1' || '0' }} MOBILEGL_VULKAN_R11G11B10F_FALLBACK: ${{ matrix.backend.name == 'DirectVulkan' && '1' || '0' }} run: | apk_file="$(find android-retrace-apks -name '${{ matrix.backend.apk }}' -print -quit)" extra_retrace_args=() # Bliss-specific workaround: this trace needs the newer ANGLE build # plus sampler mipmap min-filter downgrading on ANGLE llvmpipe. if [ "${{ matrix.backend.name }}" = "DirectGLES" ] && [ "${{ matrix.case.name }}" = "minecraft-1.21.4-fabric-iris-bliss-in-world" ]; then angle_override_dir="${RUNNER_TEMP}/mobilegl-angle-bliss-x86_64" angle_override_commit="bdcc96ac11c79001018ae4375eb73cb54a9f682f" angle_override_base="https://raw.githubusercontent.com/FCL-Team/FoldCraftLauncher/${angle_override_commit}/FCLauncher/src/main/jniLibs/x86_64" mkdir -p "${angle_override_dir}" curl -L --fail --retry 3 -o "${angle_override_dir}/libEGL_angle.so" "${angle_override_base}/libEGL_angle.so" curl -L --fail --retry 3 -o "${angle_override_dir}/libGLESv2_angle.so" "${angle_override_base}/libGLESv2_angle.so" echo "d0f4298ccc770cc801fc52e21733521646161e8a4adb3bd0052d9a1b57ee0ca8 ${angle_override_dir}/libEGL_angle.so" | sha256sum -c - echo "66fdc867e552192d553d59095ea2e3cef4829de65c356f1fd826027b1905972e ${angle_override_dir}/libGLESv2_angle.so" | sha256sum -c - extra_retrace_args+=(--angle-library-dir "${angle_override_dir}") extra_retrace_args+=(--avoid-angle-llvmpipe-sampler-mipmap-min-filter) fi timeout "$(( ${{ matrix.case.timeout_seconds }} + 300 ))" sh android-plugin/trace-replay-ci.sh \ --apk-file "${apk_file}" \ --package "${{ matrix.backend.package }}" \ --backend "${{ matrix.backend.name }}" \ --result-root android-retrace-result \ --fixture-root android-retrace-fixture \ --case "${{ matrix.case.name }}" \ --trace-archive "${{ matrix.case.trace_archive }}" \ --trace-file "${{ matrix.case.trace_file }}" \ --golden "${{ matrix.case.golden }}" \ --alternate-golden "${{ matrix.case.alternate_golden || '' }}" \ --target-call "${{ matrix.case.target_call }}" \ --width "${{ matrix.case.width }}" \ --height "${{ matrix.case.height }}" \ --ssim-threshold "${{ matrix.case.ssim_threshold || '0.99' }}" \ --crop-x "${{ matrix.case.crop_x }}" \ --crop-y "${{ matrix.case.crop_y }}" \ --crop-width "${{ matrix.case.crop_width }}" \ --crop-height "${{ matrix.case.crop_height }}" \ --timeout-seconds "${{ matrix.case.timeout_seconds }}" \ "${extra_retrace_args[@]}" - name: Collect retrace summary inputs if: always() run: | safe_case="$(printf '%s' '${{ matrix.case.name }}' | sed 's/[^A-Za-z0-9._-]/_/g')" result_dir="android-retrace-result/${safe_case}-${{ matrix.backend.name }}" mkdir -p "${result_dir}" if [ -s "${{ matrix.case.golden }}" ]; then cp "${{ matrix.case.golden }}" "${result_dir}/${safe_case}-${{ matrix.backend.name }}-golden.png" fi if [ -n "${{ matrix.case.alternate_golden || '' }}" ] && [ -s "${{ matrix.case.alternate_golden || '' }}" ]; then cp "${{ matrix.case.alternate_golden || '' }}" "${result_dir}/${safe_case}-${{ matrix.backend.name }}-alternate-golden.png" fi - name: Collect emulator diagnostics if: always() run: | mkdir -p android-retrace-result/diagnostics adb devices -l > android-retrace-result/diagnostics/adb-devices.txt || true timeout 30 adb logcat -d -t 1000 > android-retrace-result/diagnostics/logcat.txt || true if [ -f "${EMULATOR_LOG}" ]; then cp "${EMULATOR_LOG}" android-retrace-result/diagnostics/emulator.log fi - name: Stop Emulator if: always() run: | sh android-plugin/run-avd-ci.sh stop \ --avd-name "${AVD_NAME}" \ --emulator-log "${EMULATOR_LOG}" \ --pid-file "${EMULATOR_PID_FILE}" - name: Upload Android retrace result if: always() uses: actions/upload-artifact@v4 with: name: MobileGL-android-retrace-result-${{ env.date_today }}-${{ env.short_sha }}-${{ matrix.backend.name }}-${{ matrix.case.name }} path: android-retrace-result/** if-no-files-found: warn retrace-summary: name: retrace summary runs-on: ubuntu-latest needs: retrace if: always() steps: - name: Checkout repo uses: actions/checkout@v4 - name: Set artifact metadata run: | echo "date_today=$(date +'%Y-%m-%d')" >> "$GITHUB_ENV" echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_ENV" - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '22' - name: Download Android retrace results uses: actions/download-artifact@v4 with: pattern: MobileGL-android-retrace-result-* path: retrace-artifacts - name: Render retrace summary run: | node tools/trace_replay/render_retrace_summary.mjs \ --input retrace-artifacts \ --output-dir android-retrace-summary \ --title "MobileGL Android retrace overview" \ --group-label "Android Emulator" \ --html mobilegl-android-retrace-overview.html - name: Upload Android retrace summary uses: actions/upload-artifact@v7 with: path: android-retrace-summary/mobilegl-android-retrace-overview.html archive: false if-no-files-found: error