Files
RetroArch/.github/workflows/Android.yml
T
LibretroAdmin a4172fdafd CI: the lanes Ubuntu 26.04 broke, and the formats warnings
Built with ffmpeg 8, libaom 3.13, x265 4.1, glibc 2.43 and clang 21,
five lanes failed on the 26.04 runners:

- AV1 fixtures: a monochrome sequence comes out full range with no
  matrix whatever is asked for; the oracle takes the colour ffprobe
  reads instead of assuming it.
- Preview audio oracle: ffmpeg 8 leaves a timestamp gap at every seam
  of a -stream_loop copy, which the mixer honours and ffmpeg's raw
  decode does not. trailing_large loops its picture and encodes its
  sound as one track.
- rh265 multi-slice oracle: x265 4.1 writes unreadable slice headers
  when two slices are encoded on several threads; those cases encode
  on one worker.
- vkms: the kernel follows the runner's own release, its modules may
  sit under /usr/lib/modules, and modules-extra is fetched only where
  it exists.
- clang -std=c89 -pedantic: glibc's const-generic strchr/strstr under
  _GNU_SOURCE are _Generic; -Wno-c11-extensions goes wherever
  -Wno-c99-extensions already does.

ci_paths filters a file at the top of a samples tree by its own path.
rh264 and rh265 lose the parameters no instantiation reads, the 8-bit
H.264 kernels mark the depth they ignore, and the AV1 WebM fixtures
leave out the MP4 box writer they never use.
2026-11-05 17:36:02 +01:00

246 lines
10 KiB
YAML

name: CI Android
on:
push:
branches: [master]
# ci_paths: generated by tools/ci_paths.py, do not edit
paths:
- '**'
- '!.github/workflows/*.yml'
- '.github/workflows/Android.yml'
# ci_paths: end
pull_request:
# ci_paths: generated by tools/ci_paths.py, do not edit
paths:
- '**'
- '!.github/workflows/*.yml'
- '.github/workflows/Android.yml'
# ci_paths: end
workflow_dispatch:
repository_dispatch:
types: [run_build]
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
build:
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- name: Link with lld
run: sh .github/workflows/scripts/use-lld.sh
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
java-version: '25'
distribution: 'temurin'
cache: 'gradle'
- name: Compile RA
run: |
cd pkg/android/phoenix
# A repository that answers with a server error is retried with
# a backoff (2 s doubling, six tries) before Gradle gives up on
# it for the rest of the build. A build that still fails to fetch
# a dependency is run again, keeping what it already fetched and
# built; any other failure fails the step at once.
set -o pipefail
for i in 1 2 3; do
./gradlew assembleDebug \
-Dorg.gradle.internal.repository.max.tentatives=6 \
-Dorg.gradle.internal.repository.initial.backoff=2000 \
2>&1 | tee gradle.log && break
grep -qE 'Could not (resolve|GET|HEAD|download)' gradle.log \
&& [ $i != 3 ] || exit 1
echo "dependency fetch failed (attempt $i); retrying in 30s"
sleep 30
done
find . -iname "*.apk" -exec ls -l "{}" \;
- name: Verify 64-bit APK alignment
run: |
set -eu
for apk in pkg/android/phoenix/build/outputs/apk/{aarch64,quest}/debug/*.apk; do
python3 tools/android_elf_alignment.py "$apk"
"$ANDROID_HOME/build-tools/36.0.0/zipalign" -c -P 16 4 "$apk"
done
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v4
with:
name: retroarch-android-${{ steps.slug.outputs.sha8 }}
path: |
pkg/android/phoenix/build/outputs/apk/normal/debug/phoenix-normal-debug.apk
pkg/android/phoenix/build/outputs/apk/aarch64/debug/phoenix-aarch64-debug.apk
pkg/android/phoenix/build/outputs/apk/quest/debug/phoenix-quest-debug.apk
vp9-stack-abi:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- name: Use the Android project NDK version
run: |
set -eu
version=$(sed -n 's/.*ndkVersion "\([^"]*\)".*/\1/p' pkg/android/phoenix/build.gradle)
test -n "$version"
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;$version"
echo "MEDIA_NDK=$ANDROID_HOME/ndk/$version" >> "$GITHUB_ENV"
- name: VP9 C89 stack ceiling on both Android ABIs and file-offset modes
run: |
set -eu
bin="$MEDIA_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
unity="$RUNNER_TEMP/android-record-unity.c"
: > "$unity"
for source in gfx/common/mediacodec_inventory.c record/record_mediacodec_encoder.c \
record/record_mux_mediacodec.c record/record_mediacodec_worker.c \
record/record_mediacodec_surface.c record/record_android_capture_images.c \
record/record_android_capture_submit.c record/record_android_capture_gl.c \
record/record_android_capture_draw.c record/record_mediacodec_gpu_worker.c \
record/record_mediacodec_file.c record/record_gpu_queue.c \
record/record_audio_queue.c libretro-common/queues/retro_spsc.c; do
printf '#include "%s/%s"\n' "$PWD" "$source" >> "$unity"
done
for target in armv7a-linux-androideabi aarch64-linux-android; do
for api in 21 29; do
for offset in default 64; do
extra=""
if [ "$offset" = 64 ]; then extra="-D_FILE_OFFSET_BITS=64"; fi
CC="$bin/$target$api-clang $extra" python3 libretro-common/samples/formats/vp9/check_stack.py
"$bin/$target$api-clang" $extra -O1 -std=c89 -pedantic -Wall -Wextra -Werror \
-Wno-long-long -Wno-c99-extensions -Wno-c11-extensions -Wframe-larger-than=2048 \
-DHAVE_THREADS -DHAVE_DYLIB -Ilibretro-common/include -Igfx/include \
-c "$unity" -o "$RUNNER_TEMP/record-$target-$api-$offset.o"
if "$bin/llvm-nm" -u "$RUNNER_TEMP/record-$target-$api-$offset.o" | \
grep -Eq ' U (AMedia|ANativeWindow|AHardwareBuffer|egl|gl[A-Z]|record_android_capture_|record_mediacodec_|record_mux_mediacodec_|record_audio_queue_|record_gpu_queue_|retro_spsc_|mediacodec_inventory_)'; then
echo "Unresolved Android recording dependency"
exit 1
fi
for source in android_image_queue android_image_ndk mediacodec_session android_frame \
mediacodec_color mediacodec_frame_export vulkan_android_device \
vulkan_android_image vulkan_android_pipeline vulkan_android_sync \
vulkan_android_submit vulkan_android_cache_entry vulkan_android_cache vulkan_android_queue; do
"$bin/$target$api-clang" $extra -O1 -std=c89 -pedantic -Wall -Wextra -Werror \
-Wno-long-long -Wno-c99-extensions -Wno-c11-extensions -Wframe-larger-than=2048 \
-DHAVE_THREADS -DHAVE_DYLIB -Ilibretro-common/include -Igfx/include \
-c "gfx/common/$source.c" -o "$RUNNER_TEMP/$source-$target-$api-$offset.o"
done
done
done
done
- name: Link media-enabled Android unity frontend
run: |
set -eu
features="-DHAVE_RAAC -DHAVE_RMP4 -DHAVE_RWEBM -DHAVE_RVP9 -DHAVE_RAV1 -DHAVE_RVORBIS -DHAVE_ROPUS"
"$MEDIA_NDK/ndk-build" -j2 \
NDK_PROJECT_PATH=. \
APP_BUILD_SCRIPT=pkg/android/phoenix-common/jni/Android.mk \
NDK_APPLICATION_MK=pkg/android/phoenix-common/jni/Application.mk \
NDK_OUT="$RUNNER_TEMP/android-media-obj" \
NDK_LIBS_OUT="$RUNNER_TEMP/android-media-libs" \
TARGET_ABIS=arm64-v8a APP_ABI=arm64-v8a \
GLES=3 NDK_GL_HEADER_VER=android-29 APP_PLATFORM=android-29 \
APP_CFLAGS="$features" APP_CPPFLAGS="$features"
test -s "$RUNNER_TEMP/android-media-libs/arm64-v8a/libretroarch-activity.so"
codec-inventory:
runs-on: ubuntu-latest
strategy:
matrix:
cc: [gcc, clang]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Real JNI codec admission and exception contracts
run: make -C samples/gfx/mediacodec_inventory clean all check CC=${{ matrix.cc }} SANITIZER=undefined
image-ownership:
runs-on: ubuntu-latest
strategy:
matrix:
cc: [gcc, clang]
steps:
- uses: actions/checkout@v6
- name: Image ownership and runtime reader fault contracts
run: make -C samples/gfx/android_image_queue clean all check CC=${{ matrix.cc }} SANITIZER=address,undefined
codec-session:
runs-on: ubuntu-latest
strategy:
matrix:
cc: [gcc, clang]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Android encoder, AAC, mux and worker contracts
run: make -C samples/record/mediacodec_encode check CC=${{ matrix.cc }} SANITIZER=address,undefined
- name: Cold session, Surface timestamps and terminal output contracts
run: make -C samples/gfx/mediacodec_session session-check CC=${{ matrix.cc }} SANITIZER=address,undefined
- name: Opaque frame leases, HDR refinement and concurrent handoffs
run: make -C samples/gfx/mediacodec_session frame-check CC=${{ matrix.cc }} SANITIZER=address,undefined
- name: HEVC VP9 AV1 color intersection and renderer export contracts
run: make -C samples/gfx/mediacodec_session export-check CC=${{ matrix.cc }} SANITIZER=address,undefined
vulkan-import-resources:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
cc: [gcc, clang]
env:
APT_PKGS: libvulkan-dev mesa-vulkan-drivers glslc spirv-tools libegl1 libgles2 libgl1-mesa-dri
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: FD ownership, warm submission and cache retirement contracts
run: make -C samples/gfx/mediacodec_session warm-check CC=${{ matrix.cc }} SANITIZER=address,undefined
- name: Modeled image resources, device admission and pipeline contracts
run: make -C samples/gfx/mediacodec_session vulkan-check CC=${{ matrix.cc }} SANITIZER=address,undefined
- name: Apt cache key
id: apt
run: sh .github/workflows/scripts/apt-cache-key.sh "$APT_PKGS"
- name: Restore apt cache
uses: actions/cache/restore@v4
with:
path: ~/.apt-cache
key: ${{ steps.apt.outputs.key }}
restore-keys: ${{ steps.apt.outputs.prefix }}
- name: Install pixel oracle and shader validation dependencies
timeout-minutes: 20
run: sh .github/workflows/scripts/apt-install.sh $APT_PKGS
- name: Save apt cache
if: env.APT_CACHE_SAVE == '1'
uses: actions/cache/save@v4
with:
path: ~/.apt-cache
key: ${{ steps.apt.outputs.key }}
- name: Execute embedded and freshly compiled SDR PQ HLG cropped pixels
run: make -C samples/gfx/mediacodec_session vulkan-gpu-check CC=${{ matrix.cc }} SANITIZER=
- name: GLES recording SDR PQ and scRGB pixel oracle
run: EGL_PLATFORM=surfaceless LIBGL_ALWAYS_SOFTWARE=1 CC=${{ matrix.cc }} python3 samples/record/mediacodec_encode/draw_pixels.py