Compare commits

..
3138 changed files with 398350 additions and 464267 deletions

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
+3 -6
View File
@@ -2,7 +2,6 @@ name: CI 3DS
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,14 +12,9 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-devkitpro:latest
options: --user root
@@ -37,3 +31,6 @@ jobs:
run: |
make -f Makefile.ctr -j$(getconf _NPROCESSORS_ONLN) USE_CTRULIB_2=1 clean
make -f Makefile.ctr -j$(getconf _NPROCESSORS_ONLN) USE_CTRULIB_2=1 HAVE_STATIC_DUMMY=1 info all
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI Android
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
repository_dispatch:
@@ -14,17 +13,12 @@ permissions:
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
- uses: actions/checkout@v3
- name: Set up JDK 25
uses: actions/setup-java@v4
-7
View File
@@ -11,7 +11,6 @@ name: CI Apple
on:
push:
branches: [master]
pull_request:
permissions:
@@ -20,10 +19,6 @@ permissions:
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-graph guard: the Bonjour/mDNS netplay discovery path.
@@ -57,7 +52,6 @@ jobs:
netplay-discovery-guard:
name: Build graph - netplay mDNS discovery
runs-on: macos-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
@@ -134,7 +128,6 @@ jobs:
tvos:
name: tvOS build (non-gating)
runs-on: macos-latest
timeout-minutes: 60
continue-on-error: true
steps:
+3 -41
View File
@@ -11,53 +11,15 @@ on:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
compile-matrix: # every codec combination real builds select, not just this one
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Dependencies
timeout-minutes: 20
run: |
# The gl2 arms compile against the desktop GL and EGL headers,
# and the Dingux and RS90 video drivers against SDL 1.2's.
# The Direct3D and WASAPI lanes cross-compile with mingw-w64.
pkgs="build-essential libgl-dev libegl-dev libgles-dev libsdl1.2-dev gcc-mingw-w64-x86-64 clang gcc-aarch64-linux-gnu gcc-mipsel-linux-gnu"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
sudo apt-get update -y
sudo apt-get install -y build-essential
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Compile matrix
run: ./.github/workflows/scripts/compile-matrix.sh
@@ -1,189 +0,0 @@
name: CI cross-libc libretro-common/vfs samples
# libretro-common/samples runs on ubuntu-latest only, which means
# every VFS test in the tree is validated against exactly one C
# library. That is the wrong number for this code: file_stream.c and
# vfs_implementation.c sit directly on top of stdio and the file
# descriptor API, and the libraries disagree about both.
#
# glibc fread() reads straight into the caller's buffer once
# the request reaches the block size, whoever owns the
# buffer (libio/fileops.c, _IO_file_xsgetn).
# Apple libc the same bypass exists but is skipped when setvbuf()
# supplied the buffer - '__SMBF' is then clear - which is
# exactly what retro_vfs_file_open_impl() does
# (Libc/stdio/FreeBSD/fread.c, radar 5980080 / 6180417).
# UCRT not open source; behaviour is inferred and therefore
# worth measuring rather than assuming.
# msvcrt the older runtime MINGW64 links against, again
# different code from UCRT.
#
# The tests here assert behaviour, not performance, so a difference in
# any of the above shows up as a failure rather than a slowdown. The
# Windows entries matter most for the descriptor path, which opens
# with open()/_wopen() instead of fopen(mode "rb") and so depends on
# O_BINARY being in the flags; vfs_bulk_read_test's binary
# transparency case is the one that catches its absence.
on:
push:
branches:
- master
paths:
- 'libretro-common/streams/file_stream.c'
- 'libretro-common/vfs/**'
- 'libretro-common/include/vfs/**'
- 'libretro-common/include/streams/file_stream.h'
- 'libretro-common/samples/file/vfs/**'
- 'libretro-common/fastjmp/**'
- 'libretro-common/include/fastjmp.h'
- 'libretro-common/samples/fastjmp/**'
- '.github/workflows/Cross-libc-vfs-samples.yml'
pull_request:
paths:
- 'libretro-common/streams/file_stream.c'
- 'libretro-common/vfs/**'
- 'libretro-common/include/vfs/**'
- 'libretro-common/include/streams/file_stream.h'
- 'libretro-common/samples/file/vfs/**'
- 'libretro-common/fastjmp/**'
- 'libretro-common/include/fastjmp.h'
- 'libretro-common/samples/fastjmp/**'
- '.github/workflows/Cross-libc-vfs-samples.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
# glibc and Apple libc. Both take the descriptor path, since
# VFS_HAVE_FILE_MAPPING covers anything with mmap.
unix:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- name: glibc (ubuntu-latest)
runner: ubuntu-latest
# LeakSanitizer exists here, so run it at full strictness.
asan_opts: detect_leaks=1
- name: Apple libc (macos-latest)
runner: macos-latest
# LeakSanitizer is not implemented on Darwin, and asking
# for it is fatal rather than ignored: the runtime prints
# "detect_leaks is not supported on this platform" and
# aborts. Leak coverage for these sources comes from the
# Linux leg above; this one is here for Apple's libc
# behaviour, which is what differs.
asan_opts: detect_leaks=0
steps:
- uses: actions/checkout@v5
- name: Build and run
shell: bash
working-directory: libretro-common/samples/file/vfs
run: |
set -euo pipefail
run_cfg() {
echo "==> $*"
make clean >/dev/null
make "$@" SANITIZER=address,undefined
ASAN_OPTIONS=${{ matrix.asan_opts }} ./vfs_bulk_read_test
./vfs_seek_contract_test
./vfs_mapped_ptr_test
./vfs_v5_metadata_test
}
# Mapping on (what the platform actually ships), mapping off
# with the descriptor path forced (what the consoles have),
# and neither (a target on no list, which must keep its
# buffered behaviour).
run_cfg MMAP=1
run_cfg MMAP=0 DESCRIPTOR_IO=1
run_cfg MMAP=0
- name: Thread sanitizer
# Not on macOS: TSan there reports on system libraries the
# runner image ships, which is noise this job cannot fix.
if: matrix.runner == 'ubuntu-latest'
shell: bash
working-directory: libretro-common/samples/file/vfs
run: |
set -euo pipefail
make clean >/dev/null
make SANITIZER=thread
./vfs_bulk_read_test
# UCRT and msvcrt, through MSYS2. Same C runtimes an MSVC-built
# RetroArch links against, so the runtime behaviour these tests
# check is the behaviour that ships; the MSVC job covers the
# compiler.
windows:
name: ${{ matrix.sys }} (windows-latest)
runs-on: windows-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
sys: [UCRT64, MINGW64]
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v5
- uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.sys }}
update: true
install: >-
base-devel
pacboy: >-
toolchain:p
- name: Build and run
working-directory: libretro-common/samples/file/vfs
run: |
set -euo pipefail
# No sanitizers here: the MSYS2 toolchains do not ship a
# usable ASan runtime for this target, and the point of this
# job is which C runtime the calls land on, not memory
# safety - the Linux job covers that with the same sources.
#
# MMAP=0 is required, not cosmetic: -DHAVE_MMAP pulls in
# <sys/mman.h>, which does not exist here. The Win32
# file-mapping backend is selected by _WIN32 inside vfs.h
# rather than by that flag, so VFS_HAVE_FILE_MAPPING - and
# with it descriptor I/O and the mapped-pointer path - is on
# regardless.
make clean MMAP=0
make MMAP=0
./vfs_bulk_read_test.exe
./vfs_seek_contract_test.exe
# Win32 branches of the v5 metadata ops: attributes,
# SetFileTime, CopyFileW, find-data dirent_stat.
./vfs_v5_metadata_test.exe
# Exercises the Win32 CreateFileMapping/MapViewOfFile
# backend, which no other job in the tree reaches.
./vfs_mapped_ptr_test.exe
# The Win64 fastjmp_set stores xmm6-xmm15 with movaps and faults
# on a misaligned buffer. Linux has no such stores, so the Linux
# samples job cannot see a fastjmp_buf that lost its alignment;
# this is the only lane that can. Under a second to build and run.
- name: fastjmp on Win64
working-directory: libretro-common/samples/fastjmp/fastjmp_test
run: |
set -euo pipefail
make clean
make
./fastjmp_test.exe
@@ -1,46 +0,0 @@
name: CI Context presentable() contract
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
ctx-presentable-check:
name: gfx_ctx_driver_t presentable() consistency
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checker self-test
shell: bash
run: |
set -eu
# Fixture pass: a correct driver is clean, a presentable()
# casting another driver's context type is flagged, and one
# that is defined but never wired into the vtable is flagged.
python3 tools/ctx_presentable_check.py --selftest
- name: Tree check
shell: bash
run: |
set -eu
# Each context driver is compiled by one platform's CI, so a
# presentable() that casts the wrong driver's type, or that is
# never wired in, is invisible to every other job. This is the
# check that sees all of them at once.
python3 tools/ctx_presentable_check.py
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI DOS/DJGPP
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-djgpp-build-container:latest
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile RA
run: |
+5 -6
View File
@@ -2,7 +2,6 @@ name: CI Emscripten
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,14 +12,9 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-emscripten:latest
options: --user root
@@ -32,3 +26,8 @@ jobs:
run: |
emmake make -f Makefile.emscripten -j$(getconf _NPROCESSORS_ONLN) clean
emmake make -f Makefile.emscripten -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
@@ -1,48 +0,0 @@
name: CI extern "C" prototype parity
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
extern-c-prototype-check:
name: extern "C" definitions match their C prototypes
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checker self-test
shell: bash
run: |
set -eu
# Fixture pass: a matching definition is clean, a definition
# with a parameter more than its prototype (the shape of the
# 0b2613d Xbox boot crash) is flagged, and a parameter of
# another type is flagged.
python3 tools/extern_c_prototype_check.py --selftest
- name: Tree check
shell: bash
run: |
set -eu
# A .cpp file that defines a win32_common.h function under
# extern "C" without including the header (uwp_main.cpp) is
# never checked against the prototype by any compiler: the
# linker matches on the name alone. This is the check that
# compares the two, for every such definition in the tree.
python3 tools/extern_c_prototype_check.py
-91
View File
@@ -1,91 +0,0 @@
name: CI FreeBSD
# Builds RetroArch inside a FreeBSD VM (GitHub has no FreeBSD runners)
# with the same feature set the games/retroarch port enables by default,
# minus Qt (very slow to install). This is what kept the port carrying
# patches on top of each release: libudev is FreeBSD's libudev-devd, the
# input headers come from dev/evdev/, and there is no linux_common.o to
# link against.
#
# Deliberately NOT installed: evdev-proto and v4l_compat (the Linux
# compatibility headers). A stock FreeBSD box must build udev + Wayland
# from the dev/evdev/ headers in base, and configure must turn V4L2 off
# on its own when libv4l is present but linux/videodev2.h is not.
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- name: Check Out Repo
uses: actions/checkout@v4
- name: Build in FreeBSD
uses: vmactions/freebsd-vm@v1
with:
release: "14.3"
usesh: true
copyback: false
prepare: |
pkg install -y \
gmake pkgconf \
ffmpeg freetype2 openal-soft mesa-libs \
libudev-devd libxkbcommon wayland wayland-protocols \
libX11 libXext libXxf86vm libXinerama libXrandr libXv \
sdl2 pipewire alsa-lib pulseaudio libdrm libv4l
run: |
set -e
freebsd-version
NCPU=$(sysctl -n hw.ncpu)
# --disable-pipewire must not leave HAVE_PIPEWIRE_STABLE
# behind just because libpipewire is installed.
./configure --disable-qt --disable-discord --disable-pipewire
grep -q '^HAVE_PIPEWIRE_STABLE = 0' config.mk
# libv4l2.pc is installed but linux/videodev2.h is not
# (v4l_compat): V4L2 must be auto-disabled, not left on to
# fail at compile time.
grep -q '^HAVE_V4L2 = 0' config.mk
# Real build: force the FreeBSD-specific paths on so a missing
# dependency fails configure instead of silently skipping them.
./configure --disable-qt --disable-discord \
--enable-udev --enable-x11 --enable-wayland --enable-sdl2 \
--enable-ffmpeg --enable-pipewire --enable-alsa \
--enable-pulse --enable-oss
gmake -j$NCPU clean
gmake -j$NCPU info all
./retroarch --version
# udev input must multiplex with kqueue here, so the binary
# must not need libepoll-shim's epoll_* at all.
if nm -u retroarch | grep -q 'epoll_'; then
echo "retroarch still references epoll (libepoll-shim)"; exit 1
fi
# A fresh RetroArch must pick up data sets the ports install
# under /usr/local/share/libretro (assets, info, shaders,
# autoconfig) without any retroarch.cfg edits.
sh samples/frontend/packaged_dirs/run.sh
# With v4l_compat the V4L2 camera and video processor core
# must still compile; only those two objects are rebuilt.
pkg install -y v4l_compat
./configure --disable-qt --disable-discord --enable-v4l2
grep -q '^HAVE_V4L2 = 1' config.mk
gmake -j$NCPU camera/drivers/video4linux2.o \
cores/libretro-video-processor/video_processor_v4l2.o
+4 -6
View File
@@ -2,7 +2,6 @@ name: CI GameCube
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,14 +12,9 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-devkitpro:latest
options: --user root
@@ -32,3 +26,7 @@ jobs:
run: |
make -f Makefile.ngc -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.ngc -j$(getconf _NPROCESSORS_ONLN) EXTERNAL_LIBOGC=1 GX_PTHREAD_LEGACY=0 HAVE_STATIC_DUMMY=1 info all
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
+3 -38
View File
@@ -14,51 +14,16 @@ permissions:
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:
linux-nomenu: # Smoketest build with no menu support compiled in
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev nvidia-cg-toolkit nvidia-cg-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
sudo apt-get update -y
sudo apt-get install build-essential libxkbcommon-dev libx11-xcb-dev zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev nvidia-cg-toolkit nvidia-cg-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Configure
run: ./configure --disable-menu
- name: Build
+12 -101
View File
@@ -21,10 +21,8 @@ name: CI Linux ASan + UBSan [No Menu]
# surfaced in step output for triage.
#
# The per-sample tests under .github/workflows/Linux-samples-gfx.yml,
# Linux-samples-tasks.yml, Linux-samples-audio.yml,
# Linux-samples-network.yml, Linux-samples-settings.yml, and
# Linux-libretro-{db,common}-samples.yml regression-test specific
# predicates that previously had bugs. This
# Linux-samples-tasks.yml, and Linux-libretro-{db,common}-samples.yml
# regression-test specific predicates that previously had bugs. This
# job is complementary -- it covers everything those harnesses can't
# reach because the code only runs from main(), and catches future
# heap-corruption / UB regressions across the whole code base for
@@ -51,10 +49,6 @@ permissions:
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:
asan-ubsan:
name: Build with ASan+UBSan and run headless smoke
@@ -72,42 +66,20 @@ jobs:
# comment for why SDL2 over xvideo. No sanitizer-specific
# packages required; libasan / libubsan ship with the gcc
# that ubuntu-latest has installed by default.
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev nvidia-cg-toolkit nvidia-cg-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get update -y
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
build-essential \
libxkbcommon-dev libx11-xcb-dev \
xvfb x11-utils \
zlib1g-dev libfreetype6-dev \
libegl1-mesa-dev libgles2-mesa-dev libgbm-dev \
nvidia-cg-toolkit nvidia-cg-dev \
libavcodec-dev libsdl2-dev libsdl-image1.2-dev \
libxml2-dev yasm
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Configure (no menu, no discord/cheevos/networking, sdl2 on)
# Trim the build surface for the first iteration so any
@@ -400,64 +372,3 @@ jobs:
| sort -u | head -20
fi
echo "[done] imageviewer headless smoke (soft-fail)"
- name: Screenshot on exit under LeakSanitizer (strict)
# The smoke above runs with detect_leaks=0, which is how a
# synchronous screenshot leaking its task state and the whole
# captured frame on every call went unnoticed: --max-frames-ss
# and save-state thumbnails both take that path. This run
# takes one and checks for leaks with only the system libraries
# suppressed - Mesa, X11, SDL, D-Bus and friends keep caches
# alive to exit that are not RetroArch's - so anything left is
# ours and fails the job.
env:
ASAN_OPTIONS: abort_on_error=1:detect_leaks=1:print_stacktrace=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
LSAN_OPTIONS: suppressions=/tmp/lsan-system.supp:print_suppressions=0
run: |
set -eu
cat > /tmp/lsan-system.supp <<EOF
leak:libGL
leak:libGLX
leak:libGLdispatch
leak:libgallium
leak:libLLVM
leak:_dri.so
leak:libEGL
leak:libgbm
leak:libX11
leak:libxcb
leak:libSDL2
leak:libdbus-1
leak:libfontconfig
leak:libfreetype
leak:libasound
leak:libpulse
EOF
mkdir -p /tmp/lsan-cfg /tmp/lsan-shots
cat > /tmp/lsan-cfg/retroarch.cfg <<EOF
video_driver = "sdl2"
audio_driver = "null"
video_threaded = "false"
video_fullscreen = "false"
video_windowed_fullscreen = "false"
screenshot_directory = "/tmp/lsan-shots"
EOF
set +e
timeout 120 xvfb-run -a -s "-screen 0 320x240x24" ./retroarch \
-c /tmp/lsan-cfg/retroarch.cfg \
-L cores/libretro-imageviewer/image_core.so \
/tmp/test.png \
--max-frames=60 \
--max-frames-ss \
--max-frames-ss-path=/tmp/lsan-shots/exit.png \
> /tmp/lsan.log 2>&1
rc=$?
set -e
if [ "$rc" != 0 ] || grep -qE "leak of|AddressSanitizer:|runtime error:" /tmp/lsan.log; then
echo "exit=${rc}"
grep -E -A 12 "leak of|AddressSanitizer:|runtime error:" /tmp/lsan.log | head -120
exit 1
fi
test -s /tmp/lsan-shots/exit.png
echo "[pass] screenshot on exit, no leaks outside the system libraries"
@@ -1,65 +0,0 @@
name: CI Linux native audio transport
on:
push:
branches: [master]
pull_request:
branches: [master]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
native-transport:
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
sanitizer: ['', 'address,undefined']
steps:
- uses: actions/checkout@v5
- name: Build the shipping frontend and real audio wrapper fixture
working-directory: samples/audio/pipeline_wakeups
run: make clean all SANITIZER='${{ matrix.sanitizer }}'
- name: Stereo tempo extremes and live controls
working-directory: samples/audio/pipeline_wakeups
env:
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: make check-tempo check-live SANITIZER='${{ matrix.sanitizer }}'
- name: Native and mixed formats through 5.1 and 7.1
working-directory: samples/audio/pipeline_wakeups
env:
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: make check-wide SANITIZER='${{ matrix.sanitizer }}'
- name: Live source layouts on a fixed device
working-directory: samples/audio/pipeline_wakeups
env:
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: make check-layout SANITIZER='${{ matrix.sanitizer }}'
- name: Speed-linked low-pass control requests
working-directory: samples/audio/pipeline_wakeups
env:
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: make check-speed-lpf SANITIZER='${{ matrix.sanitizer }}'
- name: Runloop speed-state requests
working-directory: samples/audio/pipeline_wakeups
env:
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: make check-runloop SANITIZER='${{ matrix.sanitizer }}'
- name: Automatic producer controls and fallback
working-directory: samples/audio/pipeline_wakeups
env:
ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: make check-auto SANITIZER='${{ matrix.sanitizer }}'
+7 -65
View File
@@ -15,67 +15,20 @@ permissions:
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:
autoconf-tests:
name: Build and run the autoconfig regression suite (${{ matrix.lane }})
name: Build and run the autoconfig regression suite
runs-on: ubuntu-latest
timeout-minutes: ${{ matrix.sanitizer == '' && 15 || 40 }}
strategy:
fail-fast: false
matrix:
# The suite fails on any sanitizer report in any run, so the
# sanitized lanes hold the whole frontend it drives - runloop,
# task queue, autodetect - to the same bar as the assertions.
include:
- lane: plain
sanitizer: ''
- lane: ASan + UBSan
sanitizer: address,undefined
- lane: TSan
sanitizer: thread
timeout-minutes: 15
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential zlib1g-dev libfreetype6-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
sudo apt-get update -y
sudo apt-get install -y build-essential zlib1g-dev libfreetype6-dev
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Configure (headless, test drivers)
run: |
@@ -89,22 +42,11 @@ jobs:
grep -q '^HAVE_TEST_DRIVERS = 1' config.mk
- name: Build
run: |
if [ -n "${{ matrix.sanitizer }}" ]; then
make -j"$(nproc)" SANITIZER=${{ matrix.sanitizer }} DEBUG=1
else
make -j"$(nproc)"
fi
run: make -j"$(nproc)"
- name: Run autoconfig regression suite
shell: bash
run: |
set -eu
test -x ./retroarch
if [ "${{ matrix.sanitizer }}" = thread ]; then
# TSan cannot map its shadow under the runner's ASLR
# entropy; setarch -R carries to every child the suite runs.
setarch "$(uname -m)" -R ./tests-other/test_autoconf.sh ./retroarch
else
./tests-other/test_autoconf.sh ./retroarch
fi
./tests-other/test_autoconf.sh ./retroarch
-118
View File
@@ -1,118 +0,0 @@
name: CI driver vtables
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
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:
driver-vtables:
name: Every driver against its interface
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Install dependencies
shell: bash
run: |
set -eu
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends \
build-essential libasound2-dev libpulse-dev libjack-jackd2-dev \
libopenal-dev libpipewire-0.3-dev libsdl2-dev
- name: Checkout
uses: actions/checkout@v5
- name: Compile each driver against its interface
shell: bash
run: |
set -eu
# A driver fills in a vtable of function pointers, and almost
# every one of them does it positionally and names nothing.
# So an entry added to the middle of one of those structures
# silently moves every entry after it in every driver that
# did not name its fields, and what the compiler then says is
# that a layout function is being installed as an underrun
# counter - which is an error only if you ask for it to be.
#
# That happened: frames_consumed_fallback went in between
# frames_consumed and underruns, three Windows drivers took
# the shift, and the break reached master because the check
# run before the commit was one file rather than all of them.
#
# This is that check. It compiles every driver it can on
# Linux - the rest need SDKs that are not here - and treats a
# mismatched function pointer as the error it is.
#
# The names are matched with digits in them as well: a driver
# called sdl3 or v4l2 or ps2 is exactly as positional as one
# that spells itself in letters, and six of them were being
# walked past. The display drivers fill in a vtable of the
# same shape, so they are here too.
#
# A static function nobody calls is in the same family and is
# caught here too: it is what a call site that was meant to
# be there and is not looks like from the compiler's side.
# That happened as well - the pump's scheduler class was
# taken but never given back, and the only sign was the
# helper that returns it going unused.
fail=0
defs="-DRARCH_INTERNAL -DHAVE_THREADS -DHAVE_MENU -DHAVE_CONFIGFILE"
defs="$defs -DHAVE_AUDIOMIXER -DHAVE_REWIND -DHAVE_RWAV"
have="-DHAVE_ALSA -DHAVE_PULSE -DHAVE_JACK -DHAVE_OSS -DHAVE_OPENAL"
have="$have -DHAVE_PIPEWIRE -DHAVE_TINYALSA -DHAVE_SDL2"
inc="-I. -Ilibretro-common/include -Ideps -Ideps/rcheevos/include"
inc="$inc $(pkg-config --cflags libpipewire-0.3 2>/dev/null || true)"
# Every file that fills one of these structures in, found by
# looking rather than by listing a directory: the Android
# build broke on audio/audio_thread_wrapper.c, which fills in
# an audio_driver_t and does not live under audio/drivers,
# and so was not in the list this job first carried.
files=$(grep -rl -E \
'audio_driver_t [a-z_0-9]+ *=|camera_driver_t [a-z_0-9]+ *=|record_driver_t [a-z_0-9]+ *=|microphone_driver_t [a-z_0-9]+ *=|gfx_display_ctx_driver_t [a-z_0-9]+ *=' \
--include='*.c' . | grep -v '^\./samples/' | sort)
echo "$files" | sed 's/^/ /'
echo
for f in $files; do
[ -f "$f" ] || continue
out=$(gcc -fsyntax-only -std=gnu99 -Wall \
-Werror=incompatible-pointer-types \
-Werror=unused-function \
$defs $have $inc "$f" 2>&1 || true)
# A driver whose platform SDK is not here does not compile
# at all, and that is not what this job is about: it is
# skipped, and only a pointer mismatch fails.
if printf '%s' "$out" | grep -qE "incompatible pointer type|defined but not used"; then
echo "=== $f"
printf '%s\n' "$out" | grep -E -A2 "incompatible pointer type|defined but not used"
fail=1
elif printf '%s' "$out" | grep -q ": error:"; then
echo "[skip] $f (needs an SDK that is not here)"
else
echo "[ok] $f"
fi
done
if [ "$fail" -ne 0 ]; then
echo
echo "A driver does not match the interface it fills in, or has a"
echo "static function nothing calls. An optional vtable entry belongs"
echo "at the end of the structure, where it cannot move the entries a"
echo "positional initialiser relies on; an uncalled helper usually"
echo "means the call site that was meant to use it is missing."
exit 1
fi
@@ -1,79 +0,0 @@
name: CI Linux filter plugins
# Builds every video filter (gfx/video_filters) and audio DSP filter
# (libretro-common/audio/dsp_filters) plugin with its own Makefile and
# runs samples/gfx/filter_plugins over all of them: each plugin is
# loaded with RTLD_NOW into a host that does not link libm, so a
# symbol it cannot resolve fails the load, then fed a frame or a run
# of audio blocks at its default settings. Every video filter that
# takes more than one worker must give the single-worker output byte for
# byte with 2, 3 and 4 workers running at once. The same run is repeated
# with the plugins and the harness built under ASan, UBSan and
# LeakSanitizer, and under ThreadSanitizer.
on:
push:
branches:
- master
paths:
- 'gfx/video_filters/**'
- 'libretro-common/audio/dsp_filters/**'
- 'libretro-common/include/libretro_dspfilter.h'
- 'samples/gfx/filter_plugins/**'
- '.github/workflows/Linux-filter-plugins.yml'
pull_request:
paths:
- 'gfx/video_filters/**'
- 'libretro-common/audio/dsp_filters/**'
- 'libretro-common/include/libretro_dspfilter.h'
- 'samples/gfx/filter_plugins/**'
- '.github/workflows/Linux-filter-plugins.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
filter-plugins:
name: Load and run every filter plugin
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Build the plugins and the harness
run: |
set -eu
make -C samples/gfx/filter_plugins
# The harness must not bring libm in on the plugins' behalf.
if readelf -d samples/gfx/filter_plugins/filter_plugins_test \
| grep -q 'libm\.so'; then
echo "filter_plugins_test links libm; it would hide a plugin that does not"
exit 1
fi
- name: Load and run every plugin
run: make -C samples/gfx/filter_plugins check
- name: Load and run every plugin under ASan, UBSan and LeakSanitizer
env:
ASAN_OPTIONS: abort_on_error=1:detect_leaks=1:print_stacktrace=1
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1
run: |
set -eu
make -C samples/gfx/filter_plugins clean
make -C samples/gfx/filter_plugins check SANITIZER=address,undefined
- name: Load and run every plugin under ThreadSanitizer
env:
TSAN_OPTIONS: halt_on_error=1
run: |
set -eu
make -C samples/gfx/filter_plugins clean
make -C samples/gfx/filter_plugins check SANITIZER=thread
@@ -1,92 +0,0 @@
name: CI Linux frontend overhead [frame-path harness]
# What one runloop_iterate() costs when the core costs nothing, and
# whether anything on the frame path allocates. The harness links the
# shipping release objects with main() replaced, boots on the null
# drivers, runs a core that pushes one frame, one audio batch and one
# input read per retro_run, and counts heap calls over the frame path
# by glibc interposition - which is why this is a release build with
# no allocator sanitizer in the way. It also prints microseconds per
# frame under fast-forward and trips on a loose bound, so a blocking
# call or a sleep that lands on the frame path fails here rather than
# in a bug report about stutter.
#
# Everything a default desktop build compiles in is compiled in, so a
# product that starts costing the frame while idle is measured, not
# excluded.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
linux-frontend-overhead:
name: Release build, frame-path heap and cost
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libavcodec-dev libsdl2-dev libxml2-dev yasm"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
# Non-Qt, as the harness requires (with Qt, main() lives in
# ui_qt.o). Everything else at its default.
run: ./configure --disable-qt
- name: Build (release)
run: make -j$(getconf _NPROCESSORS_ONLN)
- name: Run the frontend-overhead harness
shell: bash
run: |
set -o pipefail
SAN=none make -C samples/runloop/frontend_overhead check
make -C samples/runloop/frontend_overhead clean
-125
View File
@@ -1,125 +0,0 @@
name: CI Linux gl1 upload
# Runs the gl1 video driver under Xvfb with a test core and checks the
# screen against the frame the core drew, pixel for pixel, down each of
# the driver's upload paths: frames taken straight from the core's
# buffer, the no-GL_EXT_bgra swizzle, native RGB565, the GL 1.1 CPU
# expansion, and texture storage respecified across frame size changes.
on:
push:
branches:
- master
paths:
- 'gfx/drivers/gl1.c'
- 'libretro-common/gfx/scaler/pixconv.c'
- 'libretro-common/include/gfx/scaler/pixconv.h'
- 'samples/gfx/gl1_upload/**'
- '.github/workflows/Linux-gl1-upload.yml'
pull_request:
paths:
- 'gfx/drivers/gl1.c'
- 'libretro-common/gfx/scaler/pixconv.c'
- 'libretro-common/include/gfx/scaler/pixconv.h'
- 'samples/gfx/gl1_upload/**'
- '.github/workflows/Linux-gl1-upload.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
gl1-upload:
name: Run retroarch on gl1 under Xvfb and check the frame
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential zlib1g-dev ccache python3 \
xvfb libgl1-mesa-dri \
libx11-dev libx11-xcb-dev libxcb1-dev libxext-dev \
libxxf86vm-dev libxrandr-dev libxinerama-dev \
libgl-dev libegl-dev && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential zlib1g-dev ccache python3 \
xvfb libgl1-mesa-dri \
libx11-dev libx11-xcb-dev libxcb1-dev libxext-dev \
libxxf86vm-dev libxrandr-dev libxinerama-dev \
libgl-dev libegl-dev
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build RetroArch (X11 + OpenGL, the rest off)
shell: bash
run: |
set -eu
./configure --disable-qt --disable-wayland --disable-sdl \
--disable-sdl2 --disable-ffmpeg --disable-vulkan \
--disable-pulse --disable-discord \
--disable-networking --disable-cheevos \
--disable-glslang --disable-slang \
--disable-spirv_cross --disable-xmb \
--disable-materialui --disable-ozone \
--disable-7zip --disable-flac \
--disable-audiomixer --disable-translate \
--disable-accessibility --disable-crtswitchres \
--disable-langextra --disable-libretrodb \
--disable-video_filter --disable-dsp_filter
grep -q '^HAVE_OPENGL1 = 1' config.mk
make -j$(nproc)
ccache -s
- name: Run gl1_upload_test
shell: bash
run: |
set -eu
make -C samples/gfx/gl1_upload
timeout 600 python3 samples/gfx/gl1_upload/gl1_upload_test.py ./retroarch
@@ -1,139 +0,0 @@
name: CI Linux library network backends
# The built-in TLS, SMB and NFS clients are the defaults and nothing is
# bundled. A system mbedTLS or BearSSL can stand in for the TLS client
# (--enable-mbedtls, --enable-bearssl) and a system libsmb2 for the SMB
# client (--enable-libsmb). Each lane configures with its option, builds
# RetroArch to the link, checks the binary carries that library's
# backend and not the built-in client, and then operates the backend:
# the TLS lanes run the cheevos login transport against a local HTTPS
# server, the libsmb2 lane runs the SMB VFS tests against a local smbd.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
library-backends:
name: ${{ matrix.lane }}
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- lane: mbedtls
configure: --enable-mbedtls
present: mbedtls_ssl_handshake
absent: ' T ssl_socket_retro_was_resumed'
- lane: bearssl
configure: --enable-bearssl
present: br_ssl_client_init_full
absent: ' T ssl_socket_retro_was_resumed'
- lane: libsmb2
configure: --enable-libsmb
present: ' U smb2_connect_share'
absent: ' T rsmb_connect'
steps:
- name: Dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y build-essential pkg-config cmake \
libgl1-mesa-dev libx11-dev libxext-dev libasound2-dev libsdl2-dev \
zlib1g-dev libfreetype6-dev python3 openssl \
libmbedtls-dev libbearssl-dev samba
- name: Checkout
uses: actions/checkout@v5
- name: libsmb2 from upstream (no Ubuntu package)
if: matrix.lane == 'libsmb2'
run: |
set -eu
git clone -q --depth 1 https://github.com/sahlberg/libsmb2.git "$RUNNER_TEMP/libsmb2"
cmake -S "$RUNNER_TEMP/libsmb2" -B "$RUNNER_TEMP/libsmb2/build" \
-DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_SHARED_LIBS=ON >/dev/null
make -C "$RUNNER_TEMP/libsmb2/build" -j"$(nproc)" >/dev/null
sudo make -C "$RUNNER_TEMP/libsmb2/build" install >/dev/null
sudo ldconfig
echo "PKG_CONFIG_PATH=/usr/local/lib/pkgconfig" >> "$GITHUB_ENV"
pkg-config --modversion libsmb2 || PKG_CONFIG_PATH=/usr/local/lib/pkgconfig pkg-config --modversion libsmb2
- name: Configure
run: |
set -eu
./configure ${{ matrix.configure }} --disable-qt --disable-wayland --disable-ffmpeg
grep -E '^HAVE_(RETROSSL|MBEDTLS|BEARSSL|RETROSMB|SMBCLIENT|SSL) ' config.mk
case "${{ matrix.lane }}" in
mbedtls) grep -q '^HAVE_MBEDTLS = 1' config.mk; grep -q '^HAVE_RETROSSL = 0' config.mk ;;
bearssl) grep -q '^HAVE_BEARSSL = 1' config.mk; grep -q '^HAVE_RETROSSL = 0' config.mk ;;
libsmb2) grep -q '^HAVE_SMBCLIENT = 1' config.mk; grep -q '^HAVE_RETROSMB = 0' config.mk ;;
esac
- name: Build
run: make -j"$(nproc)"
- name: Check which backend linked
run: |
set -eu
nm retroarch | grep -q -- '${{ matrix.present }}'
if nm retroarch | grep -q -- '${{ matrix.absent }}'; then
echo "the built-in client is still linked in the ${{ matrix.lane }} build"; exit 1
fi
echo "[pass] ${{ matrix.lane }} backend linked, built-in client absent"
- name: Operate the TLS backend (cheevos login transport, ASan + UBSan)
if: matrix.lane != 'libsmb2'
working-directory: samples/network/cheevos_login
run: |
set -eu
case "${{ matrix.lane }}" in mbedtls) be=mbed ;; bearssl) be=bear ;; esac
make clean all SSL_BACKEND=$be SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 timeout 120 \
make check SSL_BACKEND=$be
echo "[pass] ${{ matrix.lane }}: cheevos login transport over a local HTTPS server"
- name: Operate the libsmb2 backend (SMB VFS against a local smbd)
if: matrix.lane == 'libsmb2'
run: |
set -eu
sudo -E env PATH="$PATH" PKG_CONFIG_PATH="$PKG_CONFIG_PATH" WITH_LIBSMB2=1 \
samples/network/smb_retro/local_samba_test.sh
sudo make -C samples/network/smb_retro clean
# libsmb2 keeps process-wide state (its list of live contexts) with
# no lock of its own; the VFS backend must serialise it. A race
# there needs two cores to show up by timing, so the same tests run
# again under TSan against a TSan-built libsmb2, which reports it on
# any runner, every time.
- name: Operate the libsmb2 backend under TSan (instrumented libsmb2)
if: matrix.lane == 'libsmb2'
run: |
set -eu
cmake -S "$RUNNER_TEMP/libsmb2" -B "$RUNNER_TEMP/libsmb2/build-tsan" \
-DCMAKE_INSTALL_PREFIX=/opt/libsmb2-tsan -DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_FLAGS="-O1 -g -fsanitize=thread" \
-DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=thread" >/dev/null
make -C "$RUNNER_TEMP/libsmb2/build-tsan" -j"$(nproc)" >/dev/null
sudo make -C "$RUNNER_TEMP/libsmb2/build-tsan" install >/dev/null
sudo -E env PATH="$PATH" \
PKG_CONFIG_PATH=/opt/libsmb2-tsan/lib/pkgconfig \
LD_LIBRARY_PATH=/opt/libsmb2-tsan/lib \
TSAN_OPTIONS="halt_on_error=1 exitcode=66" \
CFLAGS="-O1 -g -fsanitize=thread" LDLIBS="-fsanitize=thread" \
WITH_LIBSMB2=1 samples/network/smb_retro/local_samba_test.sh
sudo make -C samples/network/smb_retro clean
@@ -15,10 +15,6 @@ permissions:
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:
samples:
name: Build and run libretro-common/samples
@@ -27,65 +23,12 @@ jobs:
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
# All three packages ship on the stock ubuntu-latest image, so
# this step is a no-op there and apt is only contacted if the
# image ever drops one of them.
# ffmpeg (with libx264 and libx265): formats/h264/rh264_lossless_test
# and formats/h265/rh265_lossless_test build their corpora and
# their reference decodes with it.
if dpkg -s build-essential zlib1g-dev clang ffmpeg >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential zlib1g-dev clang ffmpeg && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential zlib1g-dev clang ffmpeg
sudo apt-get update -y
sudo apt-get install -y build-essential zlib1g-dev clang
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
uses: actions/checkout@v3
- name: Build and run samples
shell: bash
@@ -110,31 +53,24 @@ jobs:
# self-contained test and exits 0 on success / non-zero on
# failure. These are built AND executed.
declare -a RUN_TARGETS=(
float_to_s32_test
compat_fnmatch_test
snprintf
unbase64_test
crc32_test
emscripten_mmap_test
archive_zip_test
archive_zstd_test
config_file_test
path_resolve_realpath_test
fill_pathname_test
nbio_test
rpng
rzip_chunk_size_test
rzip_matches_buf_test
rzip_codec_test
rzip_parallel_test
data_transfer_source_test
data_transfer_prefix_test
data_transfer_window_test
audio_transfer_window_test
rjpeg_test
rh264_lossless_test
rh264_lossless_test_nothreads
rh265_lossless_test
rh265_lossless_test_nothreads
r7z_lzma_props_test
vcdiff_test
net_ifinfo
@@ -142,88 +78,27 @@ jobs:
vfs_mapped_ptr_test
vfs_large_file_test
vfs_seek_contract_test
vfs_bulk_read_test
vfs_v5_metadata_test
vfs_hybrid_test
filestream_rbuf_fault_test
cdrom_cuesheet_overflow_test
cdfs_dir_record_test
cdfs_pure_api_test
chd_meta_overflow_test
strlcpy_append_test
http_parse_test
rjson_test
rm3u_test
rtga_test
rbmp_test
rbmp_encode_test
# Every 16-bit input through each pixconv converter, with
# SSE2, with MMX only, and with no SIMD at all.
pixconv_test
pixconv_test_nosimd
pixconv_test_scalar
rpng_chunk_overflow_test
rpng_roundtrip_test
rpng_decode_corpus_test
# Benchmark, not a pass/fail test, but it runs its default
# 4K comparison and exits 0, so under this job's sanitizer
# build it doubles as end-to-end ASan/UBSan smoke coverage
# of the old and new screenshot encode/write paths.
# Timings in its output are informational only.
screenshot_io_bench
word_wrap_overflow_test
task_queue_title_error_test
task_queue_snapshot_test
task_queue_init_failure_test
# Stops the worker with a bound when a detachable
# handler is stuck; waits ~1.5 s by design.
task_queue_detach_test
task_queue_main_thread_test
task_queue_budget_test
image_blit_bands_test
tpool_wait_test
# Four CPU-burning jobs on a pool of four must overlap;
# on a one-core runner it notes that and still passes.
tpool_parallel_test
data_transfer_pool_scrub_test
retro_atomic_test
retro_atomic_extern_c_linkage_test
retro_atomic_extern_c_linkage_test_cxx
# The PS2 EE backend, built off-target against a stub
# <kernel.h>: the PS2 CI lane compiles it, this runs it.
retro_atomic_ps2_backend_test
retro_spsc_test
mpsc_stack_test
retro_waitable_spsc_test
retro_eventcount_test
# retro_sleep_until_us must never return early against the
# microsecond clock; the late bound is loose for a loaded
# runner.
retro_sleep_until_test
# Runs its natural tier only here; procbarrier-tiers.yml
# forces every tier on Linux, Windows and macOS runners.
retro_procbarrier_test
retro_asym_eventcount_test
sthread_ex_test
fast_cores_test
memshm_test
fastjmp_test
rdds_block_test
faulthandler_test
memshm_area_test
msg_fifo_queue_test
audio_mixer_loop_test
audio_mixer_rate_guard_test
# The AC-3 / E-AC-3 frame layer against ffmpeg's streams:
# ffmpeg is in the package list above for it.
rac3_frame_test
rac3_tables_test
rac3_decode_test
rac3_encode_test
# IEC 61937 bursts against ffmpeg's spdif muxer and demuxer.
iec61937_test
# The AC-3 arm of audio_transfer against ffmpeg's decode.
audio_transfer_ac3_test
)
# Targets that are built but deliberately not executed, each
@@ -249,14 +124,6 @@ jobs:
# leak is fixed, so LeakSanitizer runs at full strictness and
# any surviving allocation is a real config_file regression.
declare -A RUN_ENV=(
# fastjmp_jmp is a longjmp that is not libc's, so ASan's
# fake-stack check cannot follow it; the same holds for
# libco. The jump is what the test is for.
[fastjmp_test]="ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=0"
# The filter must be the one that sees SIGSEGV: ASan installs
# its own, and with it the faults never reach the code under
# test. handle_segv=0 is how a fastmem core runs.
[faulthandler_test]="ASAN_OPTIONS=detect_leaks=1:handle_segv=0 UBSAN_OPTIONS=handle_segv=0"
)
# Samples that are build-only (either they require command-line
@@ -265,15 +132,6 @@ jobs:
# regressions but not executed.
declare -a BUILD_ONLY_DIRS=(
formats/xml
# A benchmark, not a test: its numbers only mean something
# on two dedicated physical cores, which a runner is not.
queues/retro_spsc_bench
# The same, and for the same reason: it reports park and
# commit counts under contention, which a shared runner
# cannot produce meaningfully. It also builds a second
# binary, the scond variant, and being build-only covers
# both without naming either.
rthreads/retro_eventcount_bench
)
# Samples that are currently broken at build time on a stock
@@ -515,27 +373,6 @@ jobs:
TSAN_OPTIONS=halt_on_error=1 ./retro_atomic_test
- name: Run mpsc_stack_test under Clang + ThreadSanitizer
shell: bash
working-directory: libretro-common/samples/queues/mpsc_stack_test
run: |
# mpsc_stack.h is the lock-free many-producer single-consumer
# stack the runloop's deferred messages ride. Its contract is
# the push's compare-exchange publishing the node against the
# drain's exchange; a weakened push loses nodes under
# contention, observable as a drained-count mismatch AND as a
# TSan-reported race. The default ASan/UBSan pass above
# catches neither reliably - the race needs TSan's scheduling
# to manifest - so this lane is the one that holds the
# contract.
set -u
set -o pipefail
make clean
CC=clang make all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 ./mpsc_stack_test
- name: Run retro_spsc_test under Clang + ThreadSanitizer
shell: bash
working-directory: libretro-common/samples/queues/retro_spsc_test
@@ -561,52 +398,6 @@ jobs:
TSAN_OPTIONS=halt_on_error=1 ./retro_spsc_test
- name: Run retro_eventcount_test under Clang + ThreadSanitizer
shell: bash
working-directory: libretro-common/samples/rthreads/retro_eventcount_test
run: |
# retro_eventcount parks a consumer without putting a lock on
# the producer's fast path. What it can get wrong is a lost
# wakeup: a notify that reads zero waiters while a consumer
# that has not yet seen the new epoch is on its way into a
# park. The guard is a seq_cst fence on both sides, and a
# build with either fence weakened still passes on x86 TSO,
# so the value checks alone prove nothing -- TSan is what
# sees the missing barrier.
#
# 'make check' runs the address-wait backend and then the
# condition-variable one, which is the backend macOS, the
# BSDs and the console ports get. Both matter; only the
# first is native here.
#
# The harness carries its own watchdog, so a genuine lost
# wakeup fails the job in a minute instead of hanging it.
set -u
set -o pipefail
make clean
CC=clang make check SANITIZER=thread
- name: Run rzip_parallel_test under Clang + ThreadSanitizer
shell: bash
working-directory: libretro-common/samples/streams/rzip
run: |
# rzip_stream.c's chunk-writer pool hands each slot between the
# writer and one worker on an acquire/release status word and
# parks both sides on retro_eventcount, with no lock anywhere.
# The value checks prove in-order emission; a weakened store
# or a lost wakeup still passes them on x86 TSO, and only TSan
# sees the missing barrier. The test drives the pool at every
# width and through two hundred short lifetimes so the
# start / park / shutdown edges are exercised often.
set -u
set -o pipefail
make clean
CC=clang make rzip_parallel_test SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 ./rzip_parallel_test
- name: Run crc32_test under Clang + ThreadSanitizer
shell: bash
working-directory: libretro-common/samples/encodings/crc32
@@ -627,92 +418,6 @@ jobs:
TSAN_OPTIONS=halt_on_error=1 ./crc32_test
# memmap.h picks between libretro-common's mman shim and the
# platform's own <sys/mman.h>, and Emscripten is the target where
# that choice is load-bearing: its libc declares mmap with a 64-bit
# off_t while the shim declares a 32-bit size_t, so a consumer that
# sees both declarations fails to compile, and reserve/commit has no
# meaning behind it at all - an anonymous mmap there allocates and
# zeroes the whole length, and mprotect and madvise are no-ops.
#
# None of that is reachable from the native sweep above, which
# compiles the sample with every Emscripten branch preprocessed
# away. This lane is where the declarations are held to libc's.
emscripten-memmap:
name: Emscripten memmap ABI
runs-on: ubuntu-latest
timeout-minutes: 20
env:
# Pinned rather than floating: the job exists to hold a libc ABI,
# so the toolchain it is held against changes deliberately.
EM_VERSION: 5.0.1
EM_CACHE_FOLDER: emsdk-cache
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Cache emsdk
uses: actions/cache@v4
with:
path: ${{ env.EM_CACHE_FOLDER }}
key: ${{ env.EM_VERSION }}-${{ runner.os }}
- name: Set up Emscripten
uses: emscripten-core/setup-emsdk@v15
with:
version: ${{ env.EM_VERSION }}
actions-cache-folder: ${{ env.EM_CACHE_FOLDER }}
- name: Run the memmap sample under node
shell: bash
working-directory: libretro-common/samples/memmap/emscripten_mmap
run: |
set -eu
set -o pipefail
# Fails to compile without the libc declaration; the mmap
# assignment through an off_t-typed function pointer is the
# discriminator. The mprotect / reserve / msync checks that
# follow it cover the calls the same header choice hands to
# libc.
make clean
make check-wasm
- name: Compile vfs_implementation.c with file mappings enabled
shell: bash
working-directory: libretro-common
run: |
set -eu
set -o pipefail
# The in-tree translation unit that includes memmap.h and
# <sys/mman.h> together. Makefile.emscripten does not set
# HAVE_MMAP today, so nothing else compiles this shape for
# wasm - which is exactly why the two declarations can drift
# apart unnoticed until a downstream consumer hits it.
emcc -std=c89 -D_GNU_SOURCE -DHAVE_MMAP \
-Wall -Wextra -Werror \
-I include -c vfs/vfs_implementation.c \
-o "$RUNNER_TEMP/vfs_implementation.o"
# Cross-architecture validation lane for retro_atomic_test.
#
# The samples job above runs on x86_64, which is a strongly-ordered
@@ -743,61 +448,12 @@ jobs:
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
# clang ships on the stock ubuntu-latest image; apt is only
# contacted if the image ever drops it.
if dpkg -s clang >/dev/null 2>&1; then
echo "clang already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
clang && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
clang
sudo apt-get update -y
sudo apt-get install -y clang
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
uses: actions/checkout@v3
- name: Build fuzz target
shell: bash
@@ -809,7 +465,6 @@ jobs:
-fno-sanitize-recover=all \
-I$LC/include -o config_file_fuzz config_file_fuzz.c \
$LC/file/config_file.c \
$LC/string/rstrtod.c \
$LC/file/file_path.c \
$LC/compat/compat_strl.c \
$LC/compat/compat_strcasestr.c \
@@ -863,55 +518,12 @@ jobs:
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential ${{ matrix.apt_pkgs }} qemu-user-static && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential ${{ matrix.apt_pkgs }} qemu-user-static
sudo apt-get update -y
sudo apt-get install -y build-essential ${{ matrix.apt_pkgs }} qemu-user-static
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
uses: actions/checkout@v3
- name: Build retro_atomic_test for ${{ matrix.arch }}
working-directory: libretro-common/samples/atomic/retro_atomic_test
@@ -1015,55 +627,12 @@ jobs:
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential ${{ matrix.apt_pkgs }} qemu-user-static && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential ${{ matrix.apt_pkgs }} qemu-user-static
sudo apt-get update -y
sudo apt-get install -y build-essential ${{ matrix.apt_pkgs }} qemu-user-static
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
uses: actions/checkout@v3
- name: Build crc32_test for ${{ matrix.name }}
working-directory: libretro-common/samples/encodings/crc32
@@ -1084,27 +653,6 @@ jobs:
set -o pipefail
${{ matrix.qemu }} -L ${{ matrix.sysroot }} ./crc32_test
- name: Build and run pixconv_test under qemu-user
shell: bash
working-directory: libretro-common/samples/gfx/pixconv
run: |
set -euo pipefail
# The ARM legs are the only place the NEON converters run;
# PowerPC runs the scalar paths big-endian. The armhf
# toolchain defaults to VFP without NEON, so armv7 builds a
# second time with NEON on.
make clean
CC="${{ matrix.cc }}" CFLAGS="${{ matrix.cflags }}" make all
for t in pixconv_test pixconv_test_nosimd pixconv_test_scalar; do
${{ matrix.qemu }} -L ${{ matrix.sysroot }} ./$t
done
if [ "${{ matrix.name }}" = armv7 ]; then
make clean
CC="${{ matrix.cc }}" CFLAGS="-mfpu=neon" make all
${{ matrix.qemu }} -L ${{ matrix.sysroot }} ./pixconv_test
fi
make clean
- name: Run vfs_mapped_ptr_test without mappings (MMAP=0)
shell: bash
working-directory: libretro-common/samples/file/vfs
@@ -1123,22 +671,3 @@ jobs:
UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./vfs_mapped_ptr_test
echo "[pass] vfs_mapped_ptr_test (MMAP=0, ASan)"
- name: Run vfs_v5_metadata_test against a copy_file_range that ignores len
shell: bash
working-directory: libretro-common/samples/file/vfs
run: |
set -eu
# A sandboxed kernel (gVisor on some hosted runners) answers
# copy_file_range by copying to EOF regardless of len. The
# VFS must account the bytes, retire the kernel path for the
# process, and finish the copy in place on the portable path.
# FAKE_CFR=1 is the to-EOF case, FAKE_CFR=2 a partial overshoot
# that leaves the copy part-way and has to be resumed.
for mode in 1 2; do
make clean >/dev/null
make vfs_v5_metadata_test FAKE_CFR=$mode SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./vfs_v5_metadata_test
echo "[pass] vfs_v5_metadata_test (FAKE_CFR=$mode, ASan)"
done
@@ -21,10 +21,6 @@ permissions:
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:
libretro-common-tests:
name: Build and run libretro-common/Makefile.test
@@ -33,41 +29,11 @@ jobs:
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
# ffmpeg: tools/companion_thumbs_test.sh builds its video-hover
# fixture (a 2 KB Baseline MP4) with it.
pkgs="build-essential check pkg-config zlib1g-dev lcov gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 wine wine64 ffmpeg gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf gcc-mipsel-linux-gnu qemu-user"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
sudo apt-get update -y
sudo apt-get install -y build-essential check pkg-config \
zlib1g-dev lcov \
gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 wine wine64
# mingw and wine are for the Windows A/W configuration matrix
# in Makefile.test. libretro-common selects between the ANSI
# and the wide Win32 entry points three ways and, until these
@@ -81,25 +47,7 @@ jobs:
# contributor's local run is not blocked.
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
uses: actions/checkout@v3
- name: Build and run the unit test suites
shell: bash
@@ -115,24 +63,10 @@ jobs:
# coverage, in order -- coverage files collide otherwise.
# Any suite failing to build, or any check failing, or any
# sanitizer report, fails the job.
# 'unit-tests' by name: the default goal of Makefile.test is
# win32-configs, so a bare make here builds the Windows A/W
# matrix and none of the suites this step exists to run. The
# 'all' target adds the concurrency and I/O samples, whose
# runtime depends on how many processors the runner has.
make -f Makefile.test unit-tests \
make -f Makefile.test \
LIBCHECK_CFLAGS="$(pkg-config --cflags check)" \
CFLAGS="$(pkg-config --cflags check)"
echo "[pass] libretro-common unit test suites"
# The ARMv8 AES + PMULL path executes only on ARM; this
# runs the crypto suite under qemu-aarch64 in both the
# dispatched and the baseline-crypto shape.
make -f Makefile.test crypto-aarch64-check
make -f Makefile.test crypto-arm-check
make -f Makefile.test crypto-mips-check
# every lazily set up table or CPU check, first used by
# eight threads at once under TSan
make -f Makefile.test crypto-tsan-check
- name: Check VFS backend symbol parity
shell: bash
@@ -149,156 +83,6 @@ jobs:
# free, on Linux.
python3 tools/vfs_backend_parity.py
- name: Check every command describes itself
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# HELP prints command.h's tables, and interfaces that hand the
# commands to a client are generated from them: a command
# added without a description reaches all of those blank.
python3 tools/command_table_check.py
- name: Check no video driver deletes overlay textures it was lent
shell: bash
run: |
set -eu
# load_textures lends a driver the overlay pack's handles for
# one page; they are on the pack's other pages too and are
# the pack's to delete. gl2 marked them as borrowed and then
# deleted them anyway at the next page, so rotating an
# Android device blacked the overlay out until the core was
# restarted. No runner can run a GL driver, so this is the
# check at source level: every driver with load_textures
# sets, tests and clears its borrowed marker.
python3 tools/overlay_texture_ownership.py
- name: Check overlay setters refuse an image the driver does not hold
shell: bash
run: |
set -eu
# set_alpha, vertex_geom and tex_geom are called whenever the
# layout, opacity or page changes, not only after a load()
# that worked: with no page the driver's arrays are NULL, and
# after a smaller page or a failed load the index is off the
# end. 7661ab06e7 bounded the GL geometry setters and missed
# set_alpha; D3D, Vulkan and Metal had no check at all. No
# runner can run these drivers, so this is the check at
# source level for the ones that have been audited.
python3 tools/overlay_setter_bounds.py
- name: Check companion backend feature parity
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# The Qt, Win32 and Cocoa desktop companions share one C core
# but each has its own presentation; a backend can quietly omit
# a feature (no file browser, no scan, no core picker) and still
# build and run, the gap only showing when a user switches
# drivers. Source-level check, for free, on Linux.
python3 tools/companion_parity.py
- name: Companion thumbnail engine regression test (plain, TSan, ASan)
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# The shared thumbnail engine every desktop companion draws
# through: real decoder, decode threads, cache, priority,
# cancel, shutdown, and one hover on a video (the still and
# the animation share one session). Under both sanitizers,
# since it is the one piece of threaded code in the
# companions.
tools/companion_thumbs_test.sh
tools/companion_thumbs_test.sh tsan
tools/companion_thumbs_test.sh asan
- name: Companion core regression test (plain, ASan)
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# The toolkit-free model every desktop companion drives:
# playlist listing and All Playlists, the thumbnail path rule,
# the file browser, the run / needs-core paths, launch
# options - against real .lpl fixtures, with RetroArch's
# state replaced by stubs.
tools/companion_core_test.sh
tools/companion_core_test.sh asan
tools/companion_core_test.sh tsan
- name: C89 / Win32 syntax gate on the companion sources
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# MSVC 2005 builds these as C89 through griffin. The gate's
# second pass needs a 32-bit mingw for the Windows-only unit
# (the host gcc has no <windows.h>, which used to make the
# pass skip it silently - that is how mixed declarations
# reached master).
sudo apt-get install -y -qq gcc-mingw-w64-i686 gcc-mingw-w64-x86-64 > /dev/null
tools/mingw_syntax_check.sh ui/drivers/ui_win32_companion.c \
ui/companion/companion_core.c ui/companion/companion_thumbs.c \
ui/companion/companion_dock.c \
gfx/gfx_anim_preview.c
- name: Cocoa companion regression harness (GNUstep AppKit, headless)
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# The real ui/drivers/ui_cocoa_companion.m, compiled and linked
# against GNUstep's Foundation + AppKit with the real companion
# core and the core test's fixtures, driven under Xvfb the way a
# user drives it (view popup, File Browser tab, close) and
# checked on the AppKit objects themselves.
sudo apt-get install -y -qq gobjc gnustep-devel gnustep-back-common xvfb > /dev/null
tools/companion_cocoa_test.sh
# ASan too: the grid's prefetch reaching past the thumbnail
# marks only shows under a checking allocator (it crashed the
# app on macOS, where Apple's is one).
tools/companion_cocoa_test.sh asan
- name: Win32 companion regression harness (mingw + Wine, headless)
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# The real ui/drivers/ui_win32_companion.c, built with mingw and
# linked with the real companion core and the core test's
# fixtures, run under Wine on Xvfb and driven with the messages
# the widgets send; checked on the real controls.
sudo apt-get install -y -qq gcc-mingw-w64-x86-64 wine xvfb > /dev/null
tools/companion_win32_test.sh
- name: WDM-KS ABI against the system ks.h
shell: bash
working-directory: samples/audio/wdmks_abi
run: |
set -eu
# audio/common/wdmks_ks.h declares the kernel-streaming
# interface the WDM-KS driver uses, because ks.h and
# ksmedia.h ship with the driver kit rather than the
# Platform SDK and not every toolchain here has them.
#
# That is only safe while what is declared matches what the
# system declares. A wrong layout does not fail to build and
# does not misbehave visibly: it hands the kernel a structure
# whose fields are in the wrong places. So this compiles ours
# beside the real headers and asserts every size, every field
# offset, every constant and the IOCTL code, on both word
# sizes, and in C89 as well as gnu99.
#
# It has already earned it. KSDATAFORMAT is a union with a
# LONGLONG that aligns it to eight; declared as the plain
# struct it resembles, KSDATARANGE_AUDIO came out 84 bytes
# against 88 and every field past the first would have been
# read four bytes off.
make check
echo "[pass] wdmks_abi"
- name: Check stack frame budget
shell: bash
working-directory: ${{ github.workspace }}
@@ -15,10 +15,6 @@ permissions:
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:
samples:
name: Build and run libretro-db/samples
@@ -27,60 +23,12 @@ jobs:
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential zlib1g-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
sudo apt-get update -y
sudo apt-get install -y build-essential zlib1g-dev
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
uses: actions/checkout@v3
- name: Build and run samples
shell: bash
-308
View File
@@ -1,308 +0,0 @@
name: CI Linux menu harness
# The menu playlist navigation harness links the SHIPPING RetroArch
# objects with only main() replaced, so unlike every other sample it
# needs a full build of the program before it can be built at all.
#
# That is why it lives in its own workflow rather than in
# Linux-samples-tasks: a full build does not fit inside that job's
# ten-minute budget, and putting it there cancelled the whole job -
# every other sample with it - rather than just failing its own step.
# Here it can take the time it needs without being able to take
# anything else down with it.
#
# It also needs a NON-Qt build: with Qt enabled main() lives in
# ui_qt.o and drags the entire Qt UI in with it.
on:
push:
paths:
- 'menu/**'
- 'playlist.c'
- 'playlist.h'
- 'tasks/task_content*'
- 'samples/menu/playlist_nav/**'
- 'samples/menu/nav_repeat_stall/**'
- 'runloop.c'
- 'samples/menu/network_settings/**'
- 'intl/msg_hash_lbl.h'
- 'msg_hash_lbl_str.h'
- 'samples/menu/resolution_reset/**'
- 'samples/settings/packed_rows/**'
- 'setting_list.h'
- 'gfx/video_defines.h'
- '.github/workflows/Linux-menu-harness.yml'
pull_request:
paths:
- 'menu/**'
- 'playlist.c'
- 'playlist.h'
- 'tasks/task_content*'
- 'samples/menu/playlist_nav/**'
- 'samples/menu/nav_repeat_stall/**'
- 'runloop.c'
- 'samples/menu/network_settings/**'
- 'intl/msg_hash_lbl.h'
- 'msg_hash_lbl_str.h'
- 'samples/menu/resolution_reset/**'
- 'samples/settings/packed_rows/**'
- 'setting_list.h'
- 'gfx/video_defines.h'
- '.github/workflows/Linux-menu-harness.yml'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
menu-harness:
name: Build and run the menu navigation harness
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential zlib1g-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build RetroArch headless
shell: bash
run: |
set -eu
# The harness drives the menu with the null drivers, so
# everything that draws or talks to the network is dead
# weight here - and building it is the entire cost of this
# workflow. Disabling it takes the build from roughly ten
# minutes to about three, and avoids depending on graphics
# packages the runner may or may not carry: configure found
# X11 and xcb but not libX11-xcb, and the link failed on
# -lX11-xcb.
#
# Qt in particular has to go: with it enabled main() lives
# in ui_qt.o, and the harness replaces main().
# Networking stays on: the network settings harness below
# needs the SMB and NFS client screens compiled in.
./configure --disable-qt --disable-x11 \
--disable-opengl --disable-opengl_core \
--disable-opengl1 --disable-vulkan \
--disable-cheevos \
--disable-ffmpeg
make -j$(nproc)
- name: Build and run content_closing_test
shell: bash
run: |
set -eu
# The guard that keeps the frame loop out of a core being
# torn down (core_run() refusing retro_run() while
# content_closing is set) cannot fire in shipped code yet:
# closing is still synchronous, so no frame runs during it.
# It goes live in the change that first lets frames run
# during a close, and if it is wrong the symptom is a call
# into an unloaded dylib - so it is driven here directly,
# against the real core_run() in a real frontend, rather
# than going live untested.
#
# Shares the non-Qt build made above; adds about a second.
samples/runloop/content_closing/build.sh
./samples/runloop/content_closing/content_closing_test
make -C samples/runloop/content_closing clean
- name: Build and run menu_playlist_nav_test
shell: bash
run: |
set -eu
# Four field reports came out of the seam between the
# playlist reader and the menu - a stale playlist's entries
# under a new heading, then a blank list the back button
# could not leave, then a list that filled only after the
# user pressed something, then #19427's placeholder flashing
# on every completed read - and no oracle that stopped at
# the reader could see any of them.
#
# The harness installs a VFS through the seam the frontend
# uses for SAF, returning short reads WITH a per-read delay.
# Short reads alone reproduce SAF's syscall count but not
# its latency, and on local storage the whole playlist still
# fits inside one budget slice - which is exactly why none
# of the three reports reproduced on a desktop.
samples/menu/playlist_nav/build.sh
./samples/menu/playlist_nav/menu_playlist_nav_test
make -C samples/menu/playlist_nav clean
- name: Build and run menu_nav_repeat_stall_test
shell: bash
run: |
set -eu
# One press on a menu entry whose frame stalls - Ozone and
# XMB build a large playlist synchronously when the selection
# lands on it - has to move the selection once. The menu acts
# on input one poll old, so the hold time has to be measured
# between polls or the stall fires an auto-repeat. Drives the
# real runloop with a scripted input driver; also checks that
# a hold across the stall still repeats and that a steady hold
# waits out the initial scroll delay. Shares the non-Qt build
# made above.
samples/menu/nav_repeat_stall/build.sh
./samples/menu/nav_repeat_stall/menu_nav_repeat_stall_test
make -C samples/menu/nav_repeat_stall clean
- name: Build and run menu_network_settings_test
shell: bash
run: |
set -eu
# The NFS Network Settings entry opened an empty "null"
# browser: the label its deferred list is pushed with had no
# row in msg_hash_lbl.h, so it resolved to "null" and the
# push found nothing. The harness resolves the SMB and NFS
# labels, opens Settings > Network and both screens through
# the real dispatch, and checks the Quick Menu no longer
# carries the two entries.
samples/menu/network_settings/build.sh
./samples/menu/network_settings/menu_network_settings_test
make -C samples/menu/network_settings clean
- name: Build and run resolution_reset_test
shell: bash
run: |
set -eu
# Start on the Resolution entry reinits and sets the video
# mode at the output size; it must keep the window state the
# frontend is in rather than take a windowed desktop session
# full screen. Shares the non-Qt build made above.
samples/menu/resolution_reset/build.sh
./samples/menu/resolution_reset/resolution_reset_test
make -C samples/menu/resolution_reset clean
- name: Build and run packed_rows_test
shell: bash
run: |
set -eu
# Settings rows that each own one half of a packed settings_t
# word - the custom viewport's origin and size, the window
# size pair - driven through their display strings, a right
# press and the dropdown list. Each row has to show and set
# its own axis and leave its partner as it stands. Shares the
# non-Qt build made above.
samples/settings/packed_rows/build.sh
./samples/settings/packed_rows/packed_rows_test
make -C samples/settings/packed_rows clean
- name: Hot function budget
shell: bash
run: |
set -eu
# Code size and stack frame of the functions that run every
# frame, against a checked-in reference: a change that doubles
# either passes every lane in the suite and shows up only as a
# slower frame on someone's machine. Uses the release objects
# this job already built.
.github/workflows/scripts/hot-function-budget.sh
- name: Lock budget
shell: bash
run: |
set -eu
# Lock acquisitions on the paths meant to take none, or a
# counted few, against tools/lock_acquire_budget.ref: a lock
# put back on a per-frame path passes every lane and shows up
# only as a slower frame. Same release objects as above; this
# build has no Vulkan, so the Vulkan entries report SKIP.
tools/lock_acquire_budget.sh
- name: Build and run threaded_video_test
shell: bash
run: |
set -eu
# The threaded video wrapper against the real runloop, on the
# same non-Qt menu build: the runtime toggle, reinit under the
# wrapper, the command mailbox, presenter repeats, and the
# font init/free marshalling - the last of which is where a
# deferred font free unbound the video thread's GL context on
# X11 and left every frame after it black. This build has no
# allocator sanitizer, so it is also the one job where the
# frame-path heap lane runs: it counts heap calls over three
# hundred frames, threaded and not, and the frame path makes
# none.
samples/gfx/threaded_video/build.sh
./samples/gfx/threaded_video/threaded_video_test 3
make -C samples/gfx/threaded_video clean
- name: Build and run content_load_test
shell: bash
run: |
set -eu
# The content load as a chain of main-thread tasks, against the
# real runloop on the same non-Qt menu build: frames presented
# between stages, one load at a time, a core's reinit deferred
# to the load's driver stage, the dummy-core fallback, a
# hardware-render request carried across the driver rebuild,
# the task queue surviving the load, and the close waiting out
# a save state from the frame loop.
samples/tasks/content_load/build.sh
./samples/tasks/content_load/content_load_test
make -C samples/tasks/content_load clean
- name: Build and run explore_build_test
shell: bash
run: |
set -eu
# The Explore index built in steps: one item per step hashes
# the same as the build in one go, and the explore task returns
# unfinished across checks with Threaded Tasks off.
samples/menu/explore_build/build.sh
./samples/menu/explore_build/explore_build_test
make -C samples/menu/explore_build clean
-222
View File
@@ -1,222 +0,0 @@
name: CI Linux network clients
# The built-in TLS, SMB2/3 and NFSv3 clients against real servers:
# openssl s_server, Samba, unfs3, nfs-ganesha and a MIT KDC on the runner, natively, as Windows
# builds under Wine, under ASan + UBSan + LSan, plus libFuzzer over the
# parsers. Its own job so the libretro-common unit-test job keeps its
# short budget.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
network-clients:
name: TLS, SMB and NFS clients against local servers
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Install dependencies
timeout-minutes: 25
run: |
sudo apt-get update -y
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
# tshark's dumpcap asks whether to be setuid: no, runs are root
echo "wireshark-common wireshark-common/install-setuid boolean false" | sudo debconf-set-selections
export DEBIAN_FRONTEND=noninteractive
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only --no-install-recommends build-essential clang \
gcc-mingw-w64-x86-64 openssl samba libtirpc-dev flex bison autoconf automake wine wine64 \
nfs-ganesha nfs-ganesha-vfs krb5-kdc krb5-admin-server krb5-user winbind \
samba-dsdb-modules samba-ad-provision samba-vfs-modules acl smbclient tshark && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y --no-install-recommends build-essential clang \
gcc-mingw-w64-x86-64 openssl samba libtirpc-dev flex bison autoconf automake wine wine64 \
nfs-ganesha nfs-ganesha-vfs krb5-kdc krb5-admin-server krb5-user winbind \
samba-dsdb-modules samba-ad-provision samba-vfs-modules acl smbclient tshark
- name: Checkout
uses: actions/checkout@v5
- name: Built-in TLS client against a local openssl server
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# net_socket_ssl_retro.c end to end: every cipher suite, both
# curves, RSA / P-256 / P-384 certificates under a CA made on
# the spot, verify required / optional / disabled, and the
# refusals that must happen (wrong hostname, untrusted CA). An
# IP address matches only an iPAddress SAN entry, never the
# same address written as a DNS name.
samples/network/tls_retro/local_server_test.sh
# The same tool cross-linked for Windows: the sample's link
# line has to carry Winsock, which nothing on Linux checks.
make -C samples/network/tls_retro clean
- name: Built-in SMB2/3 client against a local smbd
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# net_smb2.c end to end against Samba on the loopback: every
# dialect 2.0.2 to 3.1.1 with signing mandatory, AES-CCM and
# AES-GCM sealing required, and a refused logon. Root for
# port 445; the script itself skips without smbd.
sudo samples/network/smb_retro/local_samba_test.sh
# and with Kerberos against a Samba AD DC provisioned on the
# spot, NTLM disabled on it so only a ticket can log in
sudo samples/network/smb_retro/local_ad_dc_test.sh
sudo make -C samples/network/smb_retro clean
- name: Windows builds under Wine
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# The MinGW builds run, not just link: the crypto and keychain
# suites, then the three server matrices with the Windows tools
# talking to the same local openssl, Samba and unfs3.
export WINEDEBUG=-all WINEPREFIX=$RUNNER_TEMP/wineprefix
# the tools below are run through wine, so it must be there
command -v wine >/dev/null
make -C libretro-common -f Makefile.test win32-wine-check
export CC=x86_64-w64-mingw32-gcc RUNNER=wine EXE=.exe
make -C samples/network/tls_retro clean
samples/network/tls_retro/local_server_test.sh
make -C samples/network/tls_retro clean
make -C samples/network/smb_retro clean
# smbd needs root for port 445, and Wine refuses both a prefix
# owned by someone else and creating one inside a directory it
# does not own ($RUNNER_TEMP belongs to the runner user), so the
# root run gets a prefix under /tmp with root's own HOME
sudo -E env HOME=/root WINEPREFIX=/tmp/wineprefix-root wineboot -u
sudo -E env HOME=/root WINEPREFIX=/tmp/wineprefix-root samples/network/smb_retro/local_samba_test.sh
sudo -E env HOME=/root WINEPREFIX=/tmp/wineprefix-root samples/network/smb_retro/local_ad_dc_test.sh
sudo make -C samples/network/smb_retro clean
make -C samples/network/nfs_retro clean
samples/network/nfs_retro/local_unfs3_test.sh
make -C samples/network/nfs_retro clean
sudo -E env HOME=/root WINEPREFIX=/tmp/wineprefix-root samples/network/nfs_retro/local_ganesha_test.sh
sudo make -C samples/network/nfs_retro clean
sudo -E env HOME=/root WINEPREFIX=/tmp/wineprefix-root samples/network/nfs_retro/local_read_plus_test.sh
sudo make -C samples/network/nfs_retro clean
make -C samples/network/krb5_retro clean
samples/network/krb5_retro/local_kdc_test.sh
make -C samples/network/krb5_retro clean
- name: Fuzz the network parsers
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# libFuzzer over the X.509 parser and the TLS, SMB and NFS
# clients' receive paths (a listener in the harness answers the
# client with the fuzzer's input), under ASan + UBSan, from a
# seed corpus recorded off real servers. Any crash, timeout or
# leak artifact fails the step.
make -C libretro-common/test/fuzz fuzz-run FUZZ_SECONDS=30
if ls libretro-common/test/fuzz/crash-* libretro-common/test/fuzz/leak-* libretro-common/test/fuzz/timeout-* >/dev/null 2>&1; then
echo "fuzzer artifacts found"; exit 1
fi
make -C libretro-common/test/fuzz clean
- name: Network client matrices under ASan + UBSan + LSan
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# The three server matrices again, with the clients built under
# the sanitizers: every code path a real server drives, checked
# for memory errors, undefined behaviour and leaks. UBSan found
# a NULL memcpy in the SHA-2 stream updates on the SHA-384 PRF
# path the first time this ran.
export CFLAGS="-O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer"
export LDFLAGS="-fsanitize=address,undefined"
export ASAN_OPTIONS=detect_leaks=1:strict_string_checks=1
export UBSAN_OPTIONS=print_stacktrace=1
make -C samples/network/tls_retro clean
samples/network/tls_retro/local_server_test.sh
make -C samples/network/tls_retro clean
make -C samples/network/smb_retro clean
sudo -E samples/network/smb_retro/local_samba_test.sh
sudo -E samples/network/smb_retro/local_ad_dc_test.sh
make -C samples/network/smb_retro clean
make -C samples/network/nfs_retro clean
samples/network/nfs_retro/local_unfs3_test.sh
make -C samples/network/nfs_retro clean
sudo -E samples/network/nfs_retro/local_ganesha_test.sh
sudo make -C samples/network/nfs_retro clean
sudo -E samples/network/nfs_retro/local_read_plus_test.sh
sudo make -C samples/network/nfs_retro clean
make -C samples/network/krb5_retro clean
samples/network/krb5_retro/local_kdc_test.sh
make -C samples/network/krb5_retro clean
- name: Built-in NFSv3 client against unfs3
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# net_nfs3.c end to end against a user-space NFSv3 server built
# from unfs3's repository (Ubuntu no longer packages it), on
# fixed ports without a portmapper: mount, write, read, seek,
# stat, mkdir, rename, truncate, list, unlink, refused export.
samples/network/nfs_retro/local_unfs3_test.sh
# NFSv4.0 (one COMPOUND per operation, no portmapper or MOUNT,
# pseudo-filesystem export) against nfs-ganesha from apt
sudo -E samples/network/nfs_retro/local_ganesha_test.sh
# NFSv4.2 READ_PLUS against a fake server reporting the holes
# the filesystem really holds, its replies checked by
# Wireshark's own dissector
sudo make -C samples/network/nfs_retro clean
sudo -E samples/network/nfs_retro/local_read_plus_test.sh
# and its Windows link line, cross-linked
sudo make -C samples/network/nfs_retro clean
CC=x86_64-w64-mingw32-gcc make -C samples/network/nfs_retro nfs_test
make -C samples/network/nfs_retro clean
CC=x86_64-w64-mingw32-gcc make -C samples/network/tls_retro tls_fetch
make -C samples/network/tls_retro clean
- name: Built-in Kerberos client against a MIT KDC
shell: bash
working-directory: ${{ github.workspace }}
run: |
set -eu
# net_krb5.c against krb5kdc on a fixed port: AS with and
# without PA-ENC-TIMESTAMP, TGS for a cifs/ service with the
# ticket checked against the service's keytab key, wrong
# password and unknown service refused.
samples/network/krb5_retro/local_kdc_test.sh
make -C samples/network/krb5_retro clean
CC=x86_64-w64-mingw32-gcc make -C samples/network/krb5_retro krb5_test
make -C samples/network/krb5_retro clean
-107
View File
@@ -1,107 +0,0 @@
name: CI Linux without pkg-config
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
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:
no-pkg-config:
name: Configure and build with pkg-config unavailable
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Install dependencies
shell: bash
run: |
set -eu
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends \
build-essential zlib1g-dev libfreetype-dev libdrm-dev \
libasound2-dev libpulse-dev libpipewire-0.3-dev \
libdbus-1-dev libwayland-dev libwayland-bin libxkbcommon-dev \
libdecor-0-dev libssl-dev qt6-base-dev qt6-base-dev-tools
- name: Checkout
uses: actions/checkout@v5
- name: Configure
shell: bash
run: |
set -eu
# PKG_CONF_PATH=none makes configure behave as it does on a
# system with no pkg-config binary: every check_val falls
# back to a plain link test and takes its cflags from the
# include directories it is given. A library that links but
# whose headers are not on the include path must end up
# disabled, never enabled with empty cflags.
PKG_CONF_PATH=none ./configure --enable-dbus
grep -q '^HAVE_PIPEWIRE = 1' config.mk
grep -q '^HAVE_PIPEWIRE_STABLE = 1' config.mk
grep '^PIPEWIRE_CFLAGS = ' config.mk | grep -q -- '-I/usr/include/pipewire-0.3'
grep '^PIPEWIRE_CFLAGS = ' config.mk | grep -q -- '-I/usr/include/spa-0.2'
# Found without pkg-config: D-Bus by its headers, one of them
# under the library directory; Wayland by its libraries and the
# scanner's own version; Qt through qmake -query.
for have in DBUS WAYLAND WAYLAND_SCANNER LIBDECOR OPENSSL QT QT6; do
grep -q "^HAVE_$have = 1" config.mk \
|| { echo "::error::HAVE_$have not found without pkg-config"; exit 1; }
done
grep '^DBUS_CFLAGS = ' config.mk | grep -q -- '-I/usr/include/dbus-1.0'
grep '^DBUS_CFLAGS = ' config.mk | grep -q -- 'dbus-1.0/include'
- name: Build
shell: bash
run: |
set -eu
make -j"$(nproc)"
test -x ./retroarch
test -f obj-unix/release/audio/drivers/pipewire.o
test -f obj-unix/release/camera/drivers/pipewire.o
test -f obj-unix/release/gfx/common/dbus_common.o
test -f obj-unix/release/gfx/common/wayland_common.o
test -f obj-unix/release/ui/drivers/ui_qt.o
- name: The run-time libdbus mirror matches libdbus
shell: bash
run: |
set -eu
# gfx/common/dbus_runtime.h mirrors libdbus's public structs and
# constants so RetroArch can load it without its headers; the
# D-Bus CFLAGS configure found above lead to the real ones.
make -C samples/frontend/dbus_runtime check \
DBUS_CFLAGS="$(sed -n 's/^DBUS_CFLAGS = //p' config.mk)"
- name: A package forced by name fails when nothing can find it
shell: bash
run: |
set -u
# rsound is found only through pkg-config. Asked for by name with
# no pkg-config, configure must stop and say so rather than
# quietly build without it.
if PKG_CONF_PATH=none ./configure --enable-rsound > forced.log 2>&1; then
cat forced.log
echo "::error::--enable-rsound without pkg-config configured instead of failing"
exit 1
fi
grep -q 'Forced to build with package rsound, but pkg-config was not found' forced.log \
|| { cat forced.log; echo "::error::configure failed for another reason"; exit 1; }
# A forced package with a library check behind it still configures.
PKG_CONF_PATH=none ./configure --enable-pulse > forced.log 2>&1 \
|| { cat forced.log; echo "::error::--enable-pulse failed without pkg-config"; exit 1; }
grep -q '^HAVE_PULSE = 1' config.mk
@@ -1,178 +0,0 @@
name: CI Linux overlay on screen
# The one overlay test that looks at the screen. It builds a real
# retroarch with X11 and OpenGL, runs it under Xvfb on Mesa's software
# rasteriser with an input overlay enabled, threaded video off and then
# on, grabs the screen and checks the overlay is where its config puts
# it and nowhere else. It then checks the menu's mouse cursor with an
# overlay up: a page of "nul" buttons (an LED overlay) must leave the
# cursor to the menu, a page that takes input must not. Last, with the
# overlay LED driver on, it checks that only LED images are hidden and
# that a hidden one stays hidden while its button is held.
#
# Every stubbed overlay test passed while an enabled overlay covered the
# whole screen (2026-09-19). Nothing that stubs the driver, or builds
# the pack by hand, can see that; this can.
on:
push:
branches:
- master
paths:
- 'input/input_driver.c'
- 'input/input_overlay*'
- 'tasks/task_overlay.c'
- 'led/drivers/led_overlay.c'
- 'gfx/gfx_surface.*'
- 'gfx/video_driver.c'
- 'gfx/video_thread_wrapper.*'
- 'gfx/drivers/gl2.c'
- 'menu/menu_driver.c'
- 'input/drivers/x11_input.c'
- 'samples/input/overlay_on_screen/**'
- '.github/workflows/Linux-overlay-on-screen.yml'
pull_request:
paths:
- 'input/input_driver.c'
- 'input/input_overlay*'
- 'tasks/task_overlay.c'
- 'led/drivers/led_overlay.c'
- 'gfx/gfx_surface.*'
- 'gfx/video_driver.c'
- 'gfx/video_thread_wrapper.*'
- 'gfx/drivers/gl2.c'
- 'menu/menu_driver.c'
- 'input/drivers/x11_input.c'
- 'samples/input/overlay_on_screen/**'
- '.github/workflows/Linux-overlay-on-screen.yml'
workflow_dispatch:
permissions:
contents: read
# Only pull requests cancel a superseded run. On master every push
# gets its own group (keyed by the commit), so a burst of pushes queues
# instead of cancelling the run for the commit before it.
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
overlay-on-screen:
name: Run retroarch under Xvfb and look at the overlay
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential zlib1g-dev ccache python3 \
xvfb x11-apps libgl1-mesa-dri \
libx11-dev libx11-xcb-dev libxcb1-dev libxext-dev libxtst6 \
libxxf86vm-dev libxrandr-dev libxinerama-dev \
libgl-dev libegl-dev && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
build-essential zlib1g-dev ccache python3 \
xvfb x11-apps libgl1-mesa-dri \
libx11-dev libx11-xcb-dev libxcb1-dev libxext-dev libxtst6 \
libxxf86vm-dev libxrandr-dev libxinerama-dev \
libgl-dev libegl-dev
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build RetroArch (X11 + OpenGL, the rest off)
shell: bash
run: |
set -eu
# What draws the overlay has to be real: X11, the gl driver,
# the menu, threads. Everything else is build time.
./configure --disable-qt --disable-wayland --disable-sdl \
--disable-sdl2 --disable-ffmpeg --disable-vulkan \
--disable-pulse --disable-discord \
--disable-networking --disable-cheevos \
--disable-glslang --disable-slang \
--disable-spirv_cross --disable-xmb \
--disable-materialui --disable-ozone \
--disable-7zip --disable-flac \
--disable-audiomixer --disable-translate \
--disable-accessibility --disable-crtswitchres \
--disable-langextra --disable-libretrodb \
--disable-video_filter --disable-dsp_filter
make -j$(nproc)
ccache -s
- name: Run overlay_on_screen_test (threaded video off, then on)
shell: bash
run: |
set -eu
# Two solid magenta squares on a full-screen page. Each must
# be where the config puts it, the middle of the screen must
# not be overlay, and the overlay must cover about the area of
# its two squares. With "does this desc have an image" asked
# of pixels that had just been released, no desc's geometry
# was set and the overlay covered 100% of the screen, in both
# modes.
timeout 180 python3 samples/input/overlay_on_screen/overlay_on_screen_test.py ./retroarch
- name: Run overlay_menu_mouse_test (display and input packs, threaded off and on)
shell: bash
run: |
set -eu
# The menu switched its mouse off whenever any overlay was
# alive, so an LED overlay - nothing on it to press - left a
# fullscreen desktop user with no menu cursor. A pack of
# "nul" buttons must now show the cursor where the pointer is
# moved; the same pack bound to "a" must still not.
timeout 180 python3 samples/input/overlay_on_screen/overlay_menu_mouse_test.py ./retroarch
- name: Run overlay_led_hidden_test (mapped and named LED packs, threaded off and on)
shell: bash
run: |
set -eu
# With the overlay LED driver on and Up held through XTEST: an
# image at a ledN_map slot, "nul" or a control, stays hidden,
# as does one named with _led, and a pack that names its LEDs
# is not mapped.
timeout 300 python3 samples/input/overlay_on_screen/overlay_led_hidden_test.py ./retroarch
-108
View File
@@ -1,108 +0,0 @@
name: CI Linux pace shadow [debug harness]
# The pace decision - which sources hold the loop each iteration - is
# one pure function, runloop_pace_decide() in runloop.h, that every
# path of runloop_iterate() defers to. It began life shadowing the
# paths' own scattered decisions with a debug assertion that the two
# agreed; this job was created to run that assertion in CI, and it
# never fired, which is what let the paths defer.
#
# What the job still does: builds with DEBUG=1 under ASan and UBSan,
# so every retro_assert in the wrapper, the ring and the runloop is
# live, and runs the threaded-video harness through it - threaded and
# unthreaded, menu open and closed, display pacing on, the runtime
# toggles - then the pacing sample, whose menu table pins the decision
# row by row. The release harness job cannot see an assertion; this
# one can.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
linux-pace-shadow:
name: Debug build, harness with assertions live
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
# Non-Qt, as the harness requires (with Qt, main() lives in
# ui_qt.o). Menu enabled: the menu lanes are half the point.
run: |
./configure \
--disable-qt \
--disable-discord \
--disable-cheevos \
--disable-networking \
--disable-ffmpeg
- name: Build with DEBUG=1 and -fsanitize=address,undefined
run: |
make -j$(getconf _NPROCESSORS_ONLN) SANITIZER=address,undefined DEBUG=1
- name: Run the threaded-video harness with assertions live
shell: bash
run: |
set -eu
# SAN=address is the harness's default and links exactly the
# build above; CYCLES=2 runs each toggling lane twice.
SAN=address CYCLES=2 make -C samples/gfx/threaded_video check
make -C samples/gfx/threaded_video clean
- name: Run the pacing sample (the menu table)
shell: bash
run: |
set -eu
make -C samples/runloop/pacing check
make -C samples/runloop/pacing clean
-92
View File
@@ -1,92 +0,0 @@
name: CI Linux Qt companion (persistence)
on:
push:
branches:
- master
pull_request:
branches:
- master
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:
qt-companion-persist:
# Builds a Qt-enabled RetroArch with the null video/audio/input
# drivers and runs tools/companion_qt_persist_test.sh: the desktop
# companion's window geometry and dock layout must reach
# retroarch.cfg when RetroArch quits with the companion window still
# open, and a saved layout must restore and re-save identically.
#
# The shader stacks are disabled explicitly: with no OpenGL/Vulkan
# dev packages on the runner this is a Qt build with NO shader stack
# at all, and it links (the shader-preset editor and the companion
# core's shader accessors are compiled out). That is deliberate - it
# is the one configuration the other jobs never build.
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Dependencies
timeout-minutes: 20
run: |
pkgs="build-essential pkg-config zlib1g-dev qt6-base-dev libgl-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
run: |
./configure --enable-qt --disable-x11 --disable-wayland \
--disable-opengl --disable-opengles --disable-vulkan \
--disable-sdl2 --disable-sdl --disable-alsa --disable-pulse \
--disable-ffmpeg --disable-networking --disable-cheevos \
--disable-discord --disable-cdrom --disable-flac --disable-mpv \
--disable-libusb --disable-udev --disable-v4l2 --disable-freetype \
--disable-caca --disable-sixel --disable-microphone --disable-ssl \
--disable-bluetooth --disable-wifi --disable-oss --disable-jack \
--disable-roar --disable-al --disable-xvideo --disable-kms \
--disable-egl --disable-dispmanx --disable-videocore \
--disable-crtswitchres --disable-update_cores --disable-hid \
--disable-dbus --disable-glsl --disable-slang --disable-cg \
--disable-glslang --disable-spirv_cross
- name: Build
run: make -j$(getconf _NPROCESSORS_ONLN)
- name: Companion persistence regression
timeout-minutes: 10
run: tools/companion_qt_persist_test.sh
-958
View File
@@ -1,958 +0,0 @@
name: CI Linux samples/audio
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
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:
samples-audio:
name: Build and run samples/audio
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libasound2-dev libsdl2-dev libopenal-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build and run mixer_lock_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/mixer_lock
run: |
set -eu
# Includes audio/audio_driver.c and drives the mixer's public
# entry points with a real state lock in place. The lock is a
# plain mutex, so any path that reaches a locking entry point
# while already holding it parks the thread against itself;
# loading the first menu sound did exactly that
# (libretro/RetroArch#19485). Every case runs on a watchdog:
# a reintroduced recursive acquisition aborts with a stack
# instead of hanging the job. Also covers the lock being
# released on out-of-range slots and a NULL stream name
# surviving removal.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x mixer_lock_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./mixer_lock_test
echo "[pass] mixer_lock_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 300 ./mixer_lock_test
echo "[pass] mixer_lock_test (TSan)"
- name: Build and run thread_handshake_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/thread_handshake
run: |
set -eu
# Links audio/audio_thread_wrapper.c against a scripted
# driver. The wrapped thread parks in one of two waits and
# the main thread's block() needs stopped_ack from either; a
# stop() landing between start()'s signal and the thread's
# re-check used to leave it in the one wait that never
# acknowledged. Two thousand start/stop round-trips hit that
# window on the previous wrapper on every run. The scripted
# device can also stop returning from a call: a stop must
# then still complete once the call does, and must be
# reported exactly once meanwhile - prompt handshakes are
# asserted not to be reported.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x thread_handshake_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 300 \
./thread_handshake_test
echo "[pass] thread_handshake_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 600 ./thread_handshake_test
echo "[pass] thread_handshake_test (TSan)"
- name: Build and run graph_clock_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/graph_clock
run: |
set -eu
# The two conversions the JACK and PipeWire clock fits add.
# Neither a JACK server nor a PipeWire daemon can be started
# here, so unlike alsa_clock this mirrors the arithmetic
# rather than driving the drivers - a weaker check, said
# plainly, and aimed at the parts where being wrong is
# silent.
#
# JACK's current_frames is 32 bits and wraps in about a day
# at 48 kHz, sooner if the server was up before RetroArch
# started, since the counter is the server's. The difference
# is taken in 32 bits where the wrap cancels; widening first
# turns one wrap into a four-billion-frame jump. A run is
# started two seconds short of the wrap so it goes round
# mid-measurement.
#
# PipeWire's ticks are in units of pw_time.rate, a fraction
# that is 1/samplerate. The same physical drift has to read
# the same ppm at 44.1k and 48k, which is what the fraction
# is there for.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x graph_clock_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./graph_clock_test
echo "[pass] graph_clock_test (ASan)"
- name: Build and run alsa_clock_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/alsa_clock
run: |
set -eu
# The ALSA device-clock estimate, driving the shipping
# audio/drivers/alsa.c on a real PCM opened on the null
# device. The four libasound calls the estimate is built from
# are scripted via --wrap, so a device can be made to run at a
# chosen offset and the driver's own answer read back out of
# what it logs - what is asserted is the line a user sees.
#
# Two clocks are covered. The audio timestamp, where a driver
# counts one, is the DMA or link clock compared straight
# against the system clock and needs neither a rate nor a
# delay. Where there is none - the null PCM reports none, and
# nor do plenty of real devices - the position is fitted
# against the timestamp it was taken with. That position is
# inferred from the write count less the delay, so one case
# puts an absurd but constant delay in: it shifts the line
# and leaves its slope alone, which is why this is a fit and
# not a difference of two samples.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x alsa_clock_test
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./alsa_clock_test
echo "[pass] alsa_clock_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
timeout 60 ./alsa_clock_test
echo "[pass] alsa_clock_test (TSan)"
- name: Build and run alsa_wait_writable_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/alsa_wait_writable
run: |
set -eu
# Links the shipping audio/drivers/alsa.c and interposes the
# five libasound calls alsa_wait_writable() makes via
# -Wl,--wrap, so the devices no stock PCM can produce on
# demand are scripted: a running stream whose poll never
# signals, a prepared stream reporting no space, a start that
# lands in an underrun storm, and wakes that never deliver
# space. Each must return 0 within a bounded lap and wall-time
# budget rather than parking the audio thread; the previous
# wait was an unbounded snd_pcm_wait(-1). The conforming path
# runs end-to-end on the null PCM, and the harness skips
# cleanly if no ALSA configuration is available at all.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x alsa_wait_writable_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./alsa_wait_writable_test
echo "[pass] alsa_wait_writable_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 300 ./alsa_wait_writable_test
echo "[pass] alsa_wait_writable_test (TSan)"
- name: Build and run alsa_lifecycle_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/alsa_lifecycle
run: |
set -eu
# Links the shipping audio/drivers/alsa.c against the null PCM
# and scripts the libasound calls that decide stop/start and
# the blocking write - can_pause, pause, drop, prepare, writei,
# wait, recover - via -Wl,--wrap. alive() must follow stop()
# and start() on a device that can pause, one that cannot, and
# one that says it can and refuses; the blocking write must
# write first, wait only on EAGAIN, and never without a bound.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x alsa_lifecycle_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./alsa_lifecycle_test
echo "[pass] alsa_lifecycle_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 300 ./alsa_lifecycle_test
echo "[pass] alsa_lifecycle_test (TSan)"
- name: Build and run pipeline_stall_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/pipeline_stall
run: |
set -eu
# Includes audio/audio_driver.c and runs the threaded pipeline's
# shipping producer and consumer against a scripted driver whose
# write_raw() path reaches the device without the resampler or
# the arenas. The device is then made to stop taking audio. The
# consumer must take nothing from the ring it cannot deliver and
# report no progress it did not make; the producer must record
# the stall after one bounded wait and drop at once thereafter;
# and both must recover when the device returns. The previous
# consumer took the chunk first, threw it away on finding no
# room, and cleared the stall - the frontend paced at one frame
# per failed pass for as long as the device was stuck.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x pipeline_stall_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 180 \
./pipeline_stall_test
echo "[pass] pipeline_stall_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 400 ./pipeline_stall_test
echo "[pass] pipeline_stall_test (TSan)"
- name: Build and run upmix_test (plain, ASan + UBSan)
shell: bash
working-directory: samples/audio/upmix
run: |
set -eu
# The stereo-to-wider stage at the last step before a device
# opened with a wider speaker layout. A layout is a mask of
# positions in ascending bit order, never a count: 5.1 with
# the rear pair at the back and 5.1 with it at the sides are
# two layouts whose slots differ. The fronts carry the stereo
# unchanged, the rear pair -3 dB in its own slots, the centre
# the -6 dB sum, the LFE the bass through a 120 Hz low-pass and
# none of the treble; stereo is a copy; a mask the stage
# cannot fill is refused.
make clean && make -j$(nproc) all
./upmix_test
echo "[pass] upmix_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./upmix_test
echo "[pass] upmix_test (ASan)"
- name: Build and run discrete_multichannel_test (plain, ASan + UBSan)
shell: bash
working-directory: samples/audio/discrete_multichannel
run: |
set -eu
# A core's 5.1 through the multi-channel batch entry to a 5.1
# device without the fold and the upmix in between: each
# device channel carries its core channel's tone and none of
# the others', in all four format pairings, through the
# resampler off unity; over the threaded ring; recorded; and
# to a stereo device, the fold at the BS.775 gains with the
# LFE dropped. The last case runs the shipping WASAPI driver
# over the fake device from wasapi_exclusive_pacing, so a
# 5.1 core reaches a Dolby Digital decoder as AC-3 bursts
# that decode back to its own channels. Includes the
# shipping audio_driver.c.
make clean && make -j$(nproc) all
./discrete_multichannel_test
echo "[pass] discrete_multichannel_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./discrete_multichannel_test
echo "[pass] discrete_multichannel_test (ASan)"
- name: Build and run embedded_alsa_test (the embedded ALSA driver, mock kernel device)
shell: bash
working-directory: samples/audio/embedded_alsa
run: |
set -eu
# The "tinyalsa" driver in audio/drivers/alsa.c talks the
# kernel PCM ioctls directly. abi_check compares its copy of
# that ABI - extracted from the driver itself, so it cannot
# go stale - against <sound/asound.h>: every struct size and
# offset, constant and ioctl number. The test then runs the
# driver against a mock device that refines parameters the
# way the kernel does.
make clean && make -j$(nproc) check
echo "[pass] embedded_alsa_test"
make clean && make -j$(nproc) check SANITIZER=address,undefined
echo "[pass] embedded_alsa_test (ASan)"
- name: Build and run ealsa_test (the embedded ALSA driver against a mock PCM device)
shell: bash
working-directory: samples/audio/ealsa
run: |
set -eu
# The embedded driver in audio/drivers/alsa.c talks to the
# kernel's PCM ABI through one seam - open, ioctl, close,
# poll - so a scripted device that answers the way a card
# does runs it with no card present, and can refuse a rate, a
# format, a channel count or a period grid, which is where a
# negotiation goes wrong. Built with HAVE_TINYALSA alone, so
# the build never sees an alsa-lib header either. It also
# carries what tinyalsa_write_test used to check of the
# driver this one replaced: a full device refusing in both
# modes, a device that never signals, a poll cut short by a
# signal, and the first write reporting what it took.
make clean && make -j$(nproc) all
./ealsa_test
echo "[pass] ealsa_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./ealsa_test
echo "[pass] ealsa_test (ASan)"
- name: Build and run bitstream_test (plain, ASan + UBSan)
shell: bash
working-directory: samples/audio/bitstream
run: |
set -eu
sudo apt-get update -qq
sudo apt-get install -y -qq ffmpeg
# audio/audio_bitstream.c: a coded stream on its way to a
# receiver, which the PCM pipeline has no place for. Real
# DTS and AC-3 from ffmpeg, handed over frame by frame:
# bursts leave whole and never partial, the queue paces the
# source rather than the source running ahead, a gap
# produces the pause burst the standard has for it rather
# than silence (which makes a receiver drop its lock), and
# the PCM frames reported are the device time the bytes
# occupy.
make clean && make -j$(nproc) all
./bitstream_test
echo "[pass] bitstream_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./bitstream_test
echo "[pass] bitstream_test (ASan)"
- name: Build and run opensl_test (the Android driver against a mock OpenSL player)
shell: bash
working-directory: samples/audio/opensl
run: |
set -eu
# audio/drivers/opensl.c is Android-only and has no build
# here, so it is built against stand-in <SLES/*.h> over a
# scripted player whose queue a thread drains: the block
# arithmetic at the latencies of issue #6405 and below, the
# queue accounting the hang there came from, float and
# 16-bit, a full queue, and a device that stops consuming.
make clean && make -j$(nproc) all
./opensl_test
echo "[pass] opensl_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./opensl_test
echo "[pass] opensl_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 ./opensl_test
echo "[pass] opensl_test (TSan)"
- name: Build and run qsa_test (the QNX driver against a mock QSA device)
shell: bash
working-directory: samples/audio/qsa
run: |
set -eu
# audio/drivers/alsa_qsa.c is QNX-only and has no build here,
# so it is built against a stand-in <sys/asoundlib.h> over a
# scripted device: init and its failure path, the rate it
# reports back, blocking and non-blocking writes, stop and
# start, underrun recovery, and a device that stops draining.
# Not a substitute for a QNX build; it is the coverage the
# driver had none of.
make clean && make -j$(nproc) all
./qsa_test
echo "[pass] qsa_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./qsa_test
echo "[pass] qsa_test (ASan)"
- name: Build and run live_drivers_test (a live PulseAudio server, a null ALSA PCM)
shell: bash
working-directory: samples/audio/live_drivers
run: |
set -eu
sudo apt-get update -qq
sudo apt-get install -y -qq libasound2-dev libpulse-dev pulseaudio
# A server with a null sink, and an ALSA config naming a null
# PCM: the real drivers against the real libraries, no
# hardware. Pulse's telemetry is cached from the server
# thread's callbacks; ALSA is run once as the device reports
# itself and once told it cannot pause, the fallback from
# snd_pcm_pause to snd_pcm_drop.
export XDG_RUNTIME_DIR=/tmp/xdg
mkdir -p "$XDG_RUNTIME_DIR/pulse"
printf 'pcm.nullpcm { type null }\n' > "$HOME/.asoundrc"
pulseaudio --daemonize=no --exit-idle-time=-1 --disallow-exit -n \
-L "module-null-sink sink_name=nullsink rate=48000 channels=2" \
-L "module-native-protocol-unix auth-anonymous=1 socket=$XDG_RUNTIME_DIR/pulse/native" \
--log-target=file:/tmp/pa.log &
PA_PID=$!
sleep 3
make clean && make -j$(nproc) all
./live_drivers_test
echo "[pass] live_drivers_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./live_drivers_test
echo "[pass] live_drivers_test (ASan)"
kill $PA_PID || true
- name: Build and run binaural_test (plain, ASan + UBSan)
shell: bash
working-directory: samples/audio/binaural
run: |
set -eu
# A layout rendered to two ears for headphones: a left speaker
# arrives at the left ear first, louder and brighter; the rear
# pair duller than the front; centre and LFE alike to both
# ears; a centred source keeps its level and a full-scale one
# leaves at full scale; the two 5.1s render their rear pair
# from different directions; stereo is a mild crossfeed.
make clean && make -j$(nproc) all
./binaural_test
echo "[pass] binaural_test"
make clean && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./binaural_test
echo "[pass] binaural_test (ASan)"
- name: Build and run pipeline_rate_control_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/pipeline_rate_control
run: |
set -eu
# Includes audio/audio_driver.c and runs the threaded pipeline's
# shipping producer, consumer and rate controller against a
# device whose 8 ms buffer drains at exactly 48000 frames a
# second of wall-clock time, fed one 800-frame video frame every
# 1/60 s on an absolute schedule, audio sync off. The clocks
# match, so the right ratio is 1.0: after a four-second settle
# the mean rate adjustment over three seconds must be within
# 500 ppm of it, and the device must have taken 99.5% of what
# was produced. Rate control on the pipeline samples pipe and
# device together, at the producer; reading the device alone,
# which the consumer holds between half and full, pins the
# ratio at a bound and the pipe overflows behind it. Real time,
# so a loaded runner can shift the mean; the tolerance is ten
# times the settled residual.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x pipeline_rate_control_test
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./pipeline_rate_control_test
echo "[pass] pipeline_rate_control_test (ASan)"
# A core late by 60 ms every 2 s, audio sync off: the silence is
# the stalls' own and no more, the late audio is not kept, and
# rate control is not pinned against a backlog. And with sync on:
# the writer waits, nothing is dropped.
ASAN_OPTIONS=detect_leaks=0 timeout 120 ./pipeline_rate_control_test 12 4 jitter
ASAN_OPTIONS=detect_leaks=0 timeout 120 ./pipeline_rate_control_test 12 4 sync-jitter
echo "[pass] pipeline_rate_control_test (late core, ASan)"
# The 64 ms default buffer, sync off, a steady core and a late one:
# the consumer's chunks are whole publishes and the pipe's fill
# swings by one with the phase; nothing is dropped from a steady
# core at any phase.
ASAN_OPTIONS=detect_leaks=0 timeout 120 ./pipeline_rate_control_test 16 4 big
ASAN_OPTIONS=detect_leaks=0 timeout 120 ./pipeline_rate_control_test 16 4 big-jitter
echo "[pass] pipeline_rate_control_test (64 ms device, ASan)"
# The producer held 4 ms every five seconds, as a loaded runner
# holds it: a publish pushed across a sink window boundary. The
# estimate must settle and apply about zero, not the shift.
ASAN_OPTIONS=detect_leaks=0 timeout 120 ./pipeline_rate_control_test 16 4 big-stall
echo "[pass] pipeline_rate_control_test (stalled producer, ASan)"
# A float core on a float ring into a float device: a signal a
# tenth of an int16 LSB high arrives as published, not as zero.
ASAN_OPTIONS=detect_leaks=0 timeout 120 ./pipeline_rate_control_test 16 4 float
echo "[pass] pipeline_rate_control_test (float core, ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 240 ./pipeline_rate_control_test
echo "[pass] pipeline_rate_control_test (TSan)"
- name: Build and run resampler_reset_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/resampler_reset
run: |
set -eu
# Every resampler backend's reset(): after it the stream
# continues as a freshly initialised backend would, to the
# sample, at the ratios the frontend meets - and the reset
# makes no allocation, counted through wrapped malloc, calloc
# and memalign_alloc.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x resampler_reset_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 ./resampler_reset_test
echo "[pass] resampler_reset_test (ASan)"
- name: Build and run ff_speedup_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/ff_speedup
run: |
set -eu
# Includes audio/audio_driver.c with the clock replaced by a
# counter. The fast-forward speedup multiplier must follow the
# core's cadence on both pipelines: measured at the flush inline,
# and by the producer at its publish cadence on the threaded
# pipeline, where the consumer's own flush interval is the device
# draining the previous chunk and would only confirm the previous
# multiplier. Re-entry after an idle spell must start from unity
# rather than read the idle time as one flush interval.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x ff_speedup_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 120 ./ff_speedup_test
echo "[pass] ff_speedup_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./ff_speedup_test
echo "[pass] ff_speedup_test (TSan)"
- name: Build and run device_list_driver_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/device_list_driver
run: |
set -eu
# Includes audio/audio_driver.c with the alsa and null drivers in
# the table. Picking a driver in the menu writes the setting but
# does not reinitialise audio, and the Device list - rebuilt on
# each open - was asked of the running driver, so it showed the
# old driver's devices under the new driver's name until a
# restart. The list now comes from the configured driver, and
# is freed by the driver that built it. Cases: configured and
# running agree; configured differs from running; back again;
# nothing running; and release by the builder, once.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x device_list_driver_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./device_list_driver_test
echo "[pass] device_list_driver_test (ASan)"
- name: Build and run device_label_path_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/device_label_path
run: |
set -eu
# A device list entry with the hardware's name after the path,
# "/dev/dsp0 (HDA Intel)", is stored by the menu as shown and
# comes back to init as the device string; oss opened it as a
# path and failed, so a device picked from the list could not
# be used. Compiles oss and audioio whole with open() redirected
# to a recorder, and checks each reaches it with the path.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x device_label_path_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./device_label_path_test
echo "[pass] device_label_path_test (ASan)"
- name: Build and run rate_control_bounds_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/rate_control_bounds
run: |
set -eu
# Includes audio/audio_driver.c and runs the rate control's
# shipping computation against a scripted driver. At the
# setpoint, empty and full it must give 1.0 and the band's two
# edges; with write_avail() reporting five times buffer_size()
# it must give the upper edge and no more. Before the clamp an
# over-reporting driver drove it nine times past the band.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x rate_control_bounds_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./rate_control_bounds_test
echo "[pass] rate_control_bounds_test (ASan)"
- name: Build and run latency_contract_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/audio/latency_contract
run: |
set -eu
# Real drivers on backends that need no hardware - the ALSA null
# PCM, SDL's dummy audio, OpenAL Soft's null device - opened at
# 64 and 32 ms and checked against audio_driver.h's contract:
# buffer_size() is the setting in bytes of the output format,
# write_avail() never exceeds it, a buffer's worth offered takes
# room, and the room comes back as the device plays. The sdl
# driver before fdda5f7 reports 42.7 ms against 64 here.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x latency_contract_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./latency_contract_test
echo "[pass] latency_contract_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1:suppressions=$PWD/tsan.supp \
timeout 300 ./latency_contract_test
echo "[pass] latency_contract_test (TSan)"
- name: Build and run asio_convert_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/asio_convert
run: |
set -eu
# audio/drivers/asio_convert.h is the ASIO driver's sample
# conversion, pure C, so it runs here without Windows. Every
# ASIOSampleType the specification defines is converted for full
# scale, zero, half and one 16-bit step in both signs and checked
# byte for byte against the layout the specification gives - the
# Int32LSB16..24 family as low-aligned, sign-extended words, the
# MSB types big-endian. Saturation and the silence fill past the
# supplied frames are checked too. The converter this replaced
# wrote five types and memset the rest to silence.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x asio_convert_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./asio_convert_test
echo "[pass] asio_convert_test (ASan)"
- name: Build and run coreaudio_clock_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/coreaudio_clock
run: |
set -eu
# The device clock fitted from the timestamp the render
# callback is handed, which the driver used to discard.
#
# The fit is the same shape as the ASIO one and is checked
# there. What is different is the time axis: mHostTime is in
# mach absolute units, not nanoseconds, and the ratio is one
# to one on Intel and 125 to 3 on Apple silicon. Ignoring it
# reads a 48 kHz device as 1152 Hz - invisible on Intel and
# wrong on every Mac since 2020 - so the same clock is driven
# through both timebases here.
#
# Also mRateScalar, which is the HAL's own figure for the
# same thing, read only where it is flagged valid.
#
# Arithmetic only, so it runs here without a Mac.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x coreaudio_clock_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./coreaudio_clock_test
echo "[pass] coreaudio_clock_test (ASan)"
- name: Build and run coreaudio_ring_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/coreaudio_ring
run: |
set -eu
# The CoreAudio ring keeps a frame's channels together. Its
# capacity is the sample count rounded up to a power of two,
# which for six channels is not a whole number of frames, so
# the cursors wrap mid-frame - and that does not matter,
# because a FIFO returns samples in the order they went in
# wherever they sit. This runs the traffic for every layout,
# then forces every transfer across the wrap, to keep that
# answer honest rather than assumed.
#
# What does rotate the channels is a transfer whose count is
# not a whole number of frames, which is why the callback
# trims short reads. The last case does that on purpose and
# fails if it goes unnoticed, so the trim has a guard.
#
# Arithmetic only, so it runs here without a Mac.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x coreaudio_ring_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./coreaudio_ring_test
echo "[pass] coreaudio_ring_test (ASan)"
- name: Build and run asio_clock_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/asio_clock
run: |
set -eu
# The device clock read from the driver's own time
# information, rather than from when its callbacks arrived.
#
# Two things here do not need an interface. The ASIOTime
# layout is an ABI: the sample position and system time are
# 64-bit values the SDK splits into 32-bit halves on Windows,
# and getting that wrong does not fail to build, it reads a
# driver's numbers as garbage in a real-time callback. The
# offsets are asserted against the SDK's, and asio.c carries
# the same assertions for the compiler that sees the real
# Windows ABI.
#
# And the estimate itself: a clock at a known offset is fed
# in with scheduling jitter on the timestamps, and the answer
# has to be the clock. A two-point estimate fails that - the
# anchor's own noise divided by the window reads as drift,
# 50 ppm for half a millisecond at ten seconds - which is why
# it is a least-squares fit over every callback instead.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x asio_clock_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./asio_clock_test
echo "[pass] asio_clock_test (ASan)"
- name: Build and run asio_ring_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/asio_ring
run: |
set -eu
# Also the write's frame alignment: the callback reads the
# ring a frame at a time, so a write must end on one, and
# the rule is checked for every layout the driver can open.
#
# audio/drivers/asio_ring.h sizes the ring in front of the ASIO
# device: the latency setting less the device's reported stage,
# floored at four periods where that is under 6 ms, 6 ms where it
# is over, two periods at the least. Arithmetic only, so it runs
# here without Windows. The expected frames are worked by hand
# from those rules for the devices that set them - ASIO4ALL at 64
# frames, a wrapper locked at 528, a USB DAC at 8 and 128 - and
# the two points where the rules meet.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x asio_ring_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./asio_ring_test
echo "[pass] asio_ring_test (ASan)"
- name: Build and run dsound_pump_test (MinGW, under wine)
shell: bash
working-directory: samples/audio/dsound_pump
run: |
set -eu
# audio/drivers/dsound.c end to end on wine's DirectSound, fed
# by an ALSA null PCM, which plays at real-time pace on a
# runner with no sound card. Pins that the pump - which now
# waits for the play cursor to move the distance it needs,
# worked out from the rate, instead of retrying every
# millisecond - still moves audio through blocking writes,
# fills silence when the writer stops, and lets free() return
# at once while it waits.
if ! command -v x86_64-w64-mingw32-gcc >/dev/null 2>&1 \
|| ! command -v wine >/dev/null 2>&1; then
sudo apt-get install -y -qq gcc-mingw-w64-x86-64 wine64 \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30
fi
printf 'pcm.!default { type null }\nctl.!default { type hw card 0 }\n' > ~/.asoundrc
make clean all
WINEDEBUG=-all timeout 300 make check
echo "[pass] dsound_pump_test (wine)"
- name: Build and run wdmks_loop_test (MinGW, under wine)
shell: bash
working-directory: samples/audio/wdmks_loop
run: |
set -eu
# audio/drivers/wdmks.c compiled whole, its WaveRT loop driven
# by hand: the test owns the driver's state, points the
# position register at a word of its own and moves the
# hardware itself, so nothing reaches the kernel and wine
# needs no sound card. Pins that every byte the cursor passes
# is cleared, so the loop plays silence when the frontend
# stops writing - a pause, a menu, a stall - instead of the
# last loop of audio round and round; that a write after
# that lands a margin ahead of the hardware rather than a
# loop behind it; that a full loop is not taken for an
# overrun; and that a start puts the model back at the top
# of the loop with the hardware; and that the resync margin is
# the FIFO the pin reports plus half a millisecond, two
# milliseconds where it reports none; and that gaps in the
# audio are counted once each, neither a start nor every
# sample of a pause.
if ! command -v x86_64-w64-mingw32-gcc >/dev/null 2>&1 \
|| ! command -v wine >/dev/null 2>&1; then
sudo apt-get install -y -qq gcc-mingw-w64-x86-64 wine64 \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30
fi
make clean all
WINEDEBUG=-all timeout 120 make check
echo "[pass] wdmks_loop_test (wine)"
- name: Build and run wasapi_exclusive_pacing_test (ASan + UBSan, then TSan)
shell: bash
working-directory: samples/audio/wasapi_exclusive_pacing
run: |
set -eu
# audio/drivers/wasapi.c, unmodified but for its Windows include
# lines, against a fake device on a real-time clock: exclusive
# and event-driven, one period per endpoint buffer, every period
# taken or counted unanswered. The writer is a frontend with audio
# sync off: one frame of core audio per non-blocking write, no rate
# control. Passes when no period goes unanswered in either mode and
# nothing is dropped once the buffer holds a frame. Before the pump
# thread and the drain-first shared write this run gave 3-10% of
# periods unanswered; the first smaller-period attempt without the
# pump gave 75%.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x wasapi_exclusive_pacing_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 120 \
./wasapi_exclusive_pacing_test 3
echo "[pass] wasapi_exclusive_pacing_test (ASan)"
make clean && make -j$(nproc) all SANITIZER=thread
timeout 180 ./wasapi_exclusive_pacing_test 3
echo "[pass] wasapi_exclusive_pacing_test (TSan)"
- name: Build and run sink_rate_test (ASan + UBSan)
shell: bash
working-directory: samples/audio/sink_rate
run: |
set -eu
# The frontend's sink rate estimator against a scripted driver
# on a synthetic clock: a device 120 ppm fast and 80 ppm slow are
# measured and the resampling bias converges onto them; 5000 ppm
# stops at the clamp; with rate control on the bias absorbs rate
# control's mean adjustment; a paused window, a count that went
# backwards, and a stalled window move nothing; disabled, nothing
# moves at all.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x sink_rate_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 ./sink_rate_test
echo "[pass] sink_rate_test (ASan)"
- name: Build and run pacing_test (ASan + UBSan)
shell: bash
working-directory: samples/runloop/pacing
run: |
set -eu
# The three pacing decisions the runloop makes every
# iteration, run from runloop.h so this is the shipping code
# rather than a copy of it. The gap limiter over all 128
# combinations of the pace bits by nonblocking by fastmotion -
# exactly one may engage, because engaging next to another
# source double-paces and engaging under fast-forward
# throttles it to 1x, and both look like performance bugs
# rather than pacing bugs. The frame period over the rates a
# core can report including zero and a million, bounded and
# monotonic. And the filter on the measured loop rate, which
# has to reject a stall: one 0.9 s sample used to pull a 60
# fps reading to 8 and take several frames to recover.
make clean && make -j$(nproc) all SANITIZER=address,undefined
test -x pacing_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 timeout 60 ./pacing_test
echo "[pass] pacing_test (ASan)"
- name: Build the ALSA objects through configure (--enable-alsa)
shell: bash
run: |
set -eu
# The harnesses above compile audio/drivers/alsa.c with
# -DHAVE_ALSA on the command line. A distribution build takes
# HAVE_ALSA from config.h instead, and the file gates its
# alsa-lib includes on it, so build the objects that way too:
# configure with ALSA on, then compile them. That covers the
# object a distribution ships as well as the ones the
# harnesses build (libretro/RetroArch#19525). The embedded
# driver takes its define the same way and shares the file,
# so the arrangements below cover it too.
./configure --enable-alsa --disable-qt --disable-ffmpeg \
--disable-x11 --disable-wayland
grep -q '^HAVE_ALSA = 1' config.mk
make obj-unix/release/audio/drivers/alsa.o \
obj-unix/release/audio/common/alsa.o
echo "[pass] alsa-lib alone, through configure"
# The embedded driver is in the same file behind its own
# define, and configure puts HAVE_TINYALSA in config.h as
# well as on the command line - so it has the same question
# to answer as HAVE_ALSA did, and one object serves both
# drivers. The two arrangements a distribution can ask for:
# the embedded driver with no alsa-lib anywhere, and both in
# the one object.
rm -f obj-unix/release/audio/drivers/alsa.o
./configure --enable-tinyalsa --disable-alsa --disable-qt \
--disable-ffmpeg --disable-x11 --disable-wayland
grep -q '^HAVE_TINYALSA = 1' config.mk
grep -q '^HAVE_ALSA = 0' config.mk
make obj-unix/release/audio/drivers/alsa.o
echo "[pass] the embedded driver alone, through configure"
rm -f obj-unix/release/audio/drivers/alsa.o \
obj-unix/release/audio/common/alsa.o
./configure --enable-alsa --enable-tinyalsa --disable-qt \
--disable-ffmpeg --disable-x11 --disable-wayland
grep -q '^HAVE_TINYALSA = 1' config.mk
grep -q '^HAVE_ALSA = 1' config.mk
make obj-unix/release/audio/drivers/alsa.o \
obj-unix/release/audio/common/alsa.o
echo "[pass] both drivers in the one object, through configure"
- name: Build and run stretch and native SRC chain (C89, ASan + UBSan)
working-directory: samples/audio/stretch
run: |
make -j$(nproc) check SANITIZER=address,undefined
- name: Build and run WSOLA kernel tests (C89, ASan + UBSan)
working-directory: samples/audio/wsola_search
run: |
make -j$(nproc) check SANITIZER=address,undefined
- name: Build and run native speed LPF tests (C89, ASan + UBSan)
working-directory: samples/audio/speed_lpf
run: make check SANITIZER=address,undefined
- name: Build and run experimental sinc HQ tests (C89, ASan + UBSan)
working-directory: samples/audio/sinc_hq
run: |
make -j$(nproc) check SANITIZER=address,undefined
- name: Build and run sinc AVX tests (C89, ASan + UBSan)
working-directory: samples/audio/sinc_hq
run: |
if grep -qw avx /proc/cpuinfo; then
make clean
make -j$(nproc) check CC="gcc -mavx" SANITIZER=address,undefined
else
echo "AVX unavailable on this runner; scalar/SSE tests ran above."
fi
- name: Build and run extra-channel capacity test (ASan + UBSan)
working-directory: samples/audio/extra_capacity
run: |
make -j$(nproc) check SANITIZER=address,undefined
make clean
make -j$(nproc) check SIMD_MASK=RESAMPLER_SIMD_SSE SANITIZER=address,undefined
- name: Build and run resampler option tests (C89, ASan + UBSan)
working-directory: samples/audio/resampler_options
run: |
make -j$(nproc) check SANITIZER=address,undefined
-187
View File
@@ -1,187 +0,0 @@
name: CI Linux samples/cores
on:
push:
branches:
- master
paths:
- 'cores/libretro-ffmpeg/**'
- 'libretro-common/queues/**'
- 'libretro-common/include/retro_spsc.h'
- 'libretro-common/include/retro_atomic.h'
- 'samples/cores/**'
- '.github/workflows/Linux-samples-cores.yml'
pull_request:
branches:
- master
paths:
- 'cores/libretro-ffmpeg/**'
- 'libretro-common/queues/**'
- 'libretro-common/include/retro_spsc.h'
- 'libretro-common/include/retro_atomic.h'
- 'samples/cores/**'
- '.github/workflows/Linux-samples-cores.yml'
workflow_dispatch:
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:
samples-cores:
name: Build and run samples/cores
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential pkg-config ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build and run camera ffmpeg_live_test (plain, ASan + UBSan, TSan)
shell: bash
working-directory: samples/camera/ffmpeg_live
run: |
set -eu
sudo apt-get update -qq
sudo apt-get install -y -qq libavdevice-dev libavfilter-dev
# The camera driver against lavfi: built with its input
# format set to libavfilter, a filter graph is the device and
# the whole pipeline runs with no camera attached - avformat
# opens the source, the poll thread reads, the decoder
# decodes, swscale converts and poll() takes the frame out
# under the buffer's lock.
#
# The cases are the ones the threading has to get right and
# that no eyeball on a webcam would show: start and stop
# repeatedly, stop while the thread is mid-frame, free
# without stopping, poll before starting, and a source that
# does not exist.
make clean all
./ffmpeg_live_test
echo "[pass] ffmpeg_live_test"
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 600 ./ffmpeg_live_test
echo "[pass] ffmpeg_live_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1:suppressions=../../cores/ffmpeg_audio_pipe/tsan.supp \
timeout 600 ./ffmpeg_live_test
echo "[pass] ffmpeg_live_test (TSan)"
- name: Build and run ffmpeg_sweep_test (plain, ASan + UBSan, TSan)
shell: bash
working-directory: samples/cores/ffmpeg_sweep
run: |
set -eu
# Breadth where ffmpeg_audio_pipe_test has depth: eight clips
# across containers, video and audio codecs, rates, channel
# counts and the one-sided cases, each loaded, run, seeked
# both ways, reset and unloaded in one process - so the
# second load is what finds what the first unload left
# behind - then files that are truncated, stubbed, noise,
# empty or absent, then teardown while the decode thread is
# still working.
#
# Leak detection off: libavutil's HW-device probing keeps a
# few objects, as the audio-pipe lane already has it. The
# libav* TSan suppressions are the same ones and for the
# same reason.
make clean all
./ffmpeg_sweep_test
echo "[pass] ffmpeg_sweep_test"
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 900 ./ffmpeg_sweep_test
echo "[pass] ffmpeg_sweep_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1:suppressions=../ffmpeg_audio_pipe/tsan.supp \
timeout 900 ./ffmpeg_sweep_test
echo "[pass] ffmpeg_sweep_test (TSan)"
- name: Build and run ffmpeg_audio_pipe_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/cores/ffmpeg_audio_pipe
run: |
set -eu
# cores/libretro-ffmpeg/ffmpeg_core.c as a libretro host would
# drive it: a generated clip (tone under a test pattern), 5 s
# of frames checked for the audio frame count and a tone in
# every batch, then R1/L1 seeks both ways - the decode-thread
# / main-thread handshake around the audio ring - and a
# teardown mid-stream, all on a watchdog. Needs the ffmpeg
# CLI to generate the clip. Leak detection off: libavutil's
# own HW-device probing allocates and keeps a few objects.
make clean all SANITIZER=address,undefined
test -x ffmpeg_audio_pipe_test
ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 300 \
./ffmpeg_audio_pipe_test
echo "[pass] ffmpeg_audio_pipe_test (ASan)"
make clean all SANITIZER=thread
# The libav* libraries are uninstrumented, so TSan cannot see
# the atomics that order an AVBufferRef's reference count and
# reports the allocation and the release as a race. Only
# those libraries are suppressed; a race in the core's own
# code is still reported.
TSAN_OPTIONS=halt_on_error=1:suppressions=tsan.supp \
timeout 300 ./ffmpeg_audio_pipe_test
echo "[pass] ffmpeg_audio_pipe_test (TSan)"
+3 -157
View File
@@ -15,10 +15,6 @@ permissions:
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:
samples-formats:
name: Build and run samples/formats
@@ -27,97 +23,12 @@ jobs:
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential ffmpeg"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
sudo apt-get update -y
sudo apt-get install -y build-essential
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build and run dts_lpcm_test (plain, ASan + UBSan)
shell: bash
working-directory: samples/formats/dts_lpcm
run: |
set -eu
# The DTS frame layer and the LPCM codec against ffmpeg.
#
# rdts reads frames, it does not decode them, so what is
# checked is that every frame is found where ffmpeg's
# encoder put it, that the rate and the arrangement agree
# with ffprobe's reading of the same file, and that a stream
# byte-swapped or packed fourteen bits to the word reads
# back to the same core - which is what a receiver and a
# decoder are handed.
#
# rlpcm does decode, and is bit-exact: the samples go out
# through ffmpeg's own converters and come back the same, at
# 16 and 24 bits and both byte orders, and what rlpcm writes
# back is the bytes it read. 20-bit has no ffmpeg format to
# compare against - two samples to five bytes is a disc
# packing - so it is checked against itself, and the DVD and
# Blu-ray headers against their field layouts. The
# audio_transfer arm is driven too: chunked reads against
# the codec's own output, the compressed frontier, and
# seeks, which for constant-size frames land exactly.
#
# And the pass-through route, which is what a format with no
# decoder is for: every frame repacked to the plain core,
# put in the IEC 61937 burst its sample count calls for, and
# read back out of that burst byte for byte.
make clean all
./dts_lpcm_test
echo "[pass] dts_lpcm_test"
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./dts_lpcm_test
echo "[pass] dts_lpcm_test (ASan)"
uses: actions/checkout@v3
- name: Build and run image_decode_fuzz_test (ASan + UBSan + LSan)
shell: bash
@@ -157,68 +68,3 @@ jobs:
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 \
timeout 120 ./image_decode_fuzz_test
echo "[pass] image_decode_fuzz_test"
- name: Build and run image_avail_test (ASan + UBSan + LSan)
shell: bash
working-directory: samples/formats/image_avail
run: |
set -eu
# Partial-buffer ("avail-aware") still decoding for TGA and
# BMP, checked
# against the whole-buffer decode that has always been
# there: every fixture is decoded once with the file fully
# resident and again with the frontier raised a few bytes at
# a time, and the two surfaces must be bit-identical.
#
# The oracle is the decoder itself, so this catches the
# failures that do not crash: a wall mistaken for EOF (the
# decode pads the rest of the surface and reports success),
# an RLE run re-emitted after a stall, a cursor resumed off
# by a pixel. It found all three of those on its first runs
# while TGA was being converted.
#
# BMP rows are bottom-up, so a prefix of the file is the
# bottom of the image and a stall resumed on the wrong row
# shows up as a vertically displaced surface rather than as
# noise. The 4bpp and 8bpp fixtures put the wall inside the
# palette as well.
#
# Steps of 1, 3 and 7 bytes put the wall inside every field,
# inside RLE packets and mid-pixel for both 24bpp and 32bpp;
# 1024 is a realistic read granularity. A truncated file
# must still settle rather than wait forever, which is the
# one case where stopping at the frontier and stopping at
# the end of the data have to be told apart.
#
# One set of checks replays task_image's real call sequence
# rather than an order this test invented - set_buffer_ptr,
# then set_avail BEFORE each process(), then set_avail
# ((size_t)-1) the instant the read completes, which for a
# small file is before any process() has run - at four read
# granularities. Inventing the order instead of replaying
# it is exactly how the blank-BMP/TGA-thumbnail regression
# got past this file: every other check here raised the
# frontier only after the first process() call.
#
# One set of checks drives every avail-aware still decoder -
# PNG and JPEG as well as TGA and BMP - through the
# image_transfer facade in task_image's order. PNG, JPEG,
# WEBM and MP4 clamp the requested frontier in the size
# domain because their set_buf_ptr is given the buffer
# length; rtga's and rbmp's are not, which is why those two
# were the only ones that could turn (size_t)-1 into a
# wrapped pointer, and did. A sixth avail-aware decoder
# inherits whichever shape it copies, so the check lives
# here rather than in anyone's memory.
#
# It also checks header_ready, the gate the task layer uses
# to start a decode early, against the decoder itself: every
# prefix it accepts must be one the decoder can actually
# begin on, it must accept before the whole file has arrived
# (or partial decoding is silently off), and it must be
# monotonic in the prefix length.
make clean all SANITIZER=address,undefined
test -x image_avail_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 \
timeout 120 ./image_avail_test
echo "[pass] image_avail_test"
File diff suppressed because it is too large. Load diff
-269
View File
@@ -1,269 +0,0 @@
name: CI Linux samples/input
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
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:
samples-input:
name: Build and run samples/input
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libusb-1.0-0-dev libx11-dev libxtst-dev libxi-dev xvfb gcc-mingw-w64-x86-64 wine64"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: X11 input poll sends no requests (Xvfb, ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/x11_input_poll
run: |
set -eu
# The X input driver's poll runs every frame. Keys, and with
# XInput 2 the pointer, come from events on the driver's own
# connection, drained at the poll, so it sends no request on
# either connection; a query on the shared one waits behind
# whatever the video thread presents through it. XTEST drives
# the keyboard (held before init, auto-repeat, focus changes,
# another client's keyboard grab) and the pointer (a press
# without motion, buttons 1, 3 and 8, the wheel, a drag out of
# the window, a new driver over a held button, and grabbed
# motion across a warp the server holds back behind a server
# grab - where any wait on the server would hang the test).
Xvfb :96 -screen 0 1024x768x24 > /tmp/xvfb96.log 2>&1 &
XVFB_PID=$!
sleep 1
make clean all SANITIZER=address,undefined
DISPLAY=:96 ASAN_OPTIONS=detect_leaks=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 120 ./x11_input_poll_test
make clean all SANITIZER=thread
DISPLAY=:96 TSAN_OPTIONS=halt_on_error=1 timeout 120 ./x11_input_poll_test
make clean
kill $XVFB_PID
echo "[pass] x11_input_poll_test (ASan, TSan)"
- name: Build and run illuminance_sensor_test (ASan + UBSan)
shell: bash
working-directory: samples/input/illuminance_sensor
run: |
set -eu
# The Linux IIO illuminance sensor poller, against a fake
# sysfs tree under /tmp. Pins that the poll thread waits on a
# condition between readings rather than sleeping: a raised
# rate applies at once, and close returns without waiting out
# the period.
make clean all SANITIZER=address,undefined
test -x illuminance_sensor_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./illuminance_sensor_test
echo "[pass] illuminance_sensor_test (ASan)"
- name: Build and run illuminance_sensor_test (TSan)
shell: bash
working-directory: samples/input/illuminance_sensor
run: |
set -eu
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 60 ./illuminance_sensor_test
echo "[pass] illuminance_sensor_test (TSan)"
- name: Build and run libusb_hid_test (ASan + UBSan)
shell: bash
working-directory: samples/input/libusb_hid
run: |
set -eu
# The libusb HID driver against a fake libusb: reads and
# commands run on asynchronous transfers completed by the poll
# thread, with no thread per pad. Pins that a command goes out
# at once even while the pad sends nothing, that commands stay
# in order one at a time, that unplugging frees the adapter,
# and that freeing the driver returns at once with a send
# still pending, releasing every transfer and handle.
make clean all SANITIZER=address,undefined
test -x libusb_hid_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./libusb_hid_test
echo "[pass] libusb_hid_test (ASan)"
- name: Build and run libusb_hid_test (TSan)
shell: bash
working-directory: samples/input/libusb_hid
run: |
set -eu
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 60 ./libusb_hid_test
echo "[pass] libusb_hid_test (TSan)"
- name: Build and run wii_handshake_test (ASan + UBSan)
shell: bash
working-directory: samples/input/wii_handshake
run: |
set -eu
# The Wiimote extension handshake in connect_wii.c, fed
# reports directly. Pins that each init write waits for the
# remote's acknowledgement instead of a sleep on the packet
# thread, that a missing acknowledgement is only overtaken by
# a packet after the old 100 ms, and that no packet blocks.
make clean all SANITIZER=address,undefined
test -x wii_handshake_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./wii_handshake_test
echo "[pass] wii_handshake_test (ASan)"
- name: Build and run android_lifecycle_flush_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/android_lifecycle_flush
run: |
set -eu
# The Android background flush handshake, a UI thread against
# an app thread. Pins that onPause() and onStop() return only
# once SRAM, core options and the config are on disk - a
# swiped-away task is killed as soon as they have returned -
# that the save is written once per trip to the background,
# and that the startup pump acknowledges without saving.
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./android_lifecycle_flush_test
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 60 ./android_lifecycle_flush_test
make clean
echo "[pass] android_lifecycle_flush_test (ASan, TSan)"
- name: Build and run android_kbd_keys_test (ASan + UBSan)
shell: bash
working-directory: samples/input/android_kbd_keys
run: |
set -eu
# Key events from the Android system keyboard, through the
# native input queue to the text field that owns the menu
# line. Pins that a Backspace the soft keyboard sends as a
# key event is handed back to the field instead of being
# consumed natively - consumed, the field kept the
# characters and the next snapshot put them back on the line.
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./android_kbd_keys_test
make clean
echo "[pass] android_kbd_keys_test (ASan)"
- name: Build and run overlay_textures_test (plain, ASan + UBSan, threaded)
shell: bash
working-directory: samples/input/overlay_textures
run: |
set -eu
# input/input_overlay_textures.c as it is, against a stub
# driver that reads every pixel it is handed. Pins every
# route a page takes to the driver: as textures (each page
# gets its own images' textures, a switch uploads nothing,
# the pixels go once the driver has them and the sizes
# stay), and as pixels through load() for a driver that
# declines the textures, has no such path, or fails an
# upload - live pixels on every page. 86fbf34e01 freed the
# pixels before the page lists were matched by them, so
# with threaded video off the fallback showed freed memory;
# under ASan that is a use-after-free here.
make clean all
timeout 60 ./overlay_textures_test
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./overlay_textures_test
# THREADS=1: the threaded wrapper as a stub whose video
# thread runs when the test says so, so both outcomes of
# the race between the uploads and the poll are lanes. The
# quick thread is 86fbf34e01's bug again under threaded
# video; the slow one must find the pack's pixels alive.
make clean all THREADS=1 SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./overlay_textures_test
make clean
echo "[pass] overlay_textures_test (plain, ASan, threaded ASan)"
- name: Build and run winraw_abs_pos_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_abs_pos
run: |
set -eu
# input/drivers/winraw_input.c, cross-built with mingw-w64 and
# run under Wine: an absolute pointer report's position is
# kept as one word, and every read must give back a position
# a report carried, including a report that lands during poll.
# mingw-w64 and Wine come from "Install dependencies", whose
# download is bounded and retried; an unbounded install here
# stalled silently until the job timeout. Stop wineserver on
# exit so it cannot hold the step's output open.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_abs_pos_test (wine)"
-359
View File
@@ -1,359 +0,0 @@
name: CI Linux samples/network
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
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:
samples-network:
name: Build and run samples/network
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libmbedtls-dev libbearssl-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build and run webdav_options_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/network/webdav_options
run: |
set -eu
# Includes network/cloud_sync/webdav.c and drives the OPTIONS
# capability probe as shipped over real-world header sets. The
# probe has to separate a WebDAV server from a plain HTTP
# server that answers OPTIONS, and the target it probes is a
# collection, on which PUT is not defined (RFC 4918 9.7.1) -
# so PUT's absence from Allow must not fail it. The previous
# probe did exactly that, rejecting mod_dav and Koofr
# (libretro/RetroArch#19486) while accepting a plain nginx
# that happened to list PUT. Covers the DAV header, Allow-only
# WebDAV methods, HTTP/2 lowercase field names, plain HTTP
# with and without PUT, empty and NULL header lists, and
# whole-token matching (PROPFINDX must not match PROPFIND).
make clean all SANITIZER=address,undefined
test -x webdav_options_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./webdav_options_test
echo "[pass] webdav_options_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./webdav_options_test
echo "[pass] webdav_options_test (TSan)"
- name: Build and run webdav_reauth_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/network/webdav_reauth
run: |
set -eu
# Includes network/cloud_sync/webdav.c and plays the server
# for every request type the driver sends (OPTIONS, GET, PUT,
# DELETE, MOVE, MKCOL). A server that keeps answering 401 with
# a Digest challenge - a wrong password - must get one retry
# and then a reported failure; the driver used to retry every
# challenge, so a mistyped password looped the first request
# of a sync forever. A single stale-nonce challenge must still
# be retried and succeed. A retried PUT must send the file:
# it used to re-read it from the end the first attempt left
# it at and upload uninitialised memory in place of the save.
# A malformed challenge (a value with no closing quote, a
# trailing unquoted parameter) must be refused, not crash the
# parser or send it reading past the end of the line.
make clean all SANITIZER=address,undefined
test -x webdav_reauth_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./webdav_reauth_test
echo "[pass] webdav_reauth_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./webdav_reauth_test
echo "[pass] webdav_reauth_test (TSan)"
- name: Build and run webdav_backup_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/network/webdav_backup
run: |
set -eu
# Includes network/cloud_sync/webdav.c and plays the server,
# request by request. With destructive sync off, an upload
# must COPY the server's file to deleted/<path>-<time> before
# the PUT replaces it - it used to overwrite it in place, so
# the setting protected against deletes but not overwrites.
# Covers the order (backup first, into an existing deleted/
# collection, named as a delete names it), 404 as "nothing to
# back up", a failed backup stopping the upload, destructive
# sync and the server manifest skipping the backup, and COPY
# and PUT each getting their own Digest retry.
make clean all SANITIZER=address,undefined
test -x webdav_backup_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./webdav_backup_test
echo "[pass] webdav_backup_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./webdav_backup_test
echo "[pass] webdav_backup_test (TSan)"
- name: Build and run s3_backup_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/network/s3_backup
run: |
set -eu
# Includes network/cloud_sync/s3.c and plays the server,
# request by request. The S3 driver never read the
# destructive sync setting: deletes removed objects for good
# and uploads overwrote them. With it off, both must first
# CopyObject the object to deleted/<path>-<time>. Covers the
# copy source for virtual-hosted and path-style endpoints,
# x-amz-copy-source being signed, 404 as "nothing to keep", a
# failed copy (including a 200 with an <Error> body) stopping
# the delete or upload, and destructive sync and the server
# manifest skipping the copy.
make clean all SANITIZER=address,undefined
test -x s3_backup_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./s3_backup_test
echo "[pass] s3_backup_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./s3_backup_test
echo "[pass] s3_backup_test (TSan)"
- name: Build and run smb_backup_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/network/smb_backup
run: |
set -eu
# Includes network/cloud_sync/smb.c and runs it against an
# in-memory libsmb2 share (fake_smb.c), checking what the
# share holds after each upload. The driver used to truncate
# the server file and then write, so a write failing part way
# left a truncated save; and with destructive sync off it
# overwrote the file without keeping the old copy a delete
# keeps. Uploads now go through <path>.rauploading and the
# replaced file is kept as <path>-<time> (non-destructive).
# Covers a failed write, backup and final rename each leaving
# the old file intact with no temporary file left, no backup
# for destructive sync, a new file or the manifest, an empty
# upload and the configured subdirectory.
make clean all SANITIZER=address,undefined
test -x smb_backup_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./smb_backup_test
echo "[pass] smb_backup_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./smb_backup_test
echo "[pass] smb_backup_test (TSan)"
- name: Build and run gdrive_backup_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/network/gdrive_backup
run: |
set -eu
# Includes network/cloud_sync/google_drive.c and plays the
# Drive API, request by request. With destructive sync off, a
# delete kept the old file (renamed <name>-<time>) but an
# upload replaced its content outright. An upload to an
# existing file must now files.copy it to that name in the
# same folder before the PATCH. Covers the order and the copy
# request, a failed copy stopping the upload, a 401 on the
# copy and on the PATCH each refreshing the token once (the
# PATCH retry repeating only the PATCH, not the backup), and
# destructive sync, a new file and the manifest skipping it.
make clean all SANITIZER=address,undefined
test -x gdrive_backup_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./gdrive_backup_test
echo "[pass] gdrive_backup_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./gdrive_backup_test
echo "[pass] gdrive_backup_test (TSan)"
- name: Build and run cheevos_login_test (bear ASan+UBSan, bear TSan, mbed ASan+UBSan)
shell: bash
working-directory: samples/network/cheevos_login
run: |
set -eu
# Regression guard for the RetroAchievements login transport
# (libretro/RetroArch#19562, #19457): drives net_http with the
# exact login shape cheevos_client.c produces, against a local
# mock server that validates every request byte-for-byte, over
# plain HTTP and over TLS with the real SSL backend linked in.
# Covers: login on a fresh TLS connection, trust-store loading
# from a realistic messy CA bundle (BearSSL), keep-alive pool
# reuse, one-shot replay of a request on a pooled connection
# the server closed while idle, and no replay once response
# bytes have been seen. Each TLS backend's non-blocking send
# must push a 12 MiB body past a server that stops reading for
# a second without ever blocking, and deliver every byte; and
# net_http must send the same upload a slice per update, plain
# and over TLS - it used to go out in one blocking send, a call
# of a second or more (spinning at 100% CPU on a plain socket).
make clean all SANITIZER=address,undefined
test -x cheevos_login_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 timeout 120 \
make check
echo "[pass] cheevos_login_test (BearSSL, ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 180 make check
echo "[pass] cheevos_login_test (BearSSL, TSan)"
make clean all SSL_BACKEND=mbed SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 timeout 120 \
make check SSL_BACKEND=mbed
echo "[pass] cheevos_login_test (mbedTLS, ASan)"
# The built-in client, RetroArch's default backend.
make clean all SSL_BACKEND=retro SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 timeout 120 \
make check SSL_BACKEND=retro
echo "[pass] cheevos_login_test (built-in TLS, ASan)"
# The runner's libmbedtls-dev is 2.28, which has no TLS 1.3,
# so the leg above cannot see either TLS 1.3 failure. Mbed
# TLS 3.6.0 is the one release that shows both: it fails
# every handshake unless psa_crypto_init() was called, and it
# reports session tickets from mbedtls_ssl_read(). Library
# only, ~20 s to build. A download that still fails after
# the retries skips the leg rather than failing the job.
mbed_ver=3.6.0
mbed_sha=3ecf94fcfdaacafb757786a01b7538a61750ebd85c4b024f56ff8ba1490fcd38
mbed_tar="$RUNNER_TEMP/mbedtls-$mbed_ver.tar.bz2"
if curl -fsSL --retry 3 --retry-delay 5 --max-time 120 -o "$mbed_tar" \
"https://github.com/Mbed-TLS/mbedtls/releases/download/v$mbed_ver/mbedtls-$mbed_ver.tar.bz2"; then
echo "$mbed_sha $mbed_tar" | sha256sum -c -
tar -xjf "$mbed_tar" -C "$RUNNER_TEMP"
make -C "$RUNNER_TEMP/mbedtls-$mbed_ver" -j"$(nproc)" lib >/dev/null
make clean all SSL_BACKEND=mbed SANITIZER=address,undefined \
MBEDTLS_DIR="$RUNNER_TEMP/mbedtls-$mbed_ver"
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 timeout 120 \
make check SSL_BACKEND=mbed
echo "[pass] cheevos_login_test (mbedTLS $mbed_ver TLS 1.3, ASan)"
else
echo "::warning::Mbed TLS $mbed_ver download failed; TLS 1.3 leg skipped"
fi
- name: Build and run net_http_semantics_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/network/net_http_semantics
run: |
set -eu
# HTTP/1.1 semantics of libretro-common/net/net_http.c against
# an in-process scripted server on 127.0.0.1, which logs which
# connection every request arrived on. Covers GET 200 framing
# and pool reuse, and responses without a body: HEAD, 204 and
# 304 on keep-alive used to sit waiting for a close that never
# came, a 1xx other than 100 was taken as the final status,
# and a 101 or stray bytes after a bodyless response left the
# socket in the pool. Connection and Transfer-Encoding are
# read as lists ("Keep-Alive, Close", "gzip, chunked"),
# HTTP/1.0 without keep-alive is not pooled, and a length
# after "chunked" does not reframe the body. Redirects: an
# absolute-path Location used to go out as "GET //foo", a
# 302 loop was followed forever (now 8 hops), a streamed PUT
# redirected by a 307 is rewound and resent whole, and a 3xx
# body no longer lands in the caller's sink. Bounds: a header
# block (1xx blocks included) over 64 KiB and a chunk size
# with no hex digits fail instead of growing the buffer or
# passing as the last chunk, a Content-Length buffer never
# grows past the body, and a pooled connection that dies
# after the status line is not replayed. A URL shorter than
# its scheme is rejected without an overread. Unit matrix for
# net_http_url_join() and net_http_urldecode(), including
# buffer bounds and in-place decoding; redirects resolved
# through it ("../", "?q", "//host", fragments dropped,
# %20 left encoded). The response header block: lookup and
# iteration, the legacy string_list accessor, and 64 header
# lines costing no per-line allocations. A Content-Length or
# "chunked" on a 1xx block does not frame the final response.
# A followed 3xx's body is dropped as it arrives, not
# buffered to its Content-Length, and bytes past a body's
# Content-Length end the connection, not the transfer.
# Every case has a
# deadline, so a hang fails the case instead of the job.
# net_http is lock-free by design (DNS cache and pool owned by
# the driving thread, resolvers publish with an atomic store);
# keep it that way.
if grep -nE '\b(slock|scond)_[a-z_]+\(' ../../../libretro-common/net/net_http.c; then
echo "::error title=net_http lock::net_http.c must not take locks"
exit 1
fi
make clean all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 timeout 120 \
./net_http_semantics_test
echo "[pass] net_http_semantics_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 300 ./net_http_semantics_test
echo "[pass] net_http_semantics_test (TSan)"
-120
View File
@@ -1,120 +0,0 @@
name: CI Linux samples/record
on:
push:
branches:
- master
paths:
- 'record/**'
- 'libretro-common/queues/**'
- 'libretro-common/include/retro_spsc.h'
- 'libretro-common/include/retro_atomic.h'
- 'samples/record/**'
- '.github/workflows/Linux-samples-record.yml'
pull_request:
branches:
- master
paths:
- 'record/**'
- 'libretro-common/queues/**'
- 'libretro-common/include/retro_spsc.h'
- 'libretro-common/include/retro_atomic.h'
- 'samples/record/**'
- '.github/workflows/Linux-samples-record.yml'
workflow_dispatch:
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:
samples-record:
name: Build and run samples/record
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential pkg-config libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build and run ffmpeg_pipeline_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/record/ffmpeg_pipeline
run: |
set -eu
# record/drivers/record_ffmpeg.c end to end: frames whose
# pixels encode their number, plus audio, pushed from the
# test thread while the driver's encoder thread drains the
# attr/video/audio rings; the file is decoded back and every
# frame checked in order and pixel-exact. Covers the rings
# under contention, the full-queue wait, and the drain after
# the encoder thread is joined. Needs libavcodec with
# libx264rgb (Ubuntu's has it).
make clean all SANITIZER=address,undefined
test -x ffmpeg_pipeline_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 300 \
./ffmpeg_pipeline_test
echo "[pass] ffmpeg_pipeline_test (ASan)"
make clean all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 300 ./ffmpeg_pipeline_test
echo "[pass] ffmpeg_pipeline_test (TSan)"
@@ -1,106 +0,0 @@
name: CI Linux samples/settings
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
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:
samples-settings:
name: Build and run samples/settings
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 500M
ccache -z
- name: Build and run pipeline_migration_test (ASan + UBSan)
shell: bash
working-directory: samples/settings/pipeline_migration
run: |
set -eu
# The audio_threaded_pipeline config migration. The setting
# briefly held off/automatic/on and was saved as a number; it
# is a bool again, and a bool is always saved as "true" or
# "false", so a bare digit on the key is the older three-way
# value. config_get_bool() reads its automatic (1) as an
# explicit on, which forced the pipeline on for users who
# never chose it. Pins each stored digit against both
# defaults, and pins that "true", "false", absent, empty and
# multi-character values are untouched. The rule under test
# is restated from config_load_file(), which needs most of the
# frontend to run; a change to one must be made in the other.
make clean all SANITIZER=address,undefined
test -x pipeline_migration_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./pipeline_migration_test
echo "[pass] pipeline_migration_test (ASan)"
File diff suppressed because it is too large. Load diff
@@ -1,117 +0,0 @@
name: CI Linux samples [nothing else runs these]
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
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:
samples-unclaimed:
name: Samples no other job runs
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only -o Acquire::Retries=3 \
-o Acquire::http::Timeout=30 $pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y -o Acquire::Retries=3 \
-o Acquire::http::Timeout=30 $pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Run them
shell: bash
run: |
set -eu
# A sample that builds and runs, and that no workflow names,
# is a test nobody runs: font_lifecycle sat that way while
# its expectation drifted away from the font driver it was
# written against. This job takes whatever is left over -
# the list is computed, so a new sample joins it by existing
# rather than by being remembered.
#
# Samples that need a library the runner does not carry
# (SDL, FFmpeg, libusb) are skipped: their own workflows
# install what they need. A sample cross-built with mingw-w64
# and run under Wine gets both installed here, the first time
# one turns up, so it runs rather than fails for want of a
# compiler.
fails=0
wine_ready=0
for mk in $(find samples libretro-common/samples -name Makefile | sort); do
dir=$(dirname "$mk")
name=$(basename "$dir")
(cd "$dir" && make -n check >/dev/null 2>&1) || continue
if grep -rqlF "$name" .github/workflows/ 2>/dev/null; then
continue
fi
if grep -qiE 'sdl|ffmpeg|libav|libusb' "$mk"; then
echo "-- skip $dir (needs a library this job does not install)"
continue
fi
if [ $wine_ready -eq 0 ] && grep -qE 'mingw32-|wine' "$mk"; then
sudo apt-get update -y -qq -o Acquire::Retries=3 \
-o Acquire::http::Timeout=30 >/dev/null || true
sudo apt-get install -y -qq gcc-mingw-w64-x86-64 wine64 \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30
wine_ready=1
fi
echo "== $dir"
if (cd "$dir" && make clean >/dev/null 2>&1 \
&& ASAN_OPTIONS=detect_leaks=1:allocator_may_return_null=1 \
UBSAN_OPTIONS=print_stacktrace=1 \
timeout 300 make SANITIZER=address,undefined check); then
echo " ok"
else
echo " FAIL $dir"
fails=$((fails + 1))
fi
(cd "$dir" && make clean >/dev/null 2>&1) || true
done
if [ "$fails" -ne 0 ]; then
echo "$fails sample(s) failed"
exit 1
fi
@@ -1,68 +0,0 @@
name: CI Linux state_manager + runahead tests
# The rewind codec and ring, and the run-ahead core-copy protocol,
# driven directly by harnesses that include or extract the shipping
# code: samples/state_rewind and samples/runahead. Plain, then under
# ASan and UBSan with halt_on_error.
on:
push:
branches: [master]
paths:
- state_manager.c
- state_manager.h
- runahead.c
- runahead.h
- runloop.h
- samples/state_rewind/**
- samples/runahead/**
- tasks/task_nbio_slice.c
- tasks/tasks_internal.h
- libretro-common/queues/task_queue.c
- .github/workflows/Linux-state-runahead-tests.yml
pull_request:
branches: [master]
paths:
- state_manager.c
- state_manager.h
- runahead.c
- runahead.h
- runloop.h
- samples/state_rewind/**
- samples/runahead/**
- tasks/task_nbio_slice.c
- tasks/tasks_internal.h
- libretro-common/queues/task_queue.c
- .github/workflows/Linux-state-runahead-tests.yml
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
unit:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v5
- name: state_rewind
run: make -C samples/state_rewind clean check
- name: runahead
run: make -C samples/runahead clean check
sanitize:
runs-on: ubuntu-latest
timeout-minutes: 15
env:
ASAN_OPTIONS: abort_on_error=1:detect_leaks=1:print_stacktrace=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
steps:
- uses: actions/checkout@v5
- name: state_rewind (ASan + UBSan)
run: make -C samples/state_rewind clean check SANITIZER=address,undefined
- name: runahead (ASan + UBSan)
run: make -C samples/runahead clean check SANITIZER=address,undefined
-101
View File
@@ -1,101 +0,0 @@
name: CI Linux TSan [threaded-video harness]
# The threaded-video harness under ThreadSanitizer. Linux-tsan-threaded-
# video.yml builds with TSan and runs RetroArch headless with the
# wrapper on, which is one configuration; the harness has a lane for
# each thing the wrapper does - the runtime toggle, reinit under the
# wrapper, the command mailbox, presenter repeats and their display
# phase, the second ring waiter, the re-entrant frame, the call on the
# waiting thread, display pacing, the zero-copy loan, the hardware
# ring's bookkeeping - and runs each against the shipping objects with
# nothing stubbed. It is where the send/wait race in the waiter call
# was found, under TSan, on a developer's machine: this job is what
# keeps that class of bug found in CI instead. Null drivers, no
# display, no SDL, so no suppression file is needed; the harness sets
# halt_on_error itself, so any report fails the job.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
linux-tsan-harness:
name: TSan build, the threaded-video harness
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
# Non-Qt, as the harness requires (with Qt, main() lives in
# ui_qt.o). Menu enabled: the menu lanes are half the point.
run: |
./configure \
--disable-qt \
--disable-discord \
--disable-cheevos \
--disable-networking \
--disable-ffmpeg
- name: Build with DEBUG=1 and -fsanitize=thread
run: |
make -j$(getconf _NPROCESSORS_ONLN) SANITIZER=thread DEBUG=1
- name: Run the threaded-video harness under TSan
shell: bash
run: |
set -eu
# SAN=thread links exactly the build above; CYCLES=2 runs
# each toggling lane twice. The harness's own TSAN_OPTIONS
# halt on the first report.
SAN=thread CYCLES=2 make -C samples/gfx/threaded_video check
make -C samples/gfx/threaded_video clean
@@ -1,182 +0,0 @@
name: CI Linux TSan [Threaded video]
# Builds RetroArch with -fsanitize=thread and runs it headless with
# video_threaded = "true", which is the configuration none of the other
# jobs cover and the only one where the video thread exists at all.
#
# Why a separate job from Linux-asan-ubsan.yml: ASan and TSan cannot be
# linked into the same binary, and the ASan job deliberately runs
# unthreaded (video_threaded = "false") because its purpose is memory
# errors on the simplest path. Threading bugs are invisible there --
# the second thread is never created.
#
# What this reaches that nothing else does: the video thread wrapper's
# command and frame handoff, every driver frame() call running off the
# main thread, and the state the runloop and the video thread share --
# window title, alive/focus/presentable, viewport and statistics. Two
# real races were found this way and fixed (the window title handoff,
# and the runloop asking a context for presentability while the video
# thread rebuilt its swapchain); this job is what keeps them fixed.
#
# Soft-fail for now, like the ASan job's smoke tier was on its first
# iterations: TSan reports races inside libSDL2 itself that RetroArch
# neither causes nor can fix (see the suppression file written below),
# and the baseline wants a few green runs before it gates.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
linux-tsan-threaded-video:
name: Build with TSan and run with threaded video
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Install dependencies
# Same set as Linux-asan-ubsan.yml. libtsan ships with the gcc
# on the runner image, so nothing sanitizer-specific is needed.
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
# Same trimmed surface as the ASan job, for the same reason:
# a finding should be a RetroArch bug rather than noise from a
# vendored subsystem. --enable-sdl2 is explicit because the run
# below selects sdl2, and a silent fallback to another driver
# would quietly stop exercising the threaded path this job is
# for.
run: |
./configure \
--disable-menu \
--disable-discord \
--disable-cheevos \
--disable-networking \
--enable-sdl2
- name: Build with -fsanitize=thread
run: |
make -j$(getconf _NPROCESSORS_ONLN) SANITIZER=thread
test -x retroarch
file retroarch
- name: Run headless with video_threaded = true
continue-on-error: true
run: |
set -eu
Xvfb :99 -screen 0 640x480x24 &
for i in $(seq 1 15); do
if DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then
break
fi
sleep 1
done
# A 1x1 PNG for the imageviewer core, as in the ASan job.
python3 - <<'PY'
import binascii, struct
def chunk(t, d):
c = t + d
return struct.pack(">I", len(d)) + c + struct.pack(">I", binascii.crc32(c))
png = b"\x89PNG\r\n\x1a\n"
png += chunk(b"IHDR", struct.pack(">IIBBBBB", 1, 1, 8, 2, 0, 0, 0))
png += chunk(b"IDAT", b"\x08\xd7\x63\xf8\xcf\xc0\x00\x00\x03\x01\x01\x00\x18\xdd\x8d\xb0")
png += chunk(b"IEND", b"")
open("/tmp/test.png", "wb").write(png)
PY
# Races inside libSDL2 itself: no RetroArch frame appears on
# either access, so there is nothing here to fix. Suppressed
# by object so a real race in our own SDL-facing code is
# still reported.
cat > /tmp/tsan.supp <<'EOF'
race:libSDL2-2.0.so
EOF
mkdir -p /tmp/tsan-cfg
cat > /tmp/tsan-cfg/retroarch.cfg <<EOF
video_driver = "sdl2"
audio_driver = "null"
video_threaded = "true"
video_fullscreen = "false"
video_windowed_fullscreen = "false"
EOF
set +e
DISPLAY=:99 \
TSAN_OPTIONS="halt_on_error=0 history_size=4 suppressions=/tmp/tsan.supp" \
timeout 300 ./retroarch \
-c /tmp/tsan-cfg/retroarch.cfg \
-L cores/libretro-imageviewer/image_core.so \
/tmp/test.png \
--max-frames=400 \
--verbose \
> /tmp/tsan.out 2> /tmp/tsan.err
rc=$?
set -e
echo "exit=${rc}"
echo "=== stderr (last 200) ==="
tail -200 /tmp/tsan.err || true
# The video thread has to have existed, or the run proved
# nothing at all and a green result would be misleading.
if ! grep -q "ra-video\|[Tt]hreaded video" /tmp/tsan.out /tmp/tsan.err; then
echo "[WARN] no sign of the video thread; the threaded path may not have run"
fi
n=$(grep -c "WARNING: ThreadSanitizer" /tmp/tsan.err || true)
echo "ThreadSanitizer reports: ${n}"
if [ "${n}" -gt 0 ]; then
echo ""
echo "[INFO] ThreadSanitizer finding(s):"
grep "SUMMARY: ThreadSanitizer" /tmp/tsan.err || true
fi
@@ -1,557 +0,0 @@
name: CI Vulkan/GL/D3D11 [idle waits + driver harness]
# Two checks on the Vulkan driver, both born from the same bug: a
# vkQueuePresentKHR under queue_lock waiting for GPU work that a
# hardware core could only submit through lock_queue (parallel-GS /
# Granite stopped the frontend that way). Every vkQueueWaitIdle and
# vkDeviceWaitIdle in the driver had the same shape - a whole-queue
# drain, under the lock the core needs, on shader change, overlay
# load, font free and swapchain resize - and all of them were replaced
# by waits on the driver's own fences.
#
# 1. Idle-wait check: tools/vulkan_idle_wait_check.py fails on any
# vkQueueWaitIdle/vkDeviceWaitIdle in the Vulkan code that is not
# on tools/vulkan_idle_wait_allow.list, and on a stale entry.
#
# 2. Validation harness: the threaded-video harness (real frontend,
# real driver, only main() replaced) run on the Vulkan driver over
# lavapipe under Xvfb, with the tree built VULKAN_DEBUG=1 so
# VK_LAYER_KHRONOS_validation is loaded. The lanes exercise driver
# reinit under the wrapper, geometry changes, async texture loads,
# font marshalling, present repeat and resize; the layer turns a
# texture destroyed while a frame still samples it, a barrier
# inside a render pass, or an object leaked at device teardown into
# a logged error, and the check-vulkan target fails on any. Those
# three were the pre-existing findings the lane produced on its
# first run.
#
# 3. TSan harness: the same lanes on the same driver, built with
# -fsanitize=thread. The null-driver TSan job never runs driver
# code on the video thread, so a plain field shared between the
# frame thread and a driver's frame (the shader chains'
# FrameTimeDelta was one) only shows up here. The layer and the
# ICD are not instrumented and are suppressed; frontend races fail.
# An address,undefined build of the same runs beside it, and the
# context-only vulkan_validation sample runs on its own.
#
# 5. D3D11 harness: the same lanes on the d3d11 driver, on a Windows
# runner through MSYS2's MinGW64 build of the tree (no Qt, so main
# stays in retroarch.o for the harness to replace) and the software
# adapter the runner exposes (Microsoft Basic Render Driver, which
# is WARP). The first real-driver coverage the Windows drivers get.
#
# 4. GL harness: the same lanes on the gl and glcore drivers over
# llvmpipe (LIBGL_ALWAYS_SOFTWARE=1), release and TSan. A GL
# context is owned by one thread at a time, so anything the
# frontend does against the driver from the wrong thread is an X
# BadAccess here rather than a corruption elsewhere; the first run
# caught the OSD font rebuild doing exactly that.
#
# 6. Teardown-order check: tools/vulkan_teardown_order_check.py holds
# the order the driver retires a frame's objects in - command
# pools, then descriptor pools, then the pipelines that own the set
# layout - and the rule that destroying a descriptor pool is what
# frees its sets. The other order is legal Vulkan and the
# validation layer passes it, so the harness lanes above cannot see
# it; a driver that walks its own back references as a pool is
# destroyed faults inside vkDestroyDescriptorPool at exit, which is
# what MoltenVK did.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
vulkan-idle-waits:
name: Vulkan idle-wait allowlist
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checker self-test
shell: bash
run: |
set -eu
python3 tools/vulkan_idle_wait_check.py --selftest
- name: Tree check
shell: bash
run: |
set -eu
python3 tools/vulkan_idle_wait_check.py
vulkan-teardown-order:
name: Vulkan teardown order
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checker self-test
shell: bash
run: |
set -eu
python3 tools/vulkan_teardown_order_check.py --selftest
- name: Tree check
shell: bash
run: |
set -eu
python3 tools/vulkan_teardown_order_check.py
vulkan-validation-harness:
name: Threaded-video harness on Vulkan (lavapipe, validation layer)
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev libxcb1-dev libxinerama-dev libxrandr-dev libxxf86vm-dev libxv-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libvulkan-dev mesa-vulkan-drivers vulkan-validationlayers vulkan-tools libasound2-dev"
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
# Non-Qt, as the harness requires (with Qt, main() lives in
# ui_qt.o). Everything else at its default so the Vulkan driver
# is built with every path a release build has.
run: |
./configure --disable-qt
grep -q '^HAVE_VULKAN = 1' config.mk
- name: Build with VULKAN_DEBUG=1
# VULKAN_DEBUG enables VK_LAYER_KHRONOS_validation and the
# debug messenger that reports through RARCH_ERR. It is a
# tree-wide define: vulkan_context_t carries a member under it,
# so every TU that includes vulkan_common.h must see it.
# GFX_INSTRUMENT counts what the image and surface paths do -
# uploads, in-place updates, allocating posts, copies - so the
# harness lanes below can hold the budgets the paths are
# written to and print what a run cost. This is the one leg
# that carries it: under a sanitizer the timings mean nothing,
# and the counters change no behaviour.
run: |
make -j$(getconf _NPROCESSORS_ONLN) VULKAN_DEBUG=1 GFX_INSTRUMENT=1
test -x retroarch
- name: Run the harness on Vulkan under the validation layer
shell: bash
run: |
set -eu
Xvfb :99 -screen 0 640x480x24 &
for i in $(seq 1 15); do
if DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then
break
fi
sleep 1
done
export DISPLAY=:99
export VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.json
# The harness build reuses the tree's own compile and link
# lines, so it has to name the same build: VK_DEBUG=1. Its
# surface and overlay-page lanes run the driver's real
# in-place texture update and its borrowed-texture overlay
# page here, under the validation layer, and with the tree
# built GFX_INSTRUMENT=1 they print their baselines and hold
# the budgets: one texture per streaming surface, no
# allocation per post, no copy, a 4K submit that stays a
# descriptor hand-off.
SAN=none VK_DEBUG=1 GFX_INSTRUMENT=1 CYCLES=2 make -C samples/gfx/threaded_video check-vulkan
# Once more with the harness core pushing XRGB8888: the
# driver samples a linear 32-bit image itself where it
# converts RGB565 with a compute pass, so a lent frame and
# a window into it take the other upload path (the one
# beetle-psx takes).
HARNESS_CORE_XRGB8888=1 SAN=none VK_DEBUG=1 GFX_INSTRUMENT=1 CYCLES=1 make -C samples/gfx/threaded_video check-vulkan
# And with the harness core as a Vulkan hardware core, which
# runs its own lane alone: the core's image must not be drawn
# from once the core has destroyed it - at a content close,
# unthreaded and under the wrapper, and after a set_image(NULL)
# - and a dupe of a hardware frame must not re-submit a fence
# that is already signalled. Either is a validation error
# here, and on lavapipe a crash.
HARNESS_CORE_HW_VULKAN=1 SAN=none VK_DEBUG=1 GFX_INSTRUMENT=1 CYCLES=1 make -C samples/gfx/threaded_video check-vulkan
make -C samples/gfx/threaded_video clean
# And as a core that creates the device itself, through the
# negotiation interface's create_device - Beetle PSX, for one.
# That device has the extensions the frontend requires and
# none of the optional ones it adds to a device of its own, so
# anything the driver or the filter chain does that leans on
# an optional extension is a validation error here and nowhere
# else. The filter chain's mirror-clamp samplers were.
HARNESS_CORE_HW_VULKAN=2 SAN=none VK_DEBUG=1 GFX_INSTRUMENT=1 CYCLES=1 make -C samples/gfx/threaded_video check-vulkan
make -C samples/gfx/threaded_video clean
vulkan-validation-sample:
name: vulkan_validation sample (lavapipe, validation layer)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libx11-dev libx11-xcb-dev libxcb1-dev xvfb x11-utils libvulkan-dev mesa-vulkan-drivers vulkan-validationlayers vulkan-tools"
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Build and run
shell: bash
run: |
set -eu
# The context-only sample: vulkan_common.c against the real
# loader, brought up and torn down under the validation
# layer, and every memory type it advertises selected. It
# exits 77 with no display or no device, and that is a pass.
Xvfb :99 -screen 0 640x480x24 &
for i in $(seq 1 15); do
if DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then
break
fi
sleep 1
done
export DISPLAY=:99
make -C samples/gfx/vulkan_validation
rc=0
DISPLAY=:99 VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.json \
samples/gfx/vulkan_validation/vulkan_validation_test || rc=$?
make -C samples/gfx/vulkan_validation clean
if [ "$rc" = 77 ]; then echo "skipped: no device"; exit 0; fi
exit $rc
vulkan-asan-harness:
name: Threaded-video harness on Vulkan under ASan+UBSan (lavapipe)
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev libxcb1-dev libxinerama-dev libxrandr-dev libxxf86vm-dev libxv-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libvulkan-dev mesa-vulkan-drivers vulkan-validationlayers vulkan-tools libasound2-dev"
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
run: |
./configure --disable-qt
grep -q '^HAVE_VULKAN = 1' config.mk
- name: Build with DEBUG=1, VULKAN_DEBUG=1 and -fsanitize=address,undefined
run: |
make -j$(getconf _NPROCESSORS_ONLN) SANITIZER=address,undefined DEBUG=1 VULKAN_DEBUG=1
test -x retroarch
- name: Run the harness on Vulkan under ASan+UBSan
shell: bash
run: |
set -eu
Xvfb :99 -screen 0 640x480x24 &
for i in $(seq 1 15); do
if DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then
break
fi
sleep 1
done
export DISPLAY=:99
export VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.json
SAN=address VK_DEBUG=1 CYCLES=1 make -C samples/gfx/threaded_video check-vulkan
HARNESS_CORE_XRGB8888=1 SAN=address VK_DEBUG=1 CYCLES=1 make -C samples/gfx/threaded_video check-vulkan
make -C samples/gfx/threaded_video clean
vulkan-tsan-harness:
name: Threaded-video harness on Vulkan under TSan (lavapipe)
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev libxcb1-dev libxinerama-dev libxrandr-dev libxxf86vm-dev libxv-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libvulkan-dev mesa-vulkan-drivers vulkan-validationlayers vulkan-tools libasound2-dev"
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
run: |
./configure --disable-qt
grep -q '^HAVE_VULKAN = 1' config.mk
- name: Build with DEBUG=1, VULKAN_DEBUG=1 and -fsanitize=thread
run: |
make -j$(getconf _NPROCESSORS_ONLN) SANITIZER=thread DEBUG=1 VULKAN_DEBUG=1
test -x retroarch
- name: Run the harness on Vulkan under TSan
shell: bash
run: |
set -eu
Xvfb :99 -screen 0 640x480x24 &
for i in $(seq 1 15); do
if DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then
break
fi
sleep 1
done
export DISPLAY=:99
export VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.json
SAN=thread VK_DEBUG=1 CYCLES=1 make -C samples/gfx/threaded_video check-vulkan
make -C samples/gfx/threaded_video clean
gl-harness:
name: Threaded-video harness on ${{ matrix.driver }} (llvmpipe, ${{ matrix.san }})
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
driver: [gl, glcore]
san: [none, address, thread]
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev libxcb1-dev libxinerama-dev libxrandr-dev libxxf86vm-dev libxv-dev xvfb x11-utils zlib1g-dev libfreetype6-dev libgl-dev libglx-dev libegl-dev libgles-dev libgl1-mesa-dri libglx-mesa0 mesa-utils libasound2-dev"
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Configure
run: |
./configure --disable-qt
grep -q '^HAVE_OPENGL = 1' config.mk
grep -q '^HAVE_OPENGL_CORE = 1' config.mk
- name: Build
run: |
case "${{ matrix.san }}" in
thread) make -j$(getconf _NPROCESSORS_ONLN) SANITIZER=thread DEBUG=1 ;;
address) make -j$(getconf _NPROCESSORS_ONLN) SANITIZER=address,undefined DEBUG=1 ;;
*) make -j$(getconf _NPROCESSORS_ONLN) ;;
esac
test -x retroarch
- name: Run the harness on ${{ matrix.driver }}
shell: bash
run: |
set -eu
Xvfb :99 -screen 0 640x480x24 &
for i in $(seq 1 15); do
if DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then
break
fi
sleep 1
done
export DISPLAY=:99
export LIBGL_ALWAYS_SOFTWARE=1
SAN=${{ matrix.san }} DRIVER=${{ matrix.driver }} CYCLES=1 \
make -C samples/gfx/threaded_video check-driver
make -C samples/gfx/threaded_video clean
d3d-harness:
name: Threaded-video harness on ${{ matrix.driver }} (WARP, MSYS2 MinGW64)
runs-on: windows-latest
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
# d3d12 runs the same lanes on the other explicit-API backend:
# its in-place texture update is fence-tagged against the frame
# that last copied from the upload buffer, which only a running
# driver exercises. It runs with the harness core pushing
# XRGB8888: d3d12 lends its framebuffer only for a row pitch
# on a 256-byte boundary, which 320 pixels reach at 4 bytes and
# not at 2, so that is the run in which a frame is lent and a
# window into the loan is read out of it (lent-window lane).
driver: [d3d11, d3d12]
include:
- driver: d3d12
core_xrgb8888: 1
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Set up MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
install: >-
base-devel
git
pacboy: >-
cc:p
gdb:p
- name: Configure and build RetroArch (no Qt)
shell: msys2 {0}
run: |
set -eu
./configure --disable-qt
grep -q '^HAVE_D3D11 = 1' config.mk
grep -q '^HAVE_D3D12 = 1' config.mk
make -j"$(nproc)"
test -x retroarch.exe
- name: Run the harness on ${{ matrix.driver }}
shell: msys2 {0}
run: |
set -eu
samples/gfx/threaded_video/build.sh
HARNESS_CORE_XRGB8888=${{ matrix.core_xrgb8888 || '' }} \
SAN=none DRIVER=${{ matrix.driver }} CYCLES=1 GDB=1 make -C samples/gfx/threaded_video check-driver
make -C samples/gfx/threaded_video clean
+3 -22
View File
@@ -2,7 +2,6 @@ name: CI Linux (i686)
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,14 +12,9 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-i386-ubuntu:xenial-gcc9
options: --user root
@@ -33,24 +27,11 @@ jobs:
run: |
./configure --disable-qt --enable-xdelta
- name: Include order
run: |
# The tree's own headers are found before same-named ones in the
# system include dirs configure or pkg-config put on the line.
sh tools/include_order_check.sh
- name: Compile RA
run: |
make -j$(getconf _NPROCESSORS_ONLN) clean
make -j$(getconf _NPROCESSORS_ONLN) info all
- name: Stack frame sweep
run: |
set -eu
# Every stack frame in the graphics objects against the
# ceiling in CODING-GUIDELINES. It runs here rather than with
# the other checks because this is the job that builds the
# drivers: the menu harness turns OpenGL, Vulkan and the rest
# off for its own reasons, and the frames this sweep is for
# live in exactly those files.
.github/workflows/scripts/stack-frame-sweep.sh
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI Windows (MSVC)
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -14,15 +13,10 @@ env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
# These jobs run smoke tests to ensure that MSVC-specific builds work properly.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
msvc:
runs-on: windows-2022
timeout-minutes: 90
strategy:
matrix:
version: [UWP, 2019, 2022]
@@ -37,7 +31,7 @@ jobs:
platform: x64
# Qt and Cg builds are excluded for now
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1
+2 -7
View File
@@ -2,7 +2,6 @@ name: CI Windows (MSYS2)
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -10,10 +9,6 @@ on:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
msys2-build-test:
strategy:
@@ -33,16 +28,16 @@ jobs:
runner: windows-11-arm
runs-on: ${{ matrix.runner }}
timeout-minutes: 90
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: Set up MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.sys }}
update: true
install: >-
base-devel
git
-99
View File
@@ -1,99 +0,0 @@
name: CI macOS PowerPC (cross)
# Builds the macOS (Cocoa + OpenGL) frontend for 32-bit PowerPC with a
# GCC 14 cross compiler on Linux, against the 10.5 SDK, once for a
# 10.4 deployment target and once for 10.5. This is the
# compiler-compatibility leg for the Apple code: no clang, no ARC, no
# blocks, no GCD, and nothing newer than Leopard in the SDK. Whatever
# the Xcode 3 / PowerPC project would reject, this rejects first.
#
# Toolchain: VariantXYZ's GCC 14.2 powerpc-apple-darwin8 image (GCC
# with the Objective-C front end, cctools-port ld/as, dsymutil), see
# https://github.com/VariantXYZ/gcc-powerpc-apple-darwin8.
#
# The audit step lists every import the binary makes that the 10.4u
# SDK does not export; for the 10.4 target that list must be empty,
# which is what makes the binary launch on Tiger.
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
TARGET: powerpc-apple-darwin8
SDKROOT: /usr/local/MacOSX10.5.sdk
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 60
container:
image: ghcr.io/variantxyz/gcc-powerpc-apple-darwin8:build-gcc-14.2-MacOSXSDK10.5
options: --user root
strategy:
fail-fast: false
matrix:
deployment_target: ["10.4", "10.5"]
env:
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment_target }}
steps:
- uses: actions/checkout@v4
- name: Configure
run: |
$TARGET-gcc --version | head -n 1
./configure --host=$TARGET \
--disable-qt --disable-sdl --disable-sdl2 --disable-ffmpeg \
--disable-x11 --disable-wayland --disable-egl \
--disable-pulse --disable-alsa --disable-jack --disable-oss \
--disable-udev --disable-v4l2 --disable-libusb \
--disable-freetype --disable-flac --disable-discord \
--disable-translate --disable-microphone --disable-avf \
--disable-mfi --disable-slang --disable-spirv_cross \
--disable-glslang --disable-crtswitchres --disable-al \
--disable-cdrom
- name: Compile RA
run: |
make ARCH=ppc -j$(getconf _NPROCESSORS_ONLN)
file retroarch
$TARGET-otool -l retroarch | grep -A2 LC_VERSION_MIN_MACOSX
- name: Audit imports against the 10.4u SDK
if: matrix.deployment_target == '10.4'
run: |
set -e
cd /usr/local
wget -q https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX10.4u.sdk.tar.xz
tar xJf MacOSX10.4u.sdk.tar.xz && rm MacOSX10.4u.sdk.tar.xz
cd "$GITHUB_WORKSPACE"
SDK4=/usr/local/MacOSX10.4u.sdk
$TARGET-nm -u retroarch | sed 's/^ *//' | sort -u > undef.txt
( find $SDK4/usr/lib -name '*.dylib' ; \
find $SDK4/System/Library/Frameworks -type f -path '*/Versions/*' ! -path '*/Headers/*' ! -path '*/Resources/*' ) \
| while read -r lib; do $TARGET-nm -g -arch ppc "$lib" 2>/dev/null | awk 'NF==3 {print $3} NF==2 {print $2}'; done \
| sort -u > sdk4.txt
echo "Imports absent from the 10.4u SDK:"
comm -23 undef.txt sdk4.txt | grep -v '^_OBJC_CLASS_\$_\|^\.objc_class_name_' | tee missing.txt
test ! -s missing.txt
- name: Get short SHA
id: slug
run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with:
name: RetroArch-macOS-ppc-${{ matrix.deployment_target }}-${{ steps.slug.outputs.sha8 }}
path: retroarch
-94
View File
@@ -2,7 +2,6 @@ name: CI macOS
on:
push:
branches: [master]
pull_request:
permissions:
@@ -11,79 +10,13 @@ permissions:
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: macos-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
- name: Cocoa companion harness on Apple's AppKit
run: |
set -o pipefail
# The same harness the Linux job runs under GNUstep, built with
# Apple's clang against the real Cocoa framework and run on the
# runner's window server: key-window arbitration after closing the
# companion, the grid, the tables, the dialogs - as AppKit does them.
tools/companion_cocoa_test_macos.sh 2>&1 | grep -v "^$"
- name: Metal texture behaviour the surface, overlay and lent-framebuffer paths assume
run: |
set -o pipefail
# The driver's Metal paths have only ever been compiled. This
# asserts the two behaviours they are built on, on the runner's
# real device: a texture replaced in place while GPU work that
# samples it is in flight - the animated preview's steady
# state, and the one path with no fence check or DO_NOT_WAIT to
# drop a frame with - and an overlay page holding textures the
# pack owns, where a page switch must not take them with it.
#
# 77 means the runner exposed no Metal device; the sample says
# so rather than passing quietly.
cd samples/gfx/metal_texture_update
make check; rc=$?
if [ "$rc" = 77 ]; then
echo "::warning::no Metal device on this runner; the check did not run"
exit 0
fi
exit "$rc"
- name: iCloud Drive cloud sync driver
run: |
set -o pipefail
# Includes network/cloud_sync/icloud_drive.m, with the iCloud
# container redirected to a temporary directory. Cloud sync
# waits for every request to report exactly once: a read whose
# local file could not be created never reported (the sync
# hung), and a cloud file that could not be loaded or a local
# file that could not be read reported twice. With iCloud
# unavailable, read and delete reported success. Also covers
# the ordinary read, missing file, upload and delete paths.
cd samples/network/icloud_drive
make clean check SANITIZER=address,undefined
- name: iCloud (CloudKit) cloud sync driver
run: |
set -o pipefail
# Includes network/cloud_sync/icloud.m, with CloudKit replaced by
# an in-memory database (+[CKContainer defaultContainer] is
# overridden in a category; real CKRecord/CKAsset/CKQuery). A
# read whose local file could not be written, or whose record
# held no readable data, reported success; an upload whose
# lookup failed created a duplicate record; a delete reported
# success before its deletes were sent, whatever became of
# them; and non-destructive sync was ignored. Checks each case,
# that deletes and uploads keep <path>-<time> with destructive
# sync off (and not for destructive sync or the manifest), and
# that every request reports exactly once.
cd samples/network/icloud_cloudkit
make clean check SANITIZER=address,undefined
- name: Compile RA
run: |
set -o pipefail
@@ -98,30 +31,3 @@ jobs:
name: RetroArch-${{ steps.slug.outputs.sha8 }}
path: |
build/Build/Products/Release
# The threaded-video harness on the Metal driver: the real frontend
# under Cocoa's own main (see samples/gfx/threaded_video/harness_cocoa.m),
# every lane the Vulkan and D3D legs run, on the runner's GPU. A
# Makefile build, since the harness links the tree's objects.
metal-harness:
runs-on: macos-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
- name: Configure and build (Makefile, no Qt)
run: |
set -o pipefail
./configure --disable-qt --disable-ffmpeg --disable-discord --disable-cheevos \
--disable-networking --disable-sdl2 --disable-sdl --disable-translate \
--disable-update_cores --disable-update_assets --disable-online_updater \
--disable-cdrom --disable-7zip --disable-ssl 2>&1 | tail -5
make -j$(sysctl -n hw.ncpu) GFX_INSTRUMENT=1 2>&1 | grep -E "error|warning: unused" || true
test -x retroarch
- name: Harness on Metal (RGB565 core, then XRGB8888)
run: |
set -o pipefail
SAN=none GFX_INSTRUMENT=1 DRIVER=metal CYCLES=1 make -C samples/gfx/threaded_video check-driver
HARNESS_CORE_XRGB8888=1 SAN=none GFX_INSTRUMENT=1 DRIVER=metal CYCLES=1 make -C samples/gfx/threaded_video check-driver
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI Miyoo ARM32
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-dingux:latest
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile RA
run: |
-110
View File
@@ -1,110 +0,0 @@
name: CI msg_hash packed tables
# intl/msg_hash_<lang>.h is generated as two objects that are paired by
# position: the blob struct holds every row as one run of NUL-terminated
# strings, and ids[] names the enum each row belongs to.
# msg_hash_strtab_index_build() walks the blob once and hands row N to
# ids[N].
#
# Nothing in the C ties them together. Both objects are well formed on
# their own, and the sizeof() contiguity check inside the header only
# measures the blob against itself, so a row removed from one side and
# left on the other compiles clean everywhere and renames every row
# after it at runtime. The menu then shows real translated strings
# belonging to other entries - which is what #19534 reported, in every
# language at once. English is unaffected, because msg_hash_us.c is a
# switch rather than a packed table, so no English-language test, manual
# or automated, can see it either.
#
# 5d0f721 did exactly that: retiring audio_block_frames took
# MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES and its sublabel out of ids[]
# in twenty-nine headers and left the two blob members behind. From the
# audio device row onward every language was off by one or two.
#
# The check re-derives the pairing from the member names - json2h.py
# names each member after the djb2 hash of the key its row was emitted
# for - and compares it against ids[] row for row, under the guards. It
# reads the files rather than building them, so it covers every
# language and every #ifdef configuration at once, which no build job
# does. intl/json2h.py runs the same check on its own output before
# writing, so this is the lane that catches a header edited by hand.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
msg-hash-packed-check:
name: blob and ids[] pairing
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checker self-test
shell: bash
run: |
set -eu
# Fixture pass: a consistent table is clean, 5d0f721's shape
# (a row dropped from ids[] only) is caught, so is its mirror,
# a member one byte wider than its string, a guard present on
# one side only, and a contiguity constant left stale.
#
# The fixtures are built by the checker rather than lifted
# from intl/, so this reports the same thing whether or not
# the shipped headers currently pass - it is measuring the
# checker, not the tree.
python3 tools/msg_hash_packed_check.py --selftest
- name: Tree check
shell: bash
run: |
set -eu
# Every packed header: row N's member name must be what the
# key in ids[N] hashes to and carry the same guard, each
# member must be exactly its string plus the NUL (or exactly
# the chunk, for a non-final chunk of a split row), no row may
# hold an embedded NUL, and the sizeof() check must still add
# up to the members it guards.
python3 tools/msg_hash_packed_check.py
- name: Format parity self-test
shell: bash
run: |
set -eu
# Fixture pass: matching conversions are clean, a conversion
# lost, invented, retyped or reordered positionally is caught,
# and a percent sign in prose - English's "50% of this value",
# Hungarian's "50%-a", a doubled %% - is not mistaken for one.
# The format-site scan is measured too: it must see a format
# argument taken from the table directly and through a local,
# and must not see a string that is copied, passed as a value,
# or split on a placeholder rather than formatted.
python3 tools/msg_hash_format_check.py --selftest
- name: Format parity tree check
shell: bash
run: |
set -eu
# Every translated row against its English source: the same
# conversions in the same order wherever English has any, no
# positional %n$ anywhere, and no conversion invented in a row
# that is used as a format string and has none in English.
# That last set is measured from the call sites rather than
# assumed from the namespace: ninety rows reach a printf-family
# format argument today and twenty-nine of them are not MSG_*.
python3 tools/msg_hash_format_check.py
-54
View File
@@ -1,54 +0,0 @@
name: CI Overlapping-buffer copies
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
overlap-copy-check:
name: Overlapping dst/src in copy calls
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checker self-test
shell: bash
run: |
set -eu
# Fixture pass: exact-alias strlcpy and overlapping memcpy
# element shifts are flagged, memmove is not, unguarded
# param->param copy helpers called with aliased buffers are
# flagged while alias-guarded helpers are not, the
# allowlist suppresses audited same-base copies but can
# never suppress an exact alias, and stale allowlist
# entries are reported.
python3 tools/overlap_copy_check.py --selftest
- name: Tree check
shell: bash
run: |
set -eu
# strlcpy resolves to the fortified __strlcpy_chk on macOS,
# which aborts on ANY dst/src overlap (bd79aee: typing into
# the OSK crashed with EXC_BREAKPOINT), and overlapping
# memcpy is UB everywhere (e942ee2: leaderboard element
# shift). The portable strlcpy fallback tolerates aliasing
# on Linux/Windows, so nothing else in CI can catch this
# class before it ships to Mac users. Audited-intentional
# same-buffer copies live in tools/overlap_copy_allow.list.
python3 tools/overlap_copy_check.py
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI PS2
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-ps2:latest
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile Salamander
run: |
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI PS3/PSL1GHT
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-psl1ght:latest
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile Salamander
run: |
+17 -22
View File
@@ -2,7 +2,6 @@ name: CI PS4/ORBIS
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,35 +12,26 @@ permissions:
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-latest
timeout-minutes: 30
# The image is Alpine 3.15, whose musl cannot load the runner's
# Node 24, so JavaScript actions run on the host and only the
# build steps run inside the image.
env:
ORBIS_IMAGE: reallibretroretroarch/libretro-build-orbis:latest
container:
image: reallibretroretroarch/libretro-build-orbis:latest
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Install dependencies
run: |
apk add ncurses-dev make bash python2
apk add libintl icu-dev wget
wget https://dot.net/v1/dotnet-install.sh && chmod 755 dotnet-install.sh && ./dotnet-install.sh -c 3.0 --install-dir ~/cli
- name: Compile RA
run: |
docker run --rm --user root -v "$PWD":/src -w /src "$ORBIS_IMAGE" bash -c '
set -e
apk add ncurses-dev make bash python2
apk add libintl icu-dev wget
wget https://dot.net/v1/dotnet-install.sh && chmod 755 dotnet-install.sh && ./dotnet-install.sh -c 3.0 --install-dir ~/cli
export PATH=~/cli:$PATH # .net cli
make -f Makefile.orbis -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info all
clang --version
orbis-ld --version
'
export PATH=~/cli:$PATH # .net cli
make -f Makefile.orbis -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info all
- name: Get short SHA
id: slug
@@ -54,3 +44,8 @@ jobs:
retroarch_orbis.elf
retroarch_orbis.oelf
retroarch_orbis.self
- name: Version of binaries
run: |
clang --version
orbis-ld --version
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI PSP
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-psp:latest
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile bootstrap
run: |
+2 -8
View File
@@ -2,7 +2,6 @@ name: CI PSVita
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-vita:latest-20260905
image: reallibretroretroarch/libretro-build-vita:latest
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile Salamander
run: |
@@ -1,85 +0,0 @@
name: CI RGUI pixel format
# RGUI draws into a 16bpp framebuffer, so every menu colour, wallpaper
# and thumbnail pixel passes through one of the argb32_to_* converters
# in menu/drivers/rgui.c. Each one quantises the four 8-bit channels
# to its target widths and ORs them into their fields, with the widths
# and the shifts written by hand on separate lines - seven formats,
# fourteen driver idents, and a dithered twin of each.
#
# Nothing else in CI can see a mistake there. The formats are
# per-platform: rgb565 belongs to sdl_dingux, sdl_rs90 and xvideo, and
# no runner boots a 565 menu, so a converter can be wrong for months
# while every desktop build renders perfectly. It is not a build
# break either - a width that outgrows its shift just ORs into the
# neighbouring field, silently.
#
# c6b66c9 did exactly that: it widened green in argb32_to_rgb565 from
# 5 bits to 6 but left the packing at (g << 6), where 6-bit green
# needs (g << 5). Green's top bit landed on red's LSB, the green
# field became (g & 31) << 1, and green wrapped hard at half scale -
# mid grey rendered as (139, 0, 131). It shipped, and came back as
# #19469, bisected by hand on an Anbernic RG300X.
#
# The check lifts the marked pixel format conversion block out of
# rgui.c and compiles it on its own against two stubs, so it tests the
# real shipped converters and the real dispatch table. Field layouts
# are measured from the converters, not hardcoded, so a new format
# gets checked the moment its row is added to rgui_pixel_format_map.
on:
push:
paths:
- 'menu/drivers/rgui.c'
- 'tools/rgui_pixfmt_check.py'
- '.github/workflows/RGUI-Pixel-Format-Check.yml'
pull_request:
paths:
- 'menu/drivers/rgui.c'
- 'tools/rgui_pixfmt_check.py'
- '.github/workflows/RGUI-Pixel-Format-Check.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
rgui-pixfmt-check:
name: RGUI 8-bit to 16bpp conversion contract
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Checker self-test
shell: bash
run: |
set -eu
# Fixture pass: the corrected 6-bit green packed at <<5
# passes, c6b66c9's same green packed at <<6 is caught as a
# red/green overlap, and a table row wired to another
# format's dithered twin is caught as a reach mismatch.
#
# Both green fixtures are made by forcing the packing shift
# either way, so the self-test reports the same thing
# whether or not the tree is currently fixed - it is
# measuring the checker, not the tree.
python3 tools/rgui_pixfmt_check.py --selftest --cc gcc
- name: Tree check
shell: bash
run: |
set -eu
# Per driver ident, and for the unknown-ident fallback: the
# bits each input channel can change must be disjoint from
# every other channel's and contiguous; 0 and 255 must give
# an empty and a full field; the field must be monotonic in
# the input; and the dithered twin must cover the same bits
# and stay within one level of the plain converter.
python3 tools/rgui_pixfmt_check.py --cc gcc
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI RS90 Odbeta MIPS32
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-dingux:odbeta
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile RA
run: |
-108
View File
@@ -1,108 +0,0 @@
name: CI removed struct members
# When a struct member goes away, the compiler finds every reader it
# compiles. The readers it does not compile are the ones no Linux box
# sees - the Objective-C drivers above all, and anything behind a
# platform #ifdef - so each of those is found by whichever job builds
# that platform, one round trip at a time.
#
# window_position_x and window_position_y went that way. Packing the
# pair into one word updated the Win32 and SDL3 users, which is what a
# grep of the .c and .h files turns up; ui_cocoa.m kept reading both
# and took out the macOS job and both PowerPC cross jobs at once. Those
# three are among the slowest jobs in the tree, and the answer they
# eventually gave was four lines in one file.
#
# tools/packed_field_check.py does not cover this. It knows the six
# names a size or origin pair is spelled with, and window_position_x is
# not one of them; on the broken tree it printed 1184 lines, none of
# them ui_cocoa.m. The question here is not what a member is called,
# it is whether anything still reaches for one the change took away.
#
# So this lane reads the change rather than the tree's vocabulary: the
# members a push or a pull request removes, minus the ones something
# still declares, against every reader in every language the tree is
# written in. It reads files rather than building them, so one job
# covers what the platform jobs between them would only find one at a
# time.
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
removed-member-check:
name: readers of a removed member
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v5
with:
# Both ends of the range have to be present, and a pull
# request's base can be behind by any amount.
fetch-depth: 0
- name: Checker self-test
shell: bash
run: |
set -eu
# Fixture pass: a member removed along with its readers is
# clean, one left behind in a language no lane here compiles
# is caught, and a member that merely moved, one whose name
# another struct still declares, one that was renamed, one
# named only in a comment or a log string, one declared in a
# declarator list, and a name too common to reason about are
# each left alone.
#
# The fixtures are handed to the checker directly rather than
# taken from the tree, so this reports the same thing whether
# or not the tree currently passes - it measures the checker.
python3 tools/removed_member_check.py --selftest
- name: Range check
shell: bash
run: |
set -eu
# A pull request is measured against its base; a push against
# what was there before it. A force push or a first push
# leaves 'before' as zeroes, and a merge has more than one
# parent, so fall back to the first parent in either case.
if [ -n "${PR_BASE:-}" ]; then
base="$PR_BASE"; head="$PR_HEAD"
else
base="${EVENT_BEFORE:-}"; head="$GITHUB_SHA"
case "$base" in
''|*[!0]*) ;;
*) base= ;;
esac
if [ -z "$base" ] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
base="$(git rev-parse "$head^" 2>/dev/null || true)"
fi
fi
if [ -z "$base" ]; then
echo "no base commit to compare against; nothing to check"
exit 0
fi
echo "range: $base..$head"
# Every struct member the range removes, minus the ones the
# tree still declares somewhere, against every .c .h .m .mm
# .cpp .hpp and .inc reader of one.
python3 tools/removed_member_check.py --range "$base..$head"
env:
PR_BASE: ${{ github.event.pull_request.base.sha }}
PR_HEAD: ${{ github.event.pull_request.head.sha }}
EVENT_BEFORE: ${{ github.event.before }}
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI RetroFW MIPS32
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-dingux:odbeta
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile RA
run: |
+1 -2
View File
@@ -16,10 +16,9 @@ jobs:
build:
name: build
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
submodules: recursive
+1 -7
View File
@@ -2,7 +2,6 @@ name: CI Switch/libnx
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,20 +12,15 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-libnx-devkitpro:v4-10-0
options: --user root
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Compile RA
run: |
+4 -6
View File
@@ -2,7 +2,6 @@ name: CI Wii
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,14 +12,9 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-devkitpro:latest
options: --user root
@@ -37,3 +31,7 @@ jobs:
run: |
make -f Makefile.wii -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.wii -j$(getconf _NPROCESSORS_ONLN) EXTERNAL_LIBOGC=1 GX_PTHREAD_LEGACY=0 HAVE_STATIC_DUMMY=1 info all
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
+3 -6
View File
@@ -2,7 +2,6 @@ name: CI WiiU
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,14 +12,9 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-wiiu:latest
options: --user root
@@ -37,3 +31,6 @@ jobs:
run: |
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info all
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
+3 -123
View File
@@ -2,22 +2,9 @@ name: CI Windows ARM64 (MSVC)
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
release:
types: [published]
workflow_dispatch:
inputs:
release_tag:
description: Existing release tag to build (empty builds the selected ref)
type: string
default: ''
publish_release:
description: Upload the ARM64 package to the existing release
type: boolean
default: false
permissions:
contents: read
@@ -25,16 +12,9 @@ permissions:
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.release_tag || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
msvc:
runs-on: windows-11-arm
timeout-minutes: 90
outputs:
release_tag: ${{ steps.source.outputs.release_tag }}
strategy:
matrix:
version: [2022]
@@ -42,30 +22,7 @@ jobs:
platform: [ARM64]
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event.release.tag_name || inputs.release_tag || github.ref }}
- name: Record and verify the source revision
id: source
shell: pwsh
env:
RELEASE_TAG: ${{ github.event.release.tag_name || inputs.release_tag }}
PUBLISH_RELEASE: ${{ github.event_name == 'release' || inputs.publish_release == true }}
run: |
$revision = git rev-parse HEAD
if ($LASTEXITCODE) { throw 'Could not resolve the source revision.' }
"revision=$revision" >> $env:GITHUB_OUTPUT
if ($env:PUBLISH_RELEASE -eq 'true' -and !$env:RELEASE_TAG) {
throw 'Publishing requires an existing release tag.'
}
if ($env:RELEASE_TAG) {
$tagRevision = git rev-parse --verify "refs/tags/$($env:RELEASE_TAG)^{commit}"
if ($LASTEXITCODE -or $tagRevision -ne $revision) {
throw 'The checkout is not the requested release tag.'
}
}
"release_tag=$env:RELEASE_TAG" >> $env:GITHUB_OUTPUT
- uses: actions/checkout@v4
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1
@@ -77,88 +34,11 @@ jobs:
- name: Get short SHA
id: slug
shell: pwsh
env:
SOURCE_REVISION: ${{ steps.source.outputs.revision }}
run: echo "sha8=$($env:SOURCE_REVISION.Substring(0,8))" >> $env:GITHUB_OUTPUT
shell: powershell
run: echo "sha8=$('${{ github.sha }}'.Substring(0,8))" >> $env:GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with:
name: retroarch-${{ matrix.version }}-${{ matrix.configuration }}-${{ matrix.platform }}-${{ steps.slug.outputs.sha8 }}
path: |
pkg/msvc/${{ matrix.platform }}/${{ matrix.configuration }}/RetroArch-msvc${{ matrix.version }}.exe
- name: Checkout packaging tools from the workflow revision
if: matrix.configuration == 'Release'
uses: actions/checkout@v5
with:
ref: ${{ github.workflow_sha }}
path: .arm64-packaging
sparse-checkout: pkg/msvc/packaging
- name: Checkout pinned Ozone assets
if: matrix.configuration == 'Release'
uses: actions/checkout@v5
with:
repository: libretro/retroarch-assets
ref: 73106363e14e34c08a5854b4cfbc29f184e3b783
path: .arm64-assets
sparse-checkout: |
ozone
pkg
fonts
- name: Checkout pinned core information
if: matrix.configuration == 'Release'
uses: actions/checkout@v5
with:
repository: libretro/libretro-super
ref: 0532bd63ce3072f50ca4f4ada40d42aef565bd3f
path: .arm64-info
sparse-checkout: dist/info
- name: Verify and package ARM64 frontend
if: matrix.configuration == 'Release'
shell: pwsh
env:
SOURCE_REVISION: ${{ steps.source.outputs.revision }}
run: |
./.arm64-packaging/pkg/msvc/packaging/package-arm64.ps1 `
-Executable ./pkg/msvc/ARM64/Release/RetroArch-msvc2022.exe `
-SourceDirectory . -AssetsDirectory ./.arm64-assets -InfoDirectory ./.arm64-info `
-OutputDirectory ./arm64-dist -SourceRevision $env:SOURCE_REVISION `
-Repository $env:GITHUB_REPOSITORY `
-AssetsRevision 73106363e14e34c08a5854b4cfbc29f184e3b783 `
-InfoRevision 0532bd63ce3072f50ca4f4ada40d42aef565bd3f
- name: Upload ARM64 release package
if: matrix.configuration == 'Release'
uses: actions/upload-artifact@v4
with:
name: retroarch-windows-arm64-package
path: |
arm64-dist/RetroArch-WinARM64.zip
arm64-dist/RetroArch-WinARM64.zip.sha256
if-no-files-found: error
upload-release:
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.publish_release == true)
needs: msvc
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
name: retroarch-windows-arm64-package
path: arm64-dist
- name: Attach ARM64 package to the existing release
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ needs.msvc.outputs.release_tag }}
run: |
gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" > /dev/null
gh release upload "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --clobber \
arm64-dist/RetroArch-WinARM64.zip arm64-dist/RetroArch-WinARM64.zip.sha256
+5 -7
View File
@@ -2,7 +2,6 @@ name: CI Windows i686 (MXE)
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,16 +12,11 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-mxe-win32-cross:gcc16
image: reallibretroretroarch/libretro-build-mxe-win32-cross:gcc10
options: --user root
steps:
@@ -34,3 +28,7 @@ jobs:
./configure --host=i686-w64-mingw32.shared
make clean
make -j$(getconf _NPROCESSORS_ONLN)
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
-100
View File
@@ -1,100 +0,0 @@
name: CI Windows (memmap area)
# The fastmem window's reservation has two implementations and a Windows
# runner only ever exercises one of them. From Windows 10 1803 the area is
# a placeholder that mapping splits and unmapping coalesces; below that --
# back to Windows 2000 -- it is one reservation per allocation-granularity
# slot, released and mapped over one slot at a time. Every hosted runner is
# far past 1803, so the legacy path never runs unless it is asked for, and
# MEMSHM_AREA_FORCE_LEGACY is how it is asked for.
#
# It is worth running because its failures are quiet. A placeholder split
# that loses a range, or a slot released and not put back, does not crash:
# it maps the wrong memory, or maps nothing and lets a later map land
# somewhere else. A core with a guest RAM behind that reads and writes the
# wrong addresses.
on:
push:
branches: [master]
paths:
- 'libretro-common/memmap/**'
- 'libretro-common/include/memmap.h'
- 'libretro-common/samples/memmap/**'
- '.github/workflows/Windows-memmap-area.yml'
pull_request:
paths:
- 'libretro-common/memmap/**'
- 'libretro-common/include/memmap.h'
- 'libretro-common/samples/memmap/**'
- '.github/workflows/Windows-memmap-area.yml'
repository_dispatch:
types: [run_build]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
area:
runs-on: windows-2022
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
# The path this runner takes on its own.
- name: placeholders
defines: ''
# And the one every Windows before 10 1803 takes.
- name: legacy
defines: '-DMEMSHM_AREA_FORCE_LEGACY'
name: ${{ matrix.name }}
steps:
- uses: actions/checkout@v5
- name: Report the runner's Windows build
shell: powershell
run: |
$v = [System.Environment]::OSVersion.Version
Write-Host "Windows $($v.Major).$($v.Minor) build $($v.Build)"
if ($v.Build -lt 17134) {
Write-Host "::notice::Runner predates 10 1803; the placeholder job tests the legacy path too"
}
# vcvarsall through vswhere, which ships with every Visual Studio and
# needs no third-party action: this repo uses only
# microsoft/setup-msbuild, and one job is not a reason to add
# another dependency to the supply chain.
- name: Build the area sample
shell: cmd
run: |
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set VSPATH=%%i
if not defined VSPATH exit /b 1
call "%VSPATH%\VC\Auxiliary\Build\vcvars64.bat"
cd libretro-common\samples\memmap\memshm_area_test
cl /nologo /W3 /WX /I..\..\..\include ${{ matrix.defines }} ^
memshm_area_test.c ..\..\..\memmap\memmap.c ^
/Fe:memshm_area_test.exe
if errorlevel 1 exit /b 1
# The sample's own exit code covers the assertions. This also fails
# a run that reported no area at all: that is a pass for a platform
# which cannot have one, and a silent no-op on a runner that can.
- name: Run it, and fail if the area was skipped
shell: powershell
run: |
cd libretro-common\samples\memmap\memshm_area_test
$out = & .\memshm_area_test.exe | Out-String
Write-Host $out
if ($out -match 'skipped') {
Write-Error "no area on a runner that must be able to provide one"
exit 1
}
if ($out -notmatch 'memshm area: ok') {
Write-Error "the sample did not report ok"
exit 1
}
+5 -7
View File
@@ -2,7 +2,6 @@ name: CI Windows x64 (MXE)
on:
push:
branches: [master]
pull_request:
repository_dispatch:
types: [run_build]
@@ -13,16 +12,11 @@ permissions:
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-latest
timeout-minutes: 30
container:
image: reallibretroretroarch/libretro-build-mxe-win64-cross:gcc16
image: reallibretroretroarch/libretro-build-mxe-win64-cross:gcc10
options: --user root
steps:
@@ -34,3 +28,7 @@ jobs:
./configure --host=x86_64-w64-mingw32.shared
make clean
make -j$(getconf _NPROCESSORS_ONLN)
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
+1 -2
View File
@@ -14,7 +14,6 @@ jobs:
permissions:
contents: write # for Git to git push
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Setup Java JDK
uses: actions/setup-java@v4
@@ -26,7 +25,7 @@ jobs:
with:
python-version: '3.10'
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Crowdin Sync
shell: bash
env:
+1 -2
View File
@@ -16,7 +16,6 @@ permissions:
jobs:
sync:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Setup Java JDK
uses: actions/setup-java@v4
@@ -28,7 +27,7 @@ jobs:
with:
python-version: '3.10'
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Crowdin Sync
shell: bash
env:
-6
View File
@@ -2,7 +2,6 @@ name: CI iOS (13)
on:
push:
branches: [master]
pull_request:
permissions:
@@ -11,14 +10,9 @@ permissions:
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: macos-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
-141
View File
@@ -1,141 +0,0 @@
name: CI procbarrier tiers
# retro_procbarrier picks one of several ways to force a memory barrier
# on every running thread, and which one depends on the OS and the CPU.
# The Linux samples job only ever runs the one its runner picks
# (membarrier). This runs every tier each platform has, on a multi-core
# runner so the fence checks can actually catch a missing barrier, and
# fails if a forced tier quietly fell back to another one.
#
# Linux x86_64 membarrier, page-flip, signal
# Linux arm64 membarrier, signal
# Windows x64 FlushProcessWriteBuffers, page-flip
# Windows arm64 FlushProcessWriteBuffers
# macOS arm64 signal
# macOS x86_64 page-flip, signal
on:
push:
branches: [master]
paths:
- 'libretro-common/rthreads/**'
- 'libretro-common/include/rthreads/**'
- 'libretro-common/include/retro_atomic.h'
- 'libretro-common/samples/rthreads/retro_procbarrier_test/**'
- 'libretro-common/samples/rthreads/retro_asym_eventcount_test/**'
- '.github/workflows/procbarrier-tiers.yml'
pull_request:
paths:
- 'libretro-common/rthreads/**'
- 'libretro-common/include/rthreads/**'
- 'libretro-common/include/retro_atomic.h'
- 'libretro-common/samples/rthreads/retro_procbarrier_test/**'
- 'libretro-common/samples/rthreads/retro_asym_eventcount_test/**'
- '.github/workflows/procbarrier-tiers.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
posix:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- name: linux-x86_64
os: ubuntu-latest
libs: -lpthread -lrt
tiers: natural=membarrier membarrier=membarrier pageflip=page-flip signal=signal
- name: linux-arm64
os: ubuntu-24.04-arm
libs: -lpthread -lrt
tiers: natural=membarrier membarrier=membarrier signal=signal
- name: macos-arm64
os: macos-latest
libs: -lpthread
tiers: natural=signal signal=signal
- name: macos-x86_64
os: macos-15-intel
libs: -lpthread
tiers: natural=page-flip pageflip=page-flip signal=signal
steps:
- uses: actions/checkout@v5
- name: Build
working-directory: libretro-common
run: |
set -e
cc -std=gnu99 -O1 -g -Wall -DHAVE_THREADS -Iinclude \
samples/rthreads/retro_procbarrier_test/retro_procbarrier_test.c \
rthreads/retro_procbarrier.c rthreads/rthreads.c \
-o retro_procbarrier_test ${{ matrix.libs }}
cc -std=gnu99 -O1 -g -Wall -DHAVE_THREADS -Iinclude \
samples/rthreads/retro_asym_eventcount_test/retro_asym_eventcount_test.c \
rthreads/retro_asym_eventcount.c \
rthreads/retro_procbarrier.c rthreads/rthreads.c \
-o retro_asym_eventcount_test ${{ matrix.libs }}
- name: Run every tier
working-directory: libretro-common
env:
REQUIRE_SMP: 1
run: |
bash samples/rthreads/retro_procbarrier_test/run_tiers.sh \
./retro_procbarrier_test ./retro_asym_eventcount_test \
${{ matrix.tiers }}
windows:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- name: windows-x64
os: windows-2022
vcvars: vcvars64.bat
tiers: natural=FlushProcessWriteBuffers fpwb=FlushProcessWriteBuffers pageflip=page-flip
- name: windows-arm64
os: windows-11-arm
vcvars: vcvarsarm64.bat
tiers: natural=FlushProcessWriteBuffers fpwb=FlushProcessWriteBuffers
steps:
- uses: actions/checkout@v5
- name: Build
shell: cmd
working-directory: libretro-common
run: |
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -property installationPath`) do set VSPATH=%%i
if not defined VSPATH exit /b 1
call "%VSPATH%\VC\Auxiliary\Build\${{ matrix.vcvars }}"
cl /nologo /W3 /O1 /DHAVE_THREADS /Iinclude ^
samples\rthreads\retro_procbarrier_test\retro_procbarrier_test.c ^
rthreads\retro_procbarrier.c rthreads\rthreads.c ^
/Fe:retro_procbarrier_test.exe
if errorlevel 1 exit /b 1
cl /nologo /W3 /O1 /DHAVE_THREADS /Iinclude ^
samples\rthreads\retro_asym_eventcount_test\retro_asym_eventcount_test.c ^
rthreads\retro_asym_eventcount.c ^
rthreads\retro_procbarrier.c rthreads\rthreads.c ^
/Fe:retro_asym_eventcount_test.exe
if errorlevel 1 exit /b 1
- name: Run every tier
shell: bash
working-directory: libretro-common
env:
REQUIRE_SMP: 1
run: |
bash samples/rthreads/retro_procbarrier_test/run_tiers.sh \
./retro_procbarrier_test.exe ./retro_asym_eventcount_test.exe \
${{ matrix.tiers }}
+3 -42
View File
@@ -16,55 +16,16 @@ permissions:
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:
linux-c89: # Smoketest build using most restrictive compiler and default options
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Dependencies
timeout-minutes: 20
run: |
# libvulkan-dev brings the Vulkan driver, the slang shader stack
# (shader_vulkan.c, slang_process.c, glslang_util.c, slang_cache.c)
# and the Vulkan contexts into this lane; without it configure
# drops them and none of those C files ever meet -std=c89.
pkgs="build-essential libxkbcommon-dev libx11-xcb-dev libvulkan-dev zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev nvidia-cg-toolkit nvidia-cg-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 || true
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
sudo apt-get update -y
sudo apt-get install build-essential libxkbcommon-dev libx11-xcb-dev zlib1g-dev libfreetype6-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev nvidia-cg-toolkit nvidia-cg-dev libavcodec-dev libsdl2-dev libsdl-image1.2-dev libxml2-dev yasm
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Configure
run: ./configure
- name: Build
+3 -959
View File
@@ -19,42 +19,22 @@ cd "$(dirname "$0")/../../.."
CC=${CC:-gcc}
INC="-I. -Ilibretro-common/include -Ideps -Ideps/rcheevos/include -Iinput/include"
WARN="-Wall -Wno-unused-function -Werror=implicit-function-declaration"
# gcc 14 rejects these outright and older gcc only warns; a lane on
# an older compiler has to reject them too, or a mismatched callback
# passes here and fails on the toolchains that build the platform.
WARN="$WARN -Werror=incompatible-pointer-types -Werror=int-conversion"
BASE="-DRARCH_INTERNAL -DHAVE_AUDIOMIXER -DHAVE_THREADS -DHAVE_CONFIGFILE -DHAVE_MENU"
# A console lane that keeps the host identity takes the Linux branch
# of every #if ladder and proves nothing, so this sits above the
# lanes rather than among them.
HOSTOFF="-U__linux__ -U__gnu_linux__ -Ulinux -U__unix__ -U__unix -Uunix"
fail=0
# A failing compile's output, errors first: a file with a page of
# warnings ahead of its one error pushed the error past the cut, which
# left a failing lane reporting nothing to act on.
show_out() {
if echo "$1" | grep -q ": error: "; then
echo "$1" | grep ": error: " | sed 's/^/ /' | head -8
else
echo "$1" | sed 's/^/ /' | head -12
fi
}
check() {
name="$1"; shift
defs="$1"; shift
bad=0
for tu in "$@"; do
if ! out=$($CC $WARN $INC $BASE $defs -fsyntax-only "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1; bad=1
echo "$out" | sed 's/^/ /' | head -12
fail=1
fi
done
[ "$bad" = 1 ] || echo "ok $name"
[ "$fail" = 1 ] || echo "ok $name"
}
AUDIO="libretro-common/formats/audio_transfer.c libretro-common/audio/audio_mixer.c"
@@ -106,33 +86,6 @@ STUBS="$(dirname "$0")/stubs"
# host headers are the real ones and deprecate things the target's do not
ARMWARN="$WARN -Wno-deprecated-declarations"
# A platform's own video driver, which the arm lanes above do not reach:
# they check that one file's headers resolve, not that the driver a
# console actually draws with still compiles. Settings a driver reads
# while answering the frontend have moved into the frame descriptor more
# than once, and each time these drivers were the ones left behind -
# nothing in CI compiles them.
#
# @extra carries whatever headers the driver needs that the runner has;
# a lane whose headers are absent says so and is not a failure.
platform_video() {
name="$1"; defs="$2"; extra="$3"; tu="$4"; probe="$5"
for pr in $probe; do
if [ ! -f "$pr" ]; then
echo "skip $name (no $pr)"
return
fi
done
if ! out=$($CC $WARN $extra $INC $BASE $defs -fsyntax-only "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1
else
echo "ok $name"
fi
}
arm() {
name="$1"; stub="$2"; defs="$3"
inc="$INC"
@@ -160,920 +113,11 @@ arm "orbis" orbis "-DORBIS"
arm "ps3" ps3 "-D__PSL1GHT__ -DHAVE_MEMINFO"
arm "ps2" "" "-DPS2"
arm "emscripten" emscripten "-D__EMSCRIPTEN__"
# The consoles that carry the cleanroom crypto, keychain and TLS client
# (3DS, Vita, Switch), each in its own shape with the SDK stand-ins the
# random source and the socket layer need. Vita's and the 3DS's socket
# layers are the SDKs' own, so the TLS client itself is compiled only
# in the Switch shape here; those two builds are their workflows' to
# link.
CRYPTO_SET="libretro-common/crypto/crypto.c libretro-common/crypto/kdf.c libretro-common/crypto/pk.c libretro-common/crypto/x509.c libretro-common/file/keychain.c"
TLS_SET="$CRYPTO_SET libretro-common/net/net_socket_ssl_retro.c network/tls_log.c"
CONSOLE_NET="-DHAVE_CRYPTO -DHAVE_KEYCHAIN -DHAVE_SSL -DHAVE_RETROSSL -DHAVE_NETWORKING -DHAVE_THREADS -DHAVE_CONFIGFILE -DRARCH_INTERNAL"
console_set() {
cs_name="$1"; cs_inc="$2"; cs_defs="$3"; shift 3
for cs_tu in "$@"; do
check "$cs_name: $(basename $cs_tu)" "$HOSTOFF $cs_inc $CONSOLE_NET $cs_defs $CDECL" "$cs_tu"
done
}
console_set "3ds crypto" "-Itools/platform_stubs/ctr" "-D_3DS -DARM11" $CRYPTO_SET
console_set "vita crypto" "-Itools/platform_stubs/vita" "-DVITA" $CRYPTO_SET
console_set "switch tls" "-I$STUBS/libnx" "-DHAVE_LIBNX -DSWITCH -D__SWITCH__" $TLS_SET
# The built-in NFS client, which the 3DS, Vita, Switch and Wii U
# build, under the defines their Makefiles set (RARCH_CONSOLE for the
# console sleep and the 3DS transfer cap, Vita's legacy socket layer):
# Wii U against its own wiiu/include, Vita against stubs of vitasdk's
# socket headers.
NFS_SET="libretro-common/net/net_nfs3.c libretro-common/vfs/vfs_implementation_nfs.c libretro-common/vfs/vfs_prefetch.c"
NFSD="-DHAVE_RETRONFS -DHAVE_NFSCLIENT"
console_set "3ds nfs" "-Itools/platform_stubs/ctr $NFSD" "-D_3DS -DARM11 -DRARCH_CONSOLE" $NFS_SET
console_set "vita nfs" "-Itools/platform_stubs/vita $NFSD" "-DVITA -DRARCH_CONSOLE -DHAVE_SOCKET_LEGACY" $NFS_SET
console_set "switch nfs" "-I$STUBS/libnx $NFSD" "-DHAVE_LIBNX -DSWITCH -D__SWITCH__ -DRARCH_CONSOLE" $NFS_SET
console_set "wiiu nfs" "-Iwiiu/include -Itools/platform_stubs/wiiu $NFSD" "-DWIIU -D__WUT__ -DHW_WUP -D__wiiu__ -DRARCH_CONSOLE" $NFS_SET
# The built-in SMB and Kerberos clients, which the 3DS, Vita and Switch
# build on their crypto (the Wii U has no kernel RNG for it to draw on).
SMB_SET="libretro-common/net/net_smb2.c libretro-common/net/net_krb5.c libretro-common/vfs/vfs_implementation_smb.c"
SMBD="-DHAVE_RETROSMB -DHAVE_SMBCLIENT"
console_set "3ds smb" "-Itools/platform_stubs/ctr $SMBD" "-D_3DS -DARM11 -DRARCH_CONSOLE" $SMB_SET
console_set "vita smb" "-Itools/platform_stubs/vita $SMBD" "-DVITA -DRARCH_CONSOLE -DHAVE_SOCKET_LEGACY" $SMB_SET
console_set "switch smb" "-I$STUBS/libnx $SMBD" "-DHAVE_LIBNX -DSWITCH -D__SWITCH__ -DRARCH_CONSOLE" $SMB_SET
# The network stack in the old MSVC projects (2005 - 2017), which no job
# here builds: 32-bit Windows, C89, at the Windows floors those projects
# target - VS2005's _WIN32_WINNT 0x0410 and XP's 0x0501. The stack keeps
# to what those compilers and SDKs have: C89, the LL/ULL suffixes code
# they already build uses, Windows entry points resolved at run time,
# and a CA bundle split into parts under MSVC's 64 KiB string limit.
MSVC_OLD_CC=${MSVC_OLD_CC:-i686-w64-mingw32-gcc}
if command -v "$MSVC_OLD_CC" > /dev/null 2>&1; then
MSVC_OLD_STACK="$CRYPTO_SET libretro-common/net/net_socket_ssl_retro.c network/tls_log.c libretro-common/net/net_smb2.c libretro-common/net/net_krb5.c libretro-common/net/net_nfs3.c libretro-common/vfs/vfs_implementation_smb.c libretro-common/vfs/vfs_implementation_nfs.c libretro-common/vfs/vfs_prefetch.c"
MSVC_OLD_DEFS="-DRARCH_INTERNAL -DHAVE_NETWORKING -DHAVE_THREADS -DHAVE_CONFIGFILE -DHAVE_CRYPTO -DHAVE_KEYCHAIN -DHAVE_SSL -DHAVE_RETROSSL -DHAVE_SMBCLIENT -DHAVE_RETROSMB -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DLEGACY_WIN32_NO_MIGRATION_NOTE"
for winnt in 0x0410 0x0501; do
mo_bad=0
for tu in $MSVC_OLD_STACK; do
if ! out=$($MSVC_OLD_CC -std=c89 -ansi -pedantic -Werror=pedantic -Werror=declaration-after-statement -Wno-long-long -Wno-variadic-macros -Werror=implicit-function-declaration -Wall -Wno-unused-function -Wno-overlength-strings \
-I. -Ilibretro-common/include -D_WIN32_WINNT=$winnt $MSVC_OLD_DEFS -fsyntax-only "$tu" 2>&1) \
|| echo "$out" | grep -q "warning:"; then
echo "FAIL msvc-old network stack, _WIN32_WINNT=$winnt"
echo " $tu"
show_out "$out"
fail=1; mo_bad=1
fi
done
[ "$mo_bad" = 1 ] || echo "ok msvc-old network stack, _WIN32_WINNT=$winnt"
done
# and no single string literal in the CA bundle reaches MSVC's limit
if python3 - << 'PYEOF'
import re, sys
t = open("libretro-common/net/cacert.h", encoding="latin-1").read()
for body in re.findall(r"\[\] = \{(.*?)\};", t, re.S):
lits = re.findall(r'"((?:[^"\\]|\\.)*)"', body)
size = sum(len(l.encode("latin-1").decode("unicode_escape")) for l in lits) + len(lits)
if size >= 65535:
sys.exit(1)
PYEOF
then
echo "ok cacert.h parts under MSVC's 64 KiB string limit"
else
echo "FAIL cacert.h has a part at or over MSVC's 64 KiB string limit"; fail=1
fi
else
echo "skip msvc-old network stack (no $MSVC_OLD_CC)"
fi
# Every platform makefile on Makefile.common, without its toolchain: the
# graph's own DEFINES checked for consistency (TLS, SMB, NFS need the
# networking they are built on) and the frontend compiled under exactly
# them. Makefile.retrofw asked for the TLS client with no networking
# and only its own workflow saw the undefined reference.
pm_out=$(tools/platform_makefile_check.sh 2>&1); pm_rc=$?
printf '%s\n' "$pm_out" | sed 's/^ok /ok platform makefile: /'
[ $pm_rc -eq 0 ] || { echo "FAIL platform makefile check"; fail=1; }
# What each console Makefile actually builds, from its own object list:
# no MCP server on any console (a desktop HAVE_MCP option; listed once
# with the networking objects it broke the 3DS), and no crypto library
# on the 24/32 MiB machines.
co_out=$(tools/console_objects_check.sh 2>&1); co_rc=$?
printf '%s\n' "$co_out" | sed 's/^ok /ok console objects: /'
[ $co_rc -eq 0 ] || { echo "FAIL console object check"; fail=1; }
# The OpenDingux family builds with a MIPS toolchain; the crypto and the
# TLS client compile with a MIPS cross compiler when one is installed.
MIPSEL_CC=${MIPSEL_CC:-mipsel-linux-gnu-gcc}
if command -v "$MIPSEL_CC" >/dev/null 2>&1; then
for tu in $TLS_SET; do
if out=$($MIPSEL_CC -march=mips32r2 $INC $CONSOLE_NET -DDINGUX -D_GNU_SOURCE -Wall -Werror -Wno-unused-function -fsyntax-only "$tu" 2>&1); then
echo "ok dingux mips: $(basename $tu)"
else
echo "FAIL dingux mips: $(basename $tu)"; show_out "$out"; fail=1
fi
done
else
echo "skip dingux mips (no $MIPSEL_CC)"
fi
platform_video "odroidgo2 video" \
"-DHAVE_ODROIDGO2 -DHAVE_OPENGL -DHAVE_GLSL" "" \
gfx/drivers/gl2.c ""
platform_video "gx video" "-DGEKKO -DHW_RVL" "-I$STUBS/gx" \
gfx/drivers/gx_gfx.c ""
platform_video "switch video" \
"-DHAVE_LIBNX -DSWITCH -D__SWITCH__" "-I$STUBS/libnx" \
gfx/drivers/switch_nx_gfx.c ""
# The PSP driver folds its VRAM and cache-alias addresses into pointers,
# which a 64-bit host narrows; the arithmetic is 32-bit on the target.
platform_video "psp1 video" "-DPSP" \
"-Itools/platform_stubs/psp -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast \
-Wdeclaration-after-statement -Werror=declaration-after-statement" \
gfx/drivers/psp1_gfx.c ""
# The Vita driver, against psp2 stubs carrying the SceGxm declarations it
# names in the shapes the real headers give them. Same narrowing as the
# PSP driver above: its pool addresses are 32-bit on the target.
platform_video "gxm video" "-DVITA -DRARCH_CONSOLE $HOSTOFF" \
"-Itools/platform_stubs/vita -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast" \
gfx/drivers/gxm_gfx.c ""
# gl1 on Vita, against a vitaGL stub over the host GL headers. The
# driver's Vita branches are compiled nowhere else, and one of them
# carried a declaration after a statement that only the Vita job saw.
platform_video "vita gl1 video" \
"-DVITA -DRARCH_CONSOLE -DHAVE_OPENGL1 -DHAVE_OVERLAY -DHAVE_GFX_WIDGETS $HOSTOFF" \
"-Itools/platform_stubs/vita -Wdeclaration-after-statement \
-Werror=declaration-after-statement" \
gfx/drivers/gl1.c /usr/include/GL/gl.h
# The PS2 driver, against gsKit and PS2SDK stubs carrying what it
# names in the shapes the real headers give them. Makefile.ps2 turns on
# the window offset, which the driver reads. This lane is also the only
# one that compiles retro_atomic.h's EE interrupt-mask backend, which
# no other platform selects.
platform_video "ps2 video" \
"-DPS2 -DRARCH_CONSOLE -DHAVE_WINDOW_OFFSET -DHAVE_RGUI $HOSTOFF" \
"-Itools/platform_stubs/ps2" gfx/drivers/ps2_gfx.c ""
# The DOS VGA driver, against DJGPP stubs for the DPMI and port I/O it
# uses. Only the DJGPP job compiled it before; DJGPP defines __unix__.
platform_video "dos vga video" \
"-D__DJGPP__ -DDJGPP -DRARCH_CONSOLE $HOSTOFF -D__unix__" \
"-Itools/platform_stubs/dos -Wdeclaration-after-statement \
-Werror=declaration-after-statement" \
gfx/drivers/vga_gfx.c ""
# The two SDL video drivers. Nothing else here compiled them, which is
# how a field they read through video_info_t went on being read after it
# had been packed away. Each skips where its headers are absent, as the
# dingux lanes below do.
platform_video "sdl2 video" "-DHAVE_SDL2" "-I/usr/include/SDL2" \
gfx/drivers/sdl2_gfx.c /usr/include/SDL2/SDL.h
platform_video "sdl3 video" "-DHAVE_SDL3" "-I/usr/include/SDL3" \
gfx/drivers/sdl3_gfx.c /usr/include/SDL3/SDL.h
platform_video "dingux video" "-DDINGUX" "-I/usr/include/SDL" \
gfx/drivers/sdl_dingux_gfx.c /usr/include/SDL/SDL.h
platform_video "rs90 video" "-DDINGUX -DRS90" "-I/usr/include/SDL" \
gfx/drivers/sdl_rs90_gfx.c /usr/include/SDL/SDL.h
# libdrm's exynos module and its G2D headers, which distros ship only
# where the hardware exists. A runner building libdrm with -Dexynos=true
# turns this on.
platform_video "wiiu gx2 video" "-DWIIU $HOSTOFF" \
"-Iwiiu/include -Iwiiu" gfx/drivers/gx2_gfx.c ""
platform_video "hub75 video" "" "" gfx/drivers/hub75_gfx.c ""
platform_video "openvg video" "-DHAVE_VG -DHAVE_EGL" \
"-Itools/platform_stubs/openvg" gfx/drivers/vg.c ""
platform_video "exynos video" "-DHAVE_EXYNOS" "-I/usr/include/libdrm" \
gfx/drivers/exynos_gfx.c /usr/include/exynos/exynos_fimg2d.h
# The Direct3D drivers, against the DirectX headers the tree vendors in
# gfx/include/dxsdk. Six drivers no other lane compiles, and they read
# the same frame and draw descriptors every other video driver does.
#
# A mingw-w64 cross compiler is all these need beyond the tree; where
# there is none the lanes say so rather than fail.
MINGW_CC=${MINGW_CC:-x86_64-w64-mingw32-gcc}
d3d_video() {
name="$1"; defs="$2"; tu="$3"
if ! command -v "$MINGW_CC" > /dev/null 2>&1; then
echo "skip $name (no $MINGW_CC)"
return
fi
if ! out=$($MINGW_CC $WARN -isystemgfx/include/dxsdk $INC $BASE $defs \
-fsyntax-only "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1
else
echo "ok $name"
fi
}
D3DDEFS="-DHAVE_D3D -DHAVE_RGUI -DHAVE_OVERLAY"
d3d_video "d3d8 video" "$D3DDEFS -DHAVE_D3D8" gfx/drivers/d3d8.c
d3d_video "d3d9 video, Cg" "$D3DDEFS -DHAVE_D3D9" gfx/drivers/d3d9cg.c
d3d_video "d3d9 video, HLSL" "$D3DDEFS -DHAVE_D3D9" gfx/drivers/d3d9hlsl.c
d3d_video "d3d10 video" "$D3DDEFS -DHAVE_D3D10" gfx/drivers/d3d10.c
d3d_video "d3d11 video" "$D3DDEFS -DHAVE_D3D11" gfx/drivers/d3d11.c
d3d_video "d3d12 video" "$D3DDEFS -DHAVE_D3D12" gfx/drivers/d3d12.c
d3d_video "gdi video" "-DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_GDI" \
gfx/drivers/gdi_gfx.c
# The context drivers, which no job here compiles either. Each answers
# the frontend's window and size questions, so a change to what those
# hand back reaches all of them at once. Every lane names the headers it
# wants and says so when the runner has none.
platform_video "ctx: null" "" "" gfx/drivers_context/gfx_null_ctx.c ""
platform_video "ctx: x11 gl" "-DHAVE_X11 -DHAVE_OPENGL -DHAVE_EGL" "" \
gfx/drivers_context/x_ctx.c /usr/include/X11/Xlib.h
platform_video "ctx: x11 egl" "-DHAVE_X11 -DHAVE_EGL -DHAVE_OPENGLES" "" \
gfx/drivers_context/xegl_ctx.c /usr/include/X11/Xlib.h
platform_video "ctx: x11 vulkan" "-DHAVE_VULKAN -DHAVE_X11 -DHAVE_XCB" "" \
gfx/drivers_context/x_vk_ctx.c \
"/usr/include/vulkan/vulkan.h /usr/include/X11/Xlib-xcb.h"
platform_video "ctx: khr display" "-DHAVE_VULKAN" "" \
gfx/drivers_context/khr_display_ctx.c /usr/include/vulkan/vulkan.h
platform_video "ctx: kms/gbm" "-DHAVE_EGL -DHAVE_OPENGL -DHAVE_KMS -DHAVE_GBM" \
"-I/usr/include/libdrm" gfx/drivers_context/drm_ctx.c /usr/include/gbm.h
# vivante_fbdev is left out: it calls Vivante's own fbCreateWindow and
# fbGetDisplayByIndex, which only that vendor's EGL headers declare, and
# a lane that let those go implicit would pass what the SDK rejects.
platform_video "ctx: mali fbdev" "-DHAVE_EGL -DHAVE_OPENGLES" "" \
gfx/drivers_context/mali_fbdev_ctx.c /usr/include/EGL/egl.h
platform_video "ctx: opendingux fbdev" "-DHAVE_EGL -DHAVE_OPENGLES -DDINGUX" "" \
gfx/drivers_context/opendingux_fbdev_ctx.c /usr/include/EGL/egl.h
platform_video "ctx: sdl1 gl" "-DHAVE_SDL -DHAVE_OPENGL" "-I/usr/include/SDL" \
gfx/drivers_context/sdl1_gl_ctx.c /usr/include/SDL/SDL.h
platform_video "ctx: sdl2 gl" "-DHAVE_SDL2 -DHAVE_OPENGL" "-I/usr/include/SDL2" \
gfx/drivers_context/sdl2_gl_ctx.c /usr/include/SDL2/SDL.h
# osmesa is the software context a headless build selects, and
# qb/config.libs.sh can enable it from a pkg-config probe alone.
platform_video "ctx: osmesa" "-DHAVE_OSMESA -DHAVE_OPENGL" "" \
gfx/drivers_context/osmesa_ctx.c /usr/include/GL/osmesa.h
# The Wayland protocol headers are generated into gfx/common/wayland by
# configure, so these lanes run only in a tree that has been configured
# with Wayland.
WL_H="/usr/include/wayland-client.h gfx/common/wayland/content-type-v1.h"
platform_video "ctx: wayland gl" "-DHAVE_WAYLAND -DHAVE_EGL -DHAVE_OPENGL" "" \
gfx/drivers_context/wayland_ctx.c "$WL_H"
platform_video "ctx: wayland vulkan" "-DHAVE_WAYLAND -DHAVE_VULKAN" "" \
gfx/drivers_context/wayland_vk_ctx.c "$WL_H /usr/include/vulkan/vulkan.h"
# The shared Wayland code the two contexts above call into. It was the
# only Wayland unit no lane compiled, which is how four declarations
# after a statement sat in it. Its libdecor half is a second lane: the
# function pointers that half calls through are declared under
# HAVE_LIBDECOR_H *and* HAVE_DYLIB, so a lane naming only the first
# proves nothing, and the header libdecor.h itself comes from a
# libdecor-0 include directory the probe checks for.
WLC89="-Wdeclaration-after-statement -Werror=declaration-after-statement"
platform_video "wayland common" "-DHAVE_WAYLAND -DHAVE_EGL -DHAVE_OPENGL" \
"$WLC89" gfx/common/wayland_common.c "$WL_H"
platform_video "wayland common: libdecor" \
"-DHAVE_WAYLAND -DHAVE_EGL -DHAVE_OPENGL -DHAVE_LIBDECOR_H -DHAVE_DYLIB" \
"-I/usr/include/libdecor-0 $WLC89" \
gfx/common/wayland_common.c "$WL_H /usr/include/libdecor-0/libdecor.h"
platform_video "wayland common: backport" \
"-DHAVE_WAYLAND -DHAVE_EGL -DHAVE_OPENGL -DHAVE_WAYLAND_BACKPORT=1" \
"$WLC89" gfx/common/wayland_common.c "$WL_H"
# webOS swaps its own shim in for half of the common Wayland functions,
# and the Wayland context reaches it through prototypes of its own, so
# the shim and the context each get a lane. The shim's webOS protocol
# headers are wayland-scanner output of LG's webos-wayland-extensions
# (Apache-2.0), which the SDK generates at build time; stubs/webos keeps
# a copy laid out so the shim's ../../gfx/common/wayland includes find it.
WEBOS="-DWEBOS -DWEBOS_APP_ID=\"com.retroarch\" -DHAVE_WAYLAND -DHAVE_EGL"
WEBOS="$WEBOS -DHAVE_OPENGLES"
platform_video "ctx: wayland gl (webos)" "$WEBOS" "" \
gfx/drivers_context/wayland_ctx.c "$WL_H"
platform_video "webos wayland shim" "$WEBOS" \
"-I$STUBS/webos/gfx/common" \
input/common/wayland_common_webos.c "$WL_H"
arm "win32" win32 "-D_WIN32 -D_WIN32_WINNT=0x0600"
arm "win32-old" win32 "-D_WIN32 -D_WIN32_WINNT=0x0400"
arm "macos" apple "-D__APPLE__"
arm "ios" apple "-D__APPLE__ -DTARGET_OS_IPHONE=1"
# The GL core driver without slang: its HDR encode is slang's, and state
# for it once sat outside the slang guards, which only the C89 lane -
# built without slang - ever compiled.
platform_video "glcore without slang" "-DHAVE_OPENGL -DHAVE_OPENGL_CORE" \
"" gfx/drivers/gl3.c "/usr/include/GL/gl.h"
platform_video "glcore with slang" \
"-DHAVE_OPENGL -DHAVE_OPENGL_CORE -DHAVE_SLANG -DHAVE_SHADERPIPELINE" \
"" gfx/drivers/gl3.c "/usr/include/GL/gl.h"
# The CoreText rasterizer and the font driver's Apple branch, against
# stand-ins for the SDK headers it includes: no runner builds it but the
# Apple jobs, so a change to the rasterizer interface reached them first.
CORETEXT="$HOSTOFF -D__APPLE__ -D__MACH__ -DHAVE_CORETEXT"
platform_video "macos coretext rasterizer" "$CORETEXT" "-I$STUBS/apple" \
gfx/drivers_font_renderer/coretext.c ""
platform_video "ios coretext rasterizer" "$CORETEXT -DTARGET_OS_IPHONE=1" \
"-I$STUBS/apple" gfx/drivers_font_renderer/coretext.c ""
platform_video "macos font driver" "$CORETEXT" "-I$STUBS/apple" \
gfx/font_driver.c ""
arm "dos/djgpp" "" "-D__DJGPP__ -D__unix__"
arm "linux" "" ""
# The video drivers and the threaded wrapper compile under more than
# one API and one threading model, and the desktop job builds one of
# each. The OpenGL ring's sync objects went in under a guard the
# desktop build satisfied and the GLES builds did not, and every GLES
# target - Android, Emscripten, Vita, PS4 - went red at once; a
# threadless build had been broken for longer than anyone noticed, on
# calls that compile against a prototype and fail only at link.
# These lanes are the ones a desktop build does not exercise.
echo
echo "== video drivers: API and threading combinations =="
GLINC="-Igfx/include"
GLDEFS="-DHAVE_OPENGL -DHAVE_GLSL -DHAVE_FBO -DHAVE_REWIND -DHAVE_OVERLAY"
check "gl2: GLES2 (android/emscripten/vita/ps4)" \
"$GLDEFS -DHAVE_OPENGLES -DHAVE_OPENGLES2 -DHAVE_EGL $GLINC" gfx/drivers/gl2.c
check "gl2: GLES3" \
"$GLDEFS -DHAVE_OPENGLES -DHAVE_OPENGLES3 -DHAVE_EGL $GLINC" gfx/drivers/gl2.c
check "gl2: desktop" \
"$GLDEFS $GLINC" gfx/drivers/gl2.c
GL3DEFS="-DHAVE_OPENGL -DHAVE_OPENGL_CORE -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_SPIRV_CROSS -DHAVE_REWIND -DHAVE_OVERLAY -Ideps/SPIRV-Cross"
check "gl3: desktop" \
"$GL3DEFS $GLINC" gfx/drivers/gl3.c
check "gl3: GLES3" \
"$GL3DEFS -DHAVE_OPENGLES -DHAVE_OPENGLES3 -DHAVE_EGL $GLINC" gfx/drivers/gl3.c
# gl3 is not in the C89 job's configuration, so its C89 lane is here.
# The flags the Makefile's C89_BUILD lane uses, _GNU_SOURCE included:
# -ansi hides the C99 math names otherwise.
C89="-std=c89 -ansi -pedantic -Werror=pedantic -Werror=declaration-after-statement -Wno-long-long -Wno-variadic-macros -D_GNU_SOURCE -DC89_BUILD"
check "gl3: desktop, C89" \
"$GL3DEFS $GLINC $C89" gfx/drivers/gl3.c
# Without threads, in C89: audio_driver.h and rthreads.h both reach the
# tasks and the audio driver, and a typedef each declared on its own is
# one C89 refuses twice. make C89_BUILD=1 --disable-threads stopped at
# task_save.c on it; no job builds that shape. check() always adds
# HAVE_THREADS, so this lane spells its defines out.
NOTHREADS_BASE=$(echo "$BASE" | sed 's/-DHAVE_THREADS//')
nt_bad=0
for tu in tasks/task_save.c tasks/task_audio_mixer.c \
audio/audio_driver.c audio/audio_thread_wrapper.c; do
if ! out=$($CC $WARN $INC $NOTHREADS_BASE $C89 -fsyntax-only "$tu" 2>&1); then
echo "FAIL audio + tasks: no threads, C89"
echo " $tu"
show_out "$out"
fail=1; nt_bad=1
fi
done
[ "$nt_bad" = 1 ] || echo "ok audio + tasks: no threads, C89"
# WASAPI is in the Windows C89_BUILD lane, which no job here builds, and
# its error-string helper serves only the microphone path, so both halves
# are compiled: C89 flags, with and without HAVE_MICROPHONE, unused
# functions as errors. A real compile rather than -fsyntax-only, which
# stops before GCC looks for unused static functions.
win32_audio() {
name="$1"; defs="$2"; tu="$3"
if ! command -v "$MINGW_CC" > /dev/null 2>&1; then
echo "skip $name (no $MINGW_CC)"
return
fi
if ! out=$($MINGW_CC $WARN -Wunused-function -Werror=unused-function \
$INC $BASE $C89 \
$defs -c -o /dev/null "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1
else
echo "ok $name"
fi
}
win32_audio "wasapi: C89, microphone" "-DHAVE_WASAPI -DHAVE_MICROPHONE" \
audio/drivers/wasapi.c
win32_audio "wasapi: C89, no microphone" "-DHAVE_WASAPI" \
audio/drivers/wasapi.c
check "hw ring: OpenGL only" \
"-DHAVE_OPENGL $GLINC" gfx/video_thread_hw.c
check "hw ring: GLES only" \
"-DHAVE_OPENGLES -DHAVE_OPENGLES2 $GLINC" gfx/video_thread_hw.c
check "hw ring: Vulkan only" \
"-DHAVE_VULKAN $GLINC" gfx/video_thread_hw.c
check "hw ring: no hardware API" \
"$GLINC" gfx/video_thread_hw.c
# Widget state lock: the worker draws widgets while the main thread
# writes them, and the wrapper yields the lock around its waits.
check "widgets: state lock" "$GLINC -DHAVE_GFX_WIDGETS" \
gfx/gfx_widgets.c gfx/video_thread_wrapper.c gfx/video_driver.c runloop.c
# Without threads: the wrapper is not built, and callers must compile
# against the macro stand-ins, not the wrapper's prototypes. Syntax
# only here; the link is the threadless job's.
NOTHREADS=$(echo "$BASE" | sed 's/-DHAVE_THREADS//')
check_nothreads() {
name="$1"; shift
defs="$1"; shift
bad=0
for tu in "$@"; do
if ! out=$($CC $WARN $INC $NOTHREADS $defs -fsyntax-only "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1; bad=1
fi
done
[ "$bad" = 1 ] || echo "ok $name"
}
# Console rgui: the menu driver's GEKKO and DINGUX shapes have their
# own framebuffer dimensions, aspect handling and pixel converters;
# a syntax pass keeps refactors honest for both. GEKKO needs one
# tiny libogc stub header (tools/platform_stubs/gekko).
# The Android OpenSL driver compiles nowhere else; a stub SLES header
# set (tools/platform_stubs/android) keeps its lock-free write path
# and hardened teardown under a syntax gate.
# OpenAL: not in the audit build's configure. Compile-only AL stubs,
# first in the include order, so the lane needs no system
# libopenal-dev and behaves the same on every runner. Covers the
# eventcount park path (threads on).
check "audio: openal" "-Itools/platform_stubs/openal -DHAVE_AL -DHAVE_THREADS -Wdeclaration-after-statement -Werror=declaration-after-statement" audio/drivers/openal.c
# psp/psp2 audio: index-pair SPSC + eventcount park, one driver per
# platform; compile-only sce stubs.
check "psp: psp_audio" "-Itools/platform_stubs/psp -DPSP -DHAVE_THREADS -Wdeclaration-after-statement -Werror=declaration-after-statement" audio/drivers/psp_audio.c
check "vita: psp2_audio" "-Itools/platform_stubs/vita -DVITA -DHAVE_THREADS -Wdeclaration-after-statement -Werror=declaration-after-statement" audio/drivers/psp2_audio.c
# features_cpu.c on every statically linked platform. It owns
# cpu_features_get_time_usec() and retro_sleep_until_us(); the wait's
# generic loop calls retro_sleep_us, a per-platform macro from
# retro_timers.h everywhere but Windows and Darwin, so the branch that
# only the console toolchains compile is compiled here, against
# hermetic stubs of each SDK header the file pulls. The host compiler
# predefines __linux__ and friends; a lane that keeps them takes the
# Linux branch of every #if ladder and proves nothing, so these shed
# them. PSP gets _POSIX_C_SOURCE for the host libc's nanosleep, which
# pspsdk's newlib declares unconditionally.
FCPU_TU=libretro-common/features/features_cpu.c
check "features_cpu: 3ds" "$HOSTOFF -Itools/platform_stubs/ctr -D_3DS -D__3DS__ -DARM11 -DRARCH_CONSOLE" $FCPU_TU
check "features_cpu: gekko" "$HOSTOFF -Itools/platform_stubs/gekko -DGEKKO -DHW_RVL -DRARCH_CONSOLE" $FCPU_TU
check "features_cpu: wiiu" "$HOSTOFF -Itools/platform_stubs/wiiu -DWIIU -DRARCH_CONSOLE" $FCPU_TU
check "features_cpu: psp" "$HOSTOFF -Itools/platform_stubs/psp -DPSP -D_POSIX_C_SOURCE=199309L -DRARCH_CONSOLE" $FCPU_TU
check "features_cpu: vita" "$HOSTOFF -Itools/platform_stubs/vita -DVITA -DRARCH_CONSOLE" $FCPU_TU
check "features_cpu: ps3" "$HOSTOFF -Itools/platform_stubs/ps3 -D__PS3__ -DRARCH_CONSOLE" $FCPU_TU
check "features_cpu: psl1ght" "$HOSTOFF -Itools/platform_stubs/psl1ght -D__PS3__ -D__PSL1GHT__ -DRARCH_CONSOLE" $FCPU_TU
check "features_cpu: emscripten" "$HOSTOFF -Itools/platform_stubs/emscripten -D__EMSCRIPTEN__ -DEMSCRIPTEN" $FCPU_TU
# Shared menu and video code under the console platform macros. These
# files are compiled by every desktop job, but the blocks inside them
# that a console selects are not, and a change to a struct those blocks
# touch is green everywhere until a console job runs. The frame and
# draw descriptors they read need no SDK header, so these lanes take
# the stubs already here and shed the host identity like the ones
# above.
MENUGFX="gfx/video_driver.c gfx/gfx_display.c gfx/gfx_widgets.c \
gfx/gfx_thumbnail.c gfx/gfx_surface.c gfx/video_thread_wrapper.c \
menu/drivers/xmb.c menu/drivers/ozone.c menu/drivers/materialui.c"
MG_BASE="-DHAVE_XMB -DHAVE_OZONE -DHAVE_MATERIALUI -DHAVE_RGUI \
-DHAVE_GFX_WIDGETS -DHAVE_OVERLAY -DHAVE_CONFIGFILE -DRARCH_CONSOLE \
-DRARCH_INTERNAL -Iinput/include"
check "console menu+gfx: vita" "$HOSTOFF $MG_BASE -Itools/platform_stubs/vita -DVITA" $MENUGFX
check "console menu+gfx: wiiu" "$HOSTOFF $MG_BASE -Itools/platform_stubs/wiiu -DWIIU" $MENUGFX
check "console menu+gfx: psl1ght" "$HOSTOFF $MG_BASE -Itools/platform_stubs/psl1ght -D__PS3__ -D__PSL1GHT__" $MENUGFX
# video_thread_wrapper.c reaches for libctru's own allocator on 3DS,
# and a guessed linearMemAlign() would let this lane pass what the real
# SDK rejects, so the 3DS lane takes the rest.
check "console menu+gfx: 3ds" "$HOSTOFF $MG_BASE -Itools/platform_stubs/ctr -D_3DS -D__3DS__" \
$(echo "$MENUGFX" | tr ' ' '\n' | grep -v video_thread_wrapper)
check "console menu+gfx: gekko" "$HOSTOFF $MG_BASE -Itools/platform_stubs/gekko -DGEKKO -DHW_RVL" $MENUGFX
# Platform drivers no other job compiles. Each of these reaches a
# compiler only inside its own console toolchain - griffin includes it
# behind that platform's #ifdef and the desktop makefiles never build
# it - so a C89 slip or a missing declaration in one sits until the
# console job runs, which is how a mixed declaration lived in
# gx_joypad.c. These are the ones the stubs already in the tree can
# reach, with one stub added for the pair of PSP input drivers - the
# 3ds audio drivers want fifteen more symbols whose libctru signatures
# cannot be checked from here, and a stub that guessed one would let a
# lane pass what the real SDK rejects, so they are left out.
# The rest need headers no stub here supplies. psp1_gfx and
# dispserv_android already have lanes of their own - the latter gains
# the C89 declaration check below rather than a second lane.
#
# Same warnings as the driver lanes above, C89 declarations included,
# because that is the rule these files are furthest from anyone
# checking. GEKKO takes the vendored libogc headers before its stub:
# the stub carries only what libogc does not.
CDECL="-Wdeclaration-after-statement -Werror=declaration-after-statement"
GEKKO_INC="-Iwii/libogc/include -Itools/platform_stubs/gekko"
check "gekko: gx_input" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CONSOLE $CDECL" input/drivers/gx_input.c
check "gekko: gx_joypad" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CONSOLE $CDECL" input/drivers_joypad/gx_joypad.c
check "gekko: mem2_manager" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CONSOLE $CDECL" libretro-common/memory/mem2_manager.c
check "gekko: dispserv_gx" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_gx.c
check "gamecube: dispserv_gx" "$HOSTOFF $GEKKO_INC -DGEKKO -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_gx.c
check "gekko: dispserv_gx_modes" "$HOSTOFF $GEKKO_INC -DGEKKO -DHW_RVL -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_gx_modes.c
check "psl1ght: dispserv_ps3" "$HOSTOFF -Itools/platform_stubs/ps3 -D__PS3__ -D__PSL1GHT__ -DRARCH_CONSOLE $CDECL" gfx/display_servers/dispserv_ps3.c gfx/display_servers/dispserv_ps3_modes.c
check "3ds: ctr_input" "$HOSTOFF -Itools/platform_stubs/ctr -D_3DS -D__3DS__ -DARM11 -DRARCH_CONSOLE $CDECL" input/drivers/ctr_input.c
PSP_DEFS="$HOSTOFF -Itools/platform_stubs/psp -DPSP -D_POSIX_C_SOURCE=199309L -DRARCH_CONSOLE"
check "psp: psp_input" "$PSP_DEFS $CDECL" input/drivers/psp_input.c
check "psp: psp_joypad" "$PSP_DEFS $CDECL" input/drivers_joypad/psp_joypad.c
check "orbis: ps4_audio" "$HOSTOFF -Itools/platform_stubs/orbis -DORBIS $CDECL" audio/drivers/ps4_audio.c
check "qnx: alsa_qsa" "$HOSTOFF -Itools/platform_stubs/qnx -D__QNX__ $CDECL" audio/drivers/alsa_qsa.c
check "android: vfs saf" "$HOSTOFF -Itools/platform_stubs/android -DANDROID $CDECL" libretro-common/vfs/vfs_implementation_saf.c
check "android: play delivery" "$HOSTOFF -Itools/platform_stubs/android -DANDROID $CDECL" play_feature_delivery/play_feature_delivery.c
# the Android build carries the built-in NFS client and its backend
# (HAVE_RETRONFS in pkg/android/phoenix-common/jni/Android.mk) and the
# prefetcher both network backends read through
check "android: nfs client" "$HOSTOFF -Itools/platform_stubs/android -DANDROID -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DHAVE_THREADS -DHAVE_NETWORKING $CDECL" libretro-common/net/net_nfs3.c
check "android: nfs backend" "$HOSTOFF -Itools/platform_stubs/android -DANDROID -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DHAVE_THREADS -DHAVE_NETWORKING -DRARCH_INTERNAL $CDECL" libretro-common/vfs/vfs_implementation_nfs.c
check "android: vfs prefetch" "$HOSTOFF -Itools/platform_stubs/android -DANDROID -DHAVE_THREADS $CDECL" libretro-common/vfs/vfs_prefetch.c
# The Android build carries the cleanroom network stack (Android.mk:
# HAVE_CRYPTO, keychain, RETROSSL, RETROSMB, RETRONFS) and is compiled
# by the NDK's clang for aarch64. The same compiler family and target
# here, with the aarch64 cross headers standing in for the NDK's, over
# every translation unit of the stack: the AES/PMULL path takes the
# +crypto target attribute this way, which gcc lanes never exercise.
ANDROID_CLANG=${ANDROID_CLANG:-clang}
ANDROID_SYSINC=${ANDROID_SYSINC:-/usr/aarch64-linux-gnu/include}
android_clang() {
name="$1"; defs="$2"; tu="$3"
if ! command -v "$ANDROID_CLANG" > /dev/null 2>&1 || [ ! -d "$ANDROID_SYSINC" ]; then
echo "skip $name (no $ANDROID_CLANG or $ANDROID_SYSINC)"
return
fi
if ! out=$($ANDROID_CLANG --target=aarch64-linux-gnu -isystem "$ANDROID_SYSINC" \
-Wall -Werror -Wno-unused-function -D__ANDROID__ -DANDROID $INC $defs \
-fsyntax-only "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1
else
echo "ok $name"
fi
}
ANDROID_NET="-DHAVE_CRYPTO -DHAVE_KEYCHAIN -DHAVE_SSL -DHAVE_RETROSSL -DHAVE_SMBCLIENT -DHAVE_RETROSMB -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DHAVE_NETWORKING -DHAVE_THREADS -DHAVE_CONFIGFILE -DRARCH_INTERNAL -D_GNU_SOURCE"
for tu in libretro-common/crypto/crypto.c libretro-common/crypto/kdf.c libretro-common/crypto/pk.c \
libretro-common/crypto/x509.c libretro-common/file/keychain.c libretro-common/net/net_socket_ssl_retro.c \
libretro-common/net/net_smb2.c libretro-common/net/net_krb5.c libretro-common/net/net_nfs3.c \
libretro-common/vfs/vfs_implementation_smb.c libretro-common/vfs/vfs_implementation_nfs.c \
libretro-common/vfs/vfs_prefetch.c network/tls_log.c; do
android_clang "android clang/aarch64: $(basename $tu)" "$ANDROID_NET" "$tu"
done
# rwebaudio is its own translation unit in the emscripten build, not
# part of griffin's, and nothing else compiles it at all.
check "emscripten: rwebaudio" "$HOSTOFF -Itools/platform_stubs/emscripten -D__EMSCRIPTEN__ -DEMSCRIPTEN -DHAVE_RWEBAUDIO $CDECL" audio/drivers/rwebaudio.c
check "emscripten: rwebcam" "$HOSTOFF -Itools/platform_stubs/emscripten -D__EMSCRIPTEN__ -DEMSCRIPTEN $CDECL" camera/drivers/rwebcam.c
# Two more that no job here compiles: the S3 cloud-sync backend, which
# only griffin includes and which nothing defines HAVE_S3 for, and the
# Lakka wifi driver, which needs HAVE_LAKKA. Both had a mixed
# declaration. The C89 build cannot see either, because neither is in
# its object list.
NETDEFS="-DHAVE_NETWORKING -DHAVE_CONFIGFILE -DHAVE_OVERLAY -DHAVE_CHEATS"
check "cloudsync: s3" "$NETDEFS -DHAVE_CLOUDSYNC -DHAVE_S3 $CDECL" network/cloud_sync/s3.c
check "lakka: connmanctl" "$NETDEFS -DHAVE_LAKKA -DHAVE_WIFI $CDECL" network/drivers_wifi/connmanctl.c
# The salamander launchers link a hand-picked subset of libretro-common
# with -DIS_SALAMANDER: rtime.c for rtime_localtime, no features_cpu.c.
# A syntax pass cannot see the link error that a symbol from an
# unlinked TU produces there, so this lane links exactly that object
# set with a host main, under the Vita salamander's defines.
salamander_link() {
name="$1"; shift
defs="$1"; shift
if ! out=$($CC $WARN $INC $BASE $defs -o /tmp/salamander_link_check \
tools/platform_stubs/salamander_main.c "$@" 2>&1); then
echo "FAIL $name"
show_out "$out"
fail=1
else
echo "ok $name"
fi
rm -f /tmp/salamander_link_check
}
salamander_link "salamander link: rtime.c" \
"$HOSTOFF -UHAVE_THREADS -Itools/platform_stubs/vita -DVITA -DIS_SALAMANDER -DRARCH_CONSOLE" \
libretro-common/time/rtime.c
# runloop.c under Android: runloop_idle_wait's looper branch, and every
# other ANDROID block in the file, compiled against hermetic NDK stubs
# (jni, looper, native_activity, sensor, configuration, window) with
# the host identity shed.
check "android: runloop" "$HOSTOFF -DANDROID -Itools/platform_stubs/android" runloop.c
check "android: dispserv" "$HOSTOFF -DANDROID -Itools/platform_stubs/android $CDECL" gfx/display_servers/dispserv_android.c
# The Android arms of rthreads: thread affinity goes to the kernel
# directly there (bionic keeps cpu_set_t behind _GNU_SOURCE), and the
# API 21 arm names pthread_gettid_np, which only bionic declares.
check "android: rthreads (API 21)" "-DHAVE_THREADS -D__ANDROID__ -D__ANDROID_API__=21 -include tools/platform_stubs/android/bionic_pthread_stub.h -Itools/platform_stubs/android" libretro-common/rthreads/rthreads.c
check "android: rthreads (API 19)" "-DHAVE_THREADS -D__ANDROID__ -D__ANDROID_API__=19 -Itools/platform_stubs/android" libretro-common/rthreads/rthreads.c
# The D-Bus, Mutter and RealtimeKit units, and the elevation chain,
# are built on Linux and BSD only, but griffin and other build systems
# may still see the files elsewhere: as a target with no POSIX headers
# at all (MSVC, consoles), each must reduce to its gate and include
# none of them.
check "no-posix: D-Bus/Mutter/RealtimeKit units" "$HOSTOFF -DHAVE_DYLIB -Itools/platform_stubs/no_posix" \
gfx/common/dbus_runtime.c gfx/common/dbus_common.c \
gfx/common/mutter_displayconfig.c \
frontend/thread_elevation.c frontend/thread_elevation/rtkit.c \
frontend/thread_elevation/eevdf.c
check "android: opensl" "-DANDROID -DHAVE_OPENSL -Itools/platform_stubs/android -Wdeclaration-after-statement -Werror=declaration-after-statement" audio/drivers/opensl.c
check "gekko: rgui" "-DGEKKO -DHAVE_MENU -DHAVE_RGUI -Itools/platform_stubs/gekko" menu/drivers/rgui.c
check "dingux: rgui" "-DDINGUX -DHAVE_MENU -DHAVE_RGUI" menu/drivers/rgui.c
# The streaming surface embeds a wrapper node under HAVE_THREADS and
# collapses to direct driver calls without; both shapes compile here,
# along with the thumbnail code that produces into it.
# The VP9 decoder's tile-column threading and the video streams' pooled
# colour conversion sit behind HAVE_THREADS; both shapes compile.
check "vp9/h265/video streams: threads" "-DHAVE_RVP9 -DHAVE_RVP8 -DHAVE_RWEBM -DHAVE_RMP4 -DHAVE_RH264 -DHAVE_RH265" libretro-common/formats/vp9/rvp9.c libretro-common/formats/h265/rh265.c libretro-common/formats/webm/rwebm_video.c libretro-common/formats/mp4/rmp4_video.c libretro-common/formats/image/image_blit_bands.c
check_nothreads "no threads: vp9/h265/video streams" "-DHAVE_RVP9 -DHAVE_RVP8 -DHAVE_RWEBM -DHAVE_RMP4 -DHAVE_RH264 -DHAVE_RH265" libretro-common/formats/vp9/rvp9.c libretro-common/formats/h265/rh265.c libretro-common/formats/webm/rwebm_video.c libretro-common/formats/mp4/rmp4_video.c libretro-common/formats/image/image_blit_bands.c
check "gfx_surface: threads" "$GLINC" gfx/gfx_surface.c gfx/gfx_thumbnail.c
check_nothreads "no threads: gfx_surface" "$GLINC" gfx/gfx_surface.c gfx/gfx_thumbnail.c
check_nothreads "no threads: gl2" "$GLDEFS $GLINC" gfx/drivers/gl2.c
check_nothreads "no threads: video_driver" "$GLINC" gfx/video_driver.c
check_nothreads "no threads: retroarch" "$GLINC -DHAVE_COMMAND -DHAVE_STDIN_CMD" retroarch.c
check_nothreads "no threads: audio_driver" "$GLINC" audio/audio_driver.c
check_nothreads "no threads: linux input" "$GLINC" input/common/linux_common.c
check_nothreads "no threads: widget state lock stand-ins" \
"$GLINC -DHAVE_GFX_WIDGETS" \
gfx/gfx_widgets.c gfx/widgets/gfx_widget_volume.c gfx/video_driver.c runloop.c
# The networking files carry threaded machinery of their own - the HTTP
# DNS cache's lock and condition, the task queue's - beside code that is
# compiled either way, so a broadcast or a wait written outside the
# guard is green in every job here and breaks a threadless build. That
# has happened: a DNS cache signal added to net_http_resolve(), which is
# not itself guarded, was caught by a sample rather than by this matrix.
NETDEFS="-DHAVE_NETWORKING $GLINC"
check_nothreads "no threads: net_http" "$NETDEFS" libretro-common/net/net_http.c
check_nothreads "no threads: net_socket" "$NETDEFS" libretro-common/net/net_socket.c
check_nothreads "no threads: task_http" "$NETDEFS" tasks/task_http.c
check_nothreads "no threads: cloud sync" "$NETDEFS -DHAVE_CLOUDSYNC" \
tasks/task_cloudsync.c network/cloud_sync/webdav.c
# The menu and the on-screen widgets are switched separately, so the
# frontend translation units have to hold for all four combinations of
# the two. Every lane above builds with HAVE_MENU, and the shipping jobs
# all enable one or the other, so a declaration that reaches a caller
# only through menu_driver.h or gfx_widgets.h is green everywhere and
# absent from a build with both off.
echo
echo "== menu and widget gates =="
NOMENU=$(echo "$BASE" | sed 's/-DHAVE_MENU//')
check_gates() {
name="$1"; shift
defs="$1"; shift
bad=0
for tu in "$@"; do
if ! out=$($CC $WARN $INC $NOMENU $defs -fsyntax-only "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1; bad=1
fi
done
[ "$bad" = 1 ] || echo "ok $name"
}
UITU="retroarch.c runloop.c gfx/video_driver.c gfx/gfx_display.c"
UIDEFS="$GLINC -DHAVE_COMMAND -DHAVE_STDIN_CMD"
check_gates "gates: menu + widgets" "$UIDEFS -DHAVE_MENU -DHAVE_GFX_WIDGETS" $UITU
check_gates "gates: menu only" "$UIDEFS -DHAVE_MENU" $UITU
# The keychain without networking: its menu entry and task must be
# declared outside the networking-only parts of tasks_internal.h.
check_gates "gates: keychain menu, no networking" \
"$UIDEFS -DHAVE_MENU -DHAVE_KEYCHAIN -DHAVE_CRYPTO -DHAVE_CONFIGFILE" \
menu/menu_setting.c tasks/task_keychain.c
check_gates "gates: widgets only" "$UIDEFS -DHAVE_GFX_WIDGETS" $UITU
check_gates "gates: neither" "$UIDEFS" $UITU
# The optional subsystems switch independently of the menu and of each
# other, and the units that call into them are built either way. Each
# lane drops one subsystem from a fully featured build; the last drops
# all of them, which is what a minimal frontend compiles as.
ALLGATES="-DHAVE_MENU -DHAVE_GFX_WIDGETS -DHAVE_OVERLAY -DHAVE_CHEEVOS -DRC_CLIENT_SUPPORTS_HASH -DHAVE_NETWORKING -DHAVE_RUNAHEAD -DHAVE_DYNAMIC -DHAVE_DYLIB"
FETU="retroarch.c runloop.c command.c gfx/video_driver.c input/input_driver.c configuration.c tasks/task_content.c"
without() { echo "$ALLGATES" | sed "s/$1//g"; }
check_gates "gates: every subsystem" "$UIDEFS $ALLGATES" $FETU
check_gates "gates: no overlay" "$UIDEFS $(without -DHAVE_OVERLAY)" $FETU
check_gates "gates: no cheevos" "$UIDEFS $(without '-DHAVE_CHEEVOS -DRC_CLIENT_SUPPORTS_HASH')" $FETU
check_gates "gates: no networking" "$UIDEFS $(without -DHAVE_NETWORKING)" $FETU
check_gates "gates: no run-ahead" "$UIDEFS $(without -DHAVE_RUNAHEAD)" $FETU
check_gates "gates: no subsystems" "$UIDEFS" $FETU
# Each video API owns a GPU index setting and its default, under that
# API's own gate, and a build has any mix of APIs: a default defined
# under another API's gate builds only where both are on. Each API that
# a Linux build can have alone is checked alone.
check_gates "gates: GPU index, EGL only" "$UIDEFS -DHAVE_EGL -DHAVE_OPENGL" configuration.c
check_gates "gates: GPU index, Vulkan only" "$UIDEFS -DHAVE_VULKAN" configuration.c
# griffin is one translation unit, so a file-local name that is fine on
# its own collides there: p256's fmul against gfx's did, and only the
# MSVC job builds griffin. Both crypto shapes, on Linux, for free.
check_gates "griffin: HAVE_CRYPTO + keychain" "$UIDEFS -DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_CONFIGFILE -DHAVE_CRYPTO -DHAVE_KEYCHAIN -D_GNU_SOURCE" griffin/griffin.c
check_gates "griffin: HAVE_RETROSSL" "$UIDEFS -DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_CONFIGFILE -DHAVE_CRYPTO -DHAVE_KEYCHAIN -DHAVE_NETWORKING -DHAVE_SSL -DHAVE_RETROSSL -D_GNU_SOURCE" griffin/griffin.c
check_gates "griffin: HAVE_RETROSMB + cloud sync" "$UIDEFS -DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_CONFIGFILE -DHAVE_CRYPTO -DHAVE_NETWORKING -DHAVE_SMBCLIENT -DHAVE_RETROSMB -DHAVE_CLOUDSYNC -D_GNU_SOURCE" griffin/griffin.c
# The unity build the Android, Apple, webOS and MSVC targets ship: the
# whole network stack beside every codec, image reader and subsystem
# griffin can carry. A static helper in one translation unit that
# another one also defines (get32 in net_smb2.c and rvorbis.c) only
# collides here, so this lane carries as much of griffin as a host can.
GRIFFIN_FULL="-DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_XMB -DHAVE_OZONE -DHAVE_MATERIALUI -DHAVE_GFX_WIDGETS -DHAVE_OVERLAY -DHAVE_CONFIGFILE -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_RUNAHEAD -DHAVE_REWIND -DHAVE_PATCH -DHAVE_XDELTA -DHAVE_CHEATS -DHAVE_SCREENSHOTS -DHAVE_TRANSLATE -DHAVE_LIBRETRODB -DHAVE_DYNAMIC -DHAVE_DYLIB -DHAVE_THREADS -DHAVE_AUDIOMIXER -DHAVE_DSP_FILTER -DHAVE_VIDEO_FILTER -DHAVE_RWAV -DHAVE_RFLAC -DHAVE_RVORBIS -DHAVE_RMP3 -DHAVE_RAC3 -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RZSTD -DHAVE_7ZIP -DHAVE_CHD -DHAVE_RCHD -DHAVE_IMAGEVIEWER -DHAVE_STB_FONT -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_NETWORK_CMD -DHAVE_NETPLAYDISCOVERY -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_UPDATE_CORE_INFO -DHAVE_CORE_INFO_CACHE -DHAVE_CLOUDSYNC -DHAVE_S3 -DHAVE_CRYPTO -DHAVE_KEYCHAIN -DHAVE_SSL -DHAVE_RETROSSL -DHAVE_SMBCLIENT -DHAVE_RETROSMB -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DHAVE_LANGEXTRA -DHAVE_SHADERPIPELINE -DHAVE_GLSL -DHAVE_OPENGL -D_GNU_SOURCE"
check_gates "griffin: full unity (every codec + network stack)" "$UIDEFS $GRIFFIN_FULL" griffin/griffin.c
# The SMB show-settings row read a HAVE_MENU-only default under
# HAVE_SMBCLIENT alone; with the built-in client on by default that
# broke every --disable-menu build. configuration.c with SMB and no
# menu, and the same with no menu at all.
check_gates "gates: SMB client, no menu" "$UIDEFS -DHAVE_CONFIGFILE -DHAVE_NETWORKING -DHAVE_CRYPTO -DHAVE_SMBCLIENT -DHAVE_RETROSMB -D_GNU_SOURCE" configuration.c
check_gates "gates: NFS client, no menu" "$UIDEFS -DHAVE_CONFIGFILE -DHAVE_NETWORKING -DHAVE_NFSCLIENT -DHAVE_RETRONFS -D_GNU_SOURCE" configuration.c
check_gates "gates: NFS client + menu" "$UIDEFS -DHAVE_CONFIGFILE -DHAVE_NETWORKING -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DHAVE_MENU -DHAVE_RGUI -D_GNU_SOURCE" configuration.c menu/menu_setting.c menu/menu_displaylist.c menu/cbs/menu_cbs_ok.c menu/cbs/menu_cbs_deferred_push.c menu/cbs/menu_cbs_sublabel.c menu/cbs/menu_cbs_title.c
check_gates "gates: no menu, no SMB" "$UIDEFS -DHAVE_CONFIGFILE -DHAVE_NETWORKING -D_GNU_SOURCE" configuration.c
check_gates "griffin: HAVE_RETRONFS" "$UIDEFS -DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_CONFIGFILE -DHAVE_NETWORKING -DHAVE_NFSCLIENT -DHAVE_RETRONFS -D_GNU_SOURCE" griffin/griffin.c
check_gates "griffin: no crypto (console shape)" "$UIDEFS -DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_CONFIGFILE -DHAVE_KEYCHAIN -D_GNU_SOURCE" griffin/griffin.c
# A subsystem's own unit is built only when its gate is on, so each is
# checked with that gate on and the user interface off: the achievement
# and netplay widgets, and the menu entries either drives, are the edges
# where a declaration goes missing.
check_gates "gates: netplay, no UI" \
"$UIDEFS -DHAVE_NETWORKING" network/netplay/netplay_frontend.c
check_gates "gates: cheevos, no UI" \
"$UIDEFS -DHAVE_CHEEVOS -DRC_CLIENT_SUPPORTS_HASH" cheevos/cheevos.c
check_gates "gates: run-ahead, no UI" \
"$UIDEFS -DHAVE_RUNAHEAD -DHAVE_DYNAMIC -DHAVE_DYLIB" runahead.c
# The builtin DSP filters are compiled only by console builds, through
# griffin, and no other job compiles them as C. Each is checked on its
# own, as the consoles build it, in the C89 lane: once with the C99 math
# names glibc declares under _GNU_SOURCE, and once without them, as on
# MSVC, so an undeclared sqrtf() or M_PI fails here.
echo
echo "== dsp filters: C89 =="
DSP=$(ls libretro-common/audio/dsp_filters/*.c)
check "dsp filters: C89" "$C89 -DHAVE_FILTERS_BUILTIN" $DSP
check "dsp filters: C89, no C99 math declarations" \
"$(echo "$C89" | sed 's/ -D_GNU_SOURCE//') -DHAVE_FILTERS_BUILTIN" $DSP
# The UI companion's shared core, which only a Qt or Cocoa build puts
# in OBJ. A tree configured --disable-qt on a Linux host - which is what
# a desktop job builds - compiles none of it, so a change to a struct it
# reads is green everywhere until one of those jobs runs.
echo "== ui companion: the shared core =="
COMPANION="ui/companion/companion_core.c ui/companion/companion_thumbs.c \
ui/companion/companion_dock.c"
check "ui companion" "-DHAVE_RGUI -DHAVE_CONFIGFILE" $COMPANION
check "ui companion: no threads" \
"$(echo "$BASE" | sed 's/ -DHAVE_THREADS//') -DHAVE_RGUI -DHAVE_CONFIGFILE" \
$COMPANION
# Its own tests, which link the same objects and read the same structs.
# They live outside ui/companion and a change that stops at the three
# files above leaves them behind.
check "ui companion: tests" "-DHAVE_RGUI -DHAVE_CONFIGFILE -Iui/companion" \
ui/companion/test/companion_core_test.c \
ui/companion/test/companion_thumbs_test.c \
ui/companion/test/companion_core_stubs.c
# Video and shader back ends a Linux desktop job does not select. Each
# reads the frame descriptor and the shader parameter block every other
# driver does, and nothing else here compiles them: this configuration
# has no Vulkan, no Cg and none of the framebuffer drivers, so a change
# to those structs is green until a job that does have them runs.
echo "== video back ends this configuration does not build =="
GFXDEFS="-DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_GFX_WIDGETS"
VK_H=/usr/include/vulkan/vulkan.h
platform_video "vulkan back end" "$GFXDEFS -DHAVE_VULKAN" "" \
gfx/drivers/vulkan.c "$VK_H"
platform_video "vulkan shader back end" "$GFXDEFS -DHAVE_VULKAN" "" \
gfx/drivers_shader/shader_vulkan.c "$VK_H"
check "cg shader back end" "$GFXDEFS -DHAVE_CG -DHAVE_OPENGL" \
gfx/drivers_shader/shader_gl_cg.c
check "framebuffer back ends" "$GFXDEFS" \
gfx/drivers/fpga_gfx.c gfx/drivers/hub75_gfx.c gfx/drivers/sunxi_gfx.c
X11_H=/usr/include/X11/Xlib.h
platform_video "x11 shm back end" "$GFXDEFS -DHAVE_X11" "" \
gfx/drivers/xshm_gfx.c "$X11_H"
platform_video "xvideo back end" "$GFXDEFS -DHAVE_X11 -DHAVE_XVIDEO" "" \
gfx/drivers/xvideo.c "$X11_H"
echo "== run-ahead: the dynamic-library gates =="
# The secondary instance exists only with HAVE_DYNAMIC; a build that
# can load libraries but links its core statically (HAVE_DYLIB alone)
# compiles the secondary path out and keeps the callers linking.
RADEFS="-DHAVE_REWIND -DHAVE_RUNAHEAD -DHAVE_DYNAMIC_EXTENSIONS"
check "runahead: neither" "$RADEFS" runahead.c
check "runahead: HAVE_DYLIB only" "$RADEFS -DHAVE_DYLIB" runahead.c
check "runahead: HAVE_DYNAMIC" "$RADEFS -DHAVE_DYNAMIC" runahead.c
check "runahead: both" "$RADEFS -DHAVE_DYNAMIC -DHAVE_DYLIB" runahead.c
# The Metal driver, as Objective-C against stand-ins for the parts of the
# macOS SDK it uses (tools/platform_stubs/metal). No runner here has the
# SDK, so the Apple jobs used to be the first to compile it. A selector
# the stand-ins do not declare is an error: a new Metal call needs its
# declaration added there.
if command -v clang > /dev/null 2>&1; then
if ! out=$(clang -x objective-c -fobjc-runtime=macosx-10.13 -fblocks \
-fsyntax-only -Wall -Wno-unused-function -Werror=objc-method-access \
-Werror=unused-but-set-variable $HOSTOFF -D__APPLE__ -D__MACH__ \
-DHAVE_METAL -Itools/platform_stubs/metal $INC $BASE \
gfx/drivers/metal.m 2>&1); then
echo "FAIL metal video (stubs)"
echo " gfx/drivers/metal.m"
show_out "$out"
fail=1
else
echo "ok metal video (stubs)"
fi
else
echo "skip metal video (stubs) (no clang)"
fi
# gfx/font_layout.h expands inside each driver's render function, and a
# hook that reads a value before declaring its own locals is C99 the C89
# lane rejects, so these lanes reject it too (the PS2 and Wii U drivers,
# built only by C99 toolchains, opt out). And a
# layout counter a driver has no use for is set but never read. GCC 15
# and clang warn about that; the runner's GCC does not, so these lanes
# ask clang, with the warning made an error.
font_layout() {
name="$1"; target="$2"; defs="$3"; tu="$4"
if ! command -v clang > /dev/null 2>&1; then
echo "skip $name (no clang)"
return
fi
if ! out=$(clang $target -Werror=unused-but-set-variable \
-Werror=declaration-after-statement \
$INC $BASE $defs -fsyntax-only "$tu" 2>&1); then
echo "FAIL $name"
echo " $tu"
show_out "$out"
fail=1
else
echo "ok $name"
fi
}
# Vulkan from the Khronos headers the tree carries (gfx/include), as the
# real builds use, so the lane runs on a runner without the SDK headers
font_layout "font layout: vulkan" "" "-DHAVE_VULKAN -Igfx/include" gfx/drivers/vulkan.c
font_layout "font layout: gl" "" "-DHAVE_OPENGL" gfx/drivers/gl2.c
font_layout "font layout: gl1" "" "-DHAVE_OPENGL -DHAVE_OPENGL1" \
gfx/drivers/gl1.c
if command -v sdl2-config > /dev/null 2>&1; then
font_layout "font layout: sdl2" "" "-DHAVE_SDL2 $(sdl2-config --cflags)" \
gfx/drivers/sdl2_gfx.c
else
echo "skip font layout: sdl2 (no sdl2-config)"
fi
if [ -f /usr/include/SDL3/SDL.h ]; then
font_layout "font layout: sdl3" "" "-DHAVE_SDL3 -I/usr/include/SDL3" \
gfx/drivers/sdl3_gfx.c
else
echo "skip font layout: sdl3 (no SDL3 headers)"
fi
# The software OSD blitters, where their headers are installed
if [ -f /usr/include/X11/extensions/Xvlib.h ]; then
font_layout "font layout: xvideo" "" "-DHAVE_X11 -DHAVE_XVIDEO" \
gfx/drivers/xvideo.c
fi
if [ -f /usr/include/SDL/SDL.h ]; then
font_layout "font layout: sdl" "" "-DHAVE_SDL -I/usr/include/SDL" \
gfx/drivers/sdl_gfx.c
fi
if [ -f /usr/include/linux/omapfb.h ]; then
font_layout "font layout: omap" "" "-DHAVE_OMAP" gfx/drivers/omap_gfx.c
fi
font_layout "font layout: switch" "" \
"-DHAVE_LIBNX -DSWITCH -D__SWITCH__ -I$STUBS/libnx" \
gfx/drivers/switch_nx_gfx.c
font_layout "font layout: gxm" "" \
"-DVITA -DRARCH_CONSOLE $HOSTOFF -Itools/platform_stubs/vita" \
gfx/drivers/gxm_gfx.c
font_layout "font layout: ps2" "" \
"-DPS2 -DRARCH_CONSOLE -DHAVE_WINDOW_OFFSET -DHAVE_RGUI $HOSTOFF -Itools/platform_stubs/ps2 \
-Wno-declaration-after-statement" \
gfx/drivers/ps2_gfx.c
font_layout "font layout: gx2" "" \
"-DWIIU $HOSTOFF -Iwiiu/include -Iwiiu -Wno-declaration-after-statement" \
gfx/drivers/gx2_gfx.c
font_layout "font layout: glcore" "" \
"-DHAVE_OPENGL -DHAVE_OPENGL_CORE -DHAVE_SLANG" gfx/drivers/gl3.c
if [ -d /usr/x86_64-w64-mingw32/include ]; then
MINGW_CLANG="--target=x86_64-w64-mingw32 -isystemgfx/include/dxsdk -isystem /usr/x86_64-w64-mingw32/include"
font_layout "font layout: gdi" "$MINGW_CLANG" \
"-DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_GDI -D_WIN32_WINNT=0x0601" \
gfx/drivers/gdi_gfx.c
font_layout "font layout: d3d8" "$MINGW_CLANG" \
"-DHAVE_D3D -DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_D3D8" gfx/drivers/d3d8.c
font_layout "font layout: d3d9 hlsl" "$MINGW_CLANG" \
"-DHAVE_D3D -DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_D3D9" gfx/drivers/d3d9hlsl.c
font_layout "font layout: d3d9 cg" "$MINGW_CLANG" \
"-DHAVE_D3D -DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_D3D9" gfx/drivers/d3d9cg.c
font_layout "font layout: d3d10" "$MINGW_CLANG" \
"-DHAVE_D3D -DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_D3D10" gfx/drivers/d3d10.c
font_layout "font layout: d3d11" "$MINGW_CLANG" \
"-DHAVE_D3D -DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_D3D11" gfx/drivers/d3d11.c
font_layout "font layout: d3d12" "$MINGW_CLANG" \
"-DHAVE_D3D -DHAVE_RGUI -DHAVE_OVERLAY -DHAVE_D3D12" gfx/drivers/d3d12.c
else
echo "skip font layout: gdi, d3d8/9/10/11/12 (no MinGW headers)"
fi
exit $fail
@@ -1,5 +0,0 @@
# function size stack-frame (release build, x86-64 GCC)
runloop_iterate 3933 88
video_driver_frame 9447 4008
video_thread_frame 3097 152
audio_driver_sample_batch 394 24
@@ -1,81 +0,0 @@
#!/bin/sh
# The size and stack frame of the frontend's hottest functions, against
# a checked-in budget.
#
# Code size is I-cache footprint on the path that runs every frame, and
# the stack frame is what the prologue touches before any work happens.
# Neither is visible to a test: a change that doubles either passes
# every lane in the suite and shows up only as a slower frame on
# someone's machine. This is the check that notices.
#
# The numbers come from the release objects, so run it after a plain
# `make`. The budget is deliberately loose - a quarter over what the
# tree measures today - because compilers differ and the point is to
# catch a step change, not to freeze a byte count. When a change means
# to grow one of these, the reference moves with it in the same commit,
# which is exactly the moment to say why in the message.
#
# The functions, and why each is here:
# runloop_iterate the frame's orchestration
# video_driver_frame the frontend's hottest function by its
# own comment; also the largest frame
# video_thread_frame the handover, on the paced path
# audio_driver_sample_batch called once per core frame, more with
# per-sample cores
set -eu
cd "$(dirname "$0")/../../.."
ref=".github/workflows/scripts/hot-function-budget.ref"
obj="obj-unix/release"
fail=0
if [ ! -d "$obj" ]; then
echo "no release objects in $obj; run make first" >&2
exit 1
fi
measure() {
o="$1"; fn="$2"
sz=$(nm -S "$o" 2>/dev/null | grep -w "$fn" | head -1 | awk '{print $2}')
[ -n "$sz" ] || { echo "SKIP $fn (not in $o)"; return; }
size=$(printf '%d' "0x$sz")
# mawk has no strtonum(); the hex comes back as text and the shell
# converts it.
frame_hex=$(objdump -d --no-show-raw-insn "$o" 2>/dev/null | awk -v f="$fn" '
$0 ~ "<"f">:" { in_fn = 1; next }
in_fn && /^$/ { exit }
in_fn && /sub +\$0x[0-9a-f]+,%rsp/ {
match($0, /0x[0-9a-f]+/); print substr($0, RSTART + 2, RLENGTH - 2); exit }')
if [ -n "$frame_hex" ]; then
frame=$(printf '%d' "0x$frame_hex")
else
frame=0
fi
want_size=$(awk -v f="$fn" '$1 == f { print $2 }' "$ref")
want_frame=$(awk -v f="$fn" '$1 == f { print $3 }' "$ref")
[ -n "$want_size" ] || { echo "SKIP $fn (no reference)"; return; }
max_size=$(( want_size + want_size / 4 ))
max_frame=$(( want_frame + want_frame / 4 + 64 ))
status="ok "
if [ "$size" -gt "$max_size" ] || [ "$frame" -gt "$max_frame" ]; then
status="FAIL "
fail=1
fi
printf '%s %-28s size %6d (budget %6d) frame %5d (budget %5d)\n' \
"$status" "$fn" "$size" "$max_size" "$frame" "$max_frame"
}
echo "== hot function budget =="
measure "$obj/runloop.o" runloop_iterate
measure "$obj/gfx/video_driver.o" video_driver_frame
measure "$obj/gfx/video_thread_wrapper.o" video_thread_frame
measure "$obj/audio/audio_driver.o" audio_driver_sample_batch
if [ "$fail" = 1 ]; then
echo
echo "A hot function grew past its budget. If that is deliberate, move"
echo "the number in $ref in the same commit and say why."
exit 1
fi
@@ -1,15 +0,0 @@
# function bytes (release build, x86-64 GCC)
#
# Over the ceiling and left that way, each with its reason. A frame
# that is not listed here fails the sweep; one that grows past what is
# recorded fails too, and the number moves in the commit that grows it.
#
# switch_res_crt a CRT mode switch, once when the resolution
# changes, on the main thread
# spirv_cache_save shader cache written once per compiled pass,
# spirv_cache_load read once per pass at load
# gfx_anim_preview_probe probes a preview file, off the frame path
switch_res_crt 4440
spirv_cache_save 4312
spirv_cache_load 4296
gfx_anim_preview_probe 4128
@@ -1,95 +0,0 @@
#!/bin/sh
# Every stack frame in the graphics objects, against the tree's limit.
#
# CODING-GUIDELINES puts a ceiling on a function's stack frame - two
# kilobytes inside libretro-common, four outside it - because the
# threads this code runs on do not all get a desktop's stack, and a
# frame that overruns one corrupts whatever is under it rather than
# failing. Nothing checked it: the frames this sweep was written for
# were twelve kilobytes, in four font paths and an overlay batch, and
# they had been there for years.
#
# A large local array is invisible in review and to every other lane -
# it compiles, it runs on a machine with eight megabytes of stack, and
# it is only a problem on the platform with the smallest one. This is
# the check that notices.
#
# Reads the release objects, so run it after a plain `make`. Functions
# allowed to exceed the ceiling are listed in stack-frame-sweep.ref
# with the size they measure; a change that grows one moves its line in
# the same commit, which is the moment to say why in the message.
set -e
cd "$(dirname "$0")/../../.."
OBJDIR=${OBJDIR:-obj-unix/release}
ref="$(dirname "$0")/stack-frame-sweep.ref"
limit=${LIMIT:-4096}
fail=0
if [ ! -d "$OBJDIR/gfx" ]; then
echo "skip: no objects in $OBJDIR (run make first)"
exit 0
fi
# A large frame is built by repeated probes of a page at a time, so the
# allocation is the sum of the subtractions a function makes, not the
# largest one.
for o in $(find "$OBJDIR/gfx" -name '*.o' | sort); do
objdump -d --no-show-raw-insn "$o" 2>/dev/null | awk -v obj="$o" -v lim="$limit" '
/^[0-9a-f]+ <.*>:/ {
if (fn != "" && total > lim)
printf "%s %s %d\n", obj, fn, total
fn = $2; sub(/^</, "", fn); sub(/>:$/, "", fn)
total = 0
next
}
/sub +\$0x[0-9a-f]+,%rsp/ {
# The hex is not at a fixed field: the address column shifts
# them, so take it out of the line rather than by index.
line = $0
sub(/^.*sub +\$0x/, "", line)
sub(/,%rsp.*$/, "", line)
hex = line
# mawk has no strtonum(); fold the hex by hand, and ignore the
# sign-extended constants an add-by-subtract produces.
n = 0; ok = 1
for (i = 1; i <= length(hex); i++) {
c = substr(hex, i, 1)
p = index("0123456789abcdef", c)
if (p == 0) { ok = 0; break }
n = n * 16 + (p - 1)
}
if (ok && n < 4194304) total += n
next
}
END {
if (fn != "" && total > lim)
printf "%s %s %d\n", obj, fn, total
}
'
done > /tmp/stack-frame-sweep.$$ || true
echo "== stack frames over $limit bytes =="
while read -r obj fn size; do
[ -n "$fn" ] || continue
want=$(awk -v f="$fn" '$1 == f { print $2 }' "$ref" 2>/dev/null)
if [ -z "$want" ]; then
echo "FAIL $fn ($size bytes) in $(basename "$obj")"
fail=1
elif [ "$size" -gt "$want" ]; then
echo "FAIL $fn grew to $size, recorded $want"
fail=1
else
echo "ok $fn ($size bytes, recorded $want)"
fi
done < /tmp/stack-frame-sweep.$$
rm -f /tmp/stack-frame-sweep.$$
if [ "$fail" = 1 ]; then
echo
echo "A function's stack frame is over the ceiling in CODING-GUIDELINES."
echo "Move the array off the frame, or record it in $ref with why."
exit 1
fi
echo "ok nothing else over $limit bytes"
exit 0
@@ -1,43 +0,0 @@
/* Stand-in for the macOS SDK umbrella header: only the CoreGraphics
* and CoreText declarations gfx/drivers_font_renderer/coretext.c uses. */
#ifndef STUB_AS_H
#define STUB_AS_H
#include <CoreFoundation/CFString.h>
typedef double CGFloat;
typedef unsigned short CGGlyph;
typedef struct { CGFloat x, y; } CGPoint;
typedef struct { CGFloat width, height; } CGSize;
typedef struct { CGPoint origin; CGSize size; } CGRect;
typedef struct { CGFloat a,b,c,d,tx,ty; } CGAffineTransform;
extern const CGAffineTransform CGAffineTransformIdentity;
typedef struct CGContext *CGContextRef;
typedef struct CGColorSpace *CGColorSpaceRef;
typedef struct CGDataProvider *CGDataProviderRef;
typedef struct CGFont *CGFontRef;
typedef const struct __CTFont *CTFontRef;
typedef const struct __CTLine *CTLineRef;
typedef uint32_t CTFontOrientation;
typedef uint32_t CGBitmapInfo;
enum { kCGImageAlphaNone = 0, kCGImageAlphaOnly = 7, kCGBitmapByteOrder16Host = 0x1000 };
extern const CFStringRef kCTFontAttributeName;
extern const CFStringRef kCTForegroundColorFromContextAttributeName;
typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data, size_t size);
CGDataProviderRef CGDataProviderCreateWithData(void *, const void *, size_t, CGDataProviderReleaseDataCallback);
CGFontRef CGFontCreateWithDataProvider(CGDataProviderRef);
CTFontRef CTFontCreateWithGraphicsFont(CGFontRef, CGFloat, const CGAffineTransform *, void *);
bool CTFontGetGlyphsForCharacters(CTFontRef, const UniChar *, CGGlyph *, CFIndex);
CGRect CTFontGetBoundingRectsForGlyphs(CTFontRef, CTFontOrientation, const CGGlyph *, CGRect *, CFIndex);
double CTFontGetAdvancesForGlyphs(CTFontRef, CTFontOrientation, const CGGlyph *, CGSize *, CFIndex);
CGFloat CTFontGetAscent(CTFontRef);
CGFloat CTFontGetDescent(CTFontRef);
CGFloat CTFontGetLeading(CTFontRef);
CGColorSpaceRef CGColorSpaceCreateDeviceGray(void);
void CGColorSpaceRelease(CGColorSpaceRef);
CGContextRef CGBitmapContextCreate(void *, size_t, size_t, size_t, size_t, CGColorSpaceRef, uint32_t);
void CGContextRelease(CGContextRef);
void CGContextSetGrayFillColor(CGContextRef, CGFloat, CGFloat);
void CGContextSetTextMatrix(CGContextRef, CGAffineTransform);
void CGContextSetTextPosition(CGContextRef, CGFloat, CGFloat);
CTLineRef CTLineCreateWithAttributedString(CFAttributedStringRef);
void CTLineDraw(CTLineRef, CGContextRef);
#endif
@@ -1,27 +0,0 @@
/* Stand-in for the macOS/iOS SDK header: only the CoreFoundation
* declarations gfx/drivers_font_renderer/coretext.c uses, so the
* compile matrix can check that file in an Apple shape. */
#ifndef STUB_CF_H
#define STUB_CF_H
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
typedef long CFIndex;
typedef unsigned short UniChar;
typedef const void *CFTypeRef;
typedef const struct __CFString *CFStringRef;
typedef const struct __CFDictionary *CFDictionaryRef;
typedef const struct __CFAllocator *CFAllocatorRef;
typedef const struct __CFBoolean *CFBooleanRef;
typedef const struct __CFAttributedString *CFAttributedStringRef;
typedef struct { int v; } CFDictionaryKeyCallBacks;
typedef struct { int v; } CFDictionaryValueCallBacks;
extern const CFBooleanRef kCFBooleanTrue;
extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
void CFRelease(CFTypeRef);
CFTypeRef CFRetain(CFTypeRef);
CFStringRef CFStringCreateWithCharacters(CFAllocatorRef, const UniChar *, CFIndex);
CFDictionaryRef CFDictionaryCreate(CFAllocatorRef, const void **, const void **, CFIndex, const CFDictionaryKeyCallBacks *, const CFDictionaryValueCallBacks *);
CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef, CFStringRef, CFDictionaryRef);
#endif
@@ -1,2 +0,0 @@
/* iOS spelling of the same stand-in */
#include <ApplicationServices/ApplicationServices.h>
@@ -1,2 +0,0 @@
/* iOS spelling of the same stand-in */
#include <ApplicationServices/ApplicationServices.h>
@@ -1,8 +1,5 @@
#ifndef STUB_TC_H
#define STUB_TC_H
#ifdef __MACH__
#include <TargetConditionals.h>
#endif
#ifndef TARGET_OS_IPHONE
#define TARGET_OS_IPHONE 0
#endif
+3 -370
View File
@@ -1,372 +1,5 @@
/* Stand-in for devkitPro's libogc <gccore.h>, for the GX video driver.
*
* Prototypes and values follow libogc's, so the driver's calls are
* checked as it makes them. As the note at the top of compile-matrix.sh
* says, this does not prove the real SDK matches: it proves RetroArch's
* own GX code is well formed and uses only what it has arranged to
* have. Pinning the surface here rather than fetching the SDK is
* deliberate - the 3DS driver no longer compiles against a current
* libctru, whose gspSubmitGxCommand() changed shape under it, and a
* lane that goes red when somebody else's headers move tells us
* nothing about this tree.
*/
#ifndef LIBOGC_STUB_GCCORE_H
#define LIBOGC_STUB_GCCORE_H
#ifndef STUB_GCCORE_H
#define STUB_GCCORE_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef float f32;
typedef double f64;
typedef volatile uint8_t vu8;
typedef volatile uint16_t vu16;
typedef volatile uint32_t vu32;
typedef uint32_t lwpq_t;
typedef uint32_t lwp_t;
typedef uint32_t mutex_t;
typedef uint32_t syswd_t;
typedef struct { u32 dummy[16]; } GXFifoObj;
typedef void (*VIRetraceCallback)(u32 retraceCnt);
typedef void (*VIPositionCallback)(s16 x, s16 y);
typedef f32 Mtx[3][4];
typedef f32 Mtx44[4][4];
#define ATTRIBUTE_ALIGN(v) __attribute__((aligned(v)))
#define ATTRIBUTE_PACKED __attribute__((packed))
#define LWP_TQUEUE_NULL 0xffffffff
#define SYS_BASE_CACHED 0x80000000
#define SYS_BASE_UNCACHED 0xc0000000
/* uintptr_t, not u32: on the console a pointer is 32 bits and libogc's
* own cast is exact, while the host running this check is 64-bit and
* would lose half of one. The arithmetic is what matters here. */
#define MEM_K0_TO_K1(x) ((void*)((uintptr_t)(x) + (SYS_BASE_UNCACHED - SYS_BASE_CACHED)))
#define MEM_K1_TO_K0(x) ((void*)((uintptr_t)(x) - (SYS_BASE_UNCACHED - SYS_BASE_CACHED)))
#define VIDEO_PadFramebufferWidth(w) ((u16)(((u16)(w) + 15) & ~15))
#define VI_TVMODE(fmt, mode) (((fmt) << 2) + (mode))
typedef struct { u8 r, g, b, a; } GXColor;
typedef struct { u32 dummy[8]; } GXTexObj;
typedef struct
{
u32 viTVMode;
u16 fbWidth, efbHeight, xfbHeight;
u16 viXOrigin, viYOrigin, viWidth, viHeight;
u32 xfbMode;
u8 field_rendering, aa;
u8 sample_pattern[12][2];
u8 vfilter[7];
} GXRModeObj;
typedef enum { CONF_VIDEO_NTSC = 0, CONF_VIDEO_PAL, CONF_VIDEO_MPAL } CONFVideoMode;
#ifndef COLOR_BLACK
#define COLOR_BLACK (0x10801080)
#endif
#ifndef VI_DISPLAY_PIX_SZ
#define VI_DISPLAY_PIX_SZ 2
#endif
#ifndef VI_EURGB60
#define VI_EURGB60 5
#endif
#ifndef VI_INTERLACE
#define VI_INTERLACE 0
#endif
#ifndef VI_MAX_HEIGHT_EURGB60
#define VI_MAX_HEIGHT_EURGB60 VI_MAX_HEIGHT_NTSC
#endif
#ifndef VI_MAX_HEIGHT_MPAL
#define VI_MAX_HEIGHT_MPAL 480
#endif
#ifndef VI_MAX_HEIGHT_NTSC
#define VI_MAX_HEIGHT_NTSC 480
#endif
#ifndef VI_MAX_HEIGHT_PAL
#define VI_MAX_HEIGHT_PAL 576
#endif
#ifndef VI_MAX_WIDTH_EURGB60
#define VI_MAX_WIDTH_EURGB60 VI_MAX_WIDTH_NTSC
#endif
#ifndef VI_MAX_WIDTH_MPAL
#define VI_MAX_WIDTH_MPAL 720
#endif
#ifndef VI_MAX_WIDTH_NTSC
#define VI_MAX_WIDTH_NTSC 720
#endif
#ifndef VI_MAX_WIDTH_PAL
#define VI_MAX_WIDTH_PAL 720
#endif
#ifndef VI_MPAL
#define VI_MPAL 2
#endif
#ifndef VI_NON_INTERLACE
#define VI_NON_INTERLACE 1
#endif
#ifndef VI_NTSC
#define VI_NTSC 0
#endif
#ifndef VI_PAL
#define VI_PAL 1
#endif
#ifndef VI_PROGRESSIVE
#define VI_PROGRESSIVE 2
#endif
#ifndef VI_XFBMODE_DF
#define VI_XFBMODE_DF 1
#endif
#ifndef VI_XFBMODE_SF
#define VI_XFBMODE_SF 0
#endif
typedef struct { u32 dummy[8]; } syssram;
/* Drawing primitives libogc gives as inline functions */
static inline void GX_Position3f32(f32 x, f32 y, f32 z) { (void)x; (void)y; (void)z; }
static inline void GX_Position1x8(u8 i) { (void)i; }
static inline void GX_Color4u8(u8 r, u8 g, u8 b, u8 a) { (void)r; (void)g; (void)b; (void)a; }
static inline void GX_Color1x8(u8 i) { (void)i; }
static inline void GX_TexCoord2f32(f32 s, f32 t) { (void)s; (void)t; }
static inline void GX_TexCoord1x8(u8 i) { (void)i; }
static inline void GX_End(void) { }
void VIDEO_SetGamma(int gamma);
/* The matrix helpers the driver sets its projection up with */
void guOrtho(Mtx44 mt, f32 t, f32 b, f32 l, f32 r, f32 n, f32 f);
void guMtxIdentity(Mtx mt);
void c_guMtxConcat(Mtx a, Mtx b, Mtx ab);
void DCFlushRange(void *startaddress, u32 len);
void DCInvalidateRange(void *startaddress, u32 len);
void guMtxRotDeg(Mtx mt, const char axis, f32 deg);
/* The threading calls libretro-common's gx_defines.h maps OS* onto */
void LWP_InitQueue(lwpq_t *queue);
void LWP_CloseQueue(lwpq_t queue);
void LWP_ThreadSignal(lwpq_t queue);
void LWP_ThreadBroadcast(lwpq_t queue);
s32 LWP_ThreadSleep(lwpq_t queue);
s32 LWP_MutexInit(mutex_t *mutex, bool use_recursive);
s32 LWP_MutexLock(mutex_t mutex);
s32 LWP_MutexTryLock(mutex_t mutex);
s32 LWP_MutexUnlock(mutex_t mutex);
s32 LWP_MutexDestroy(mutex_t mutex);
s32 LWP_CondInit(lwpq_t *cond);
s32 LWP_CondWait(lwpq_t cond, mutex_t mutex);
s32 LWP_CondDestroy(lwpq_t cond);
s32 LWP_CreateThread(lwp_t *thethread, void *(*entry)(void *),
void *arg, void *stackbase, u32 stack_size, u8 prio);
s32 LWP_JoinThread(lwp_t thethread, void **value_ptr);
void VIDEO_SetTrapFilter(bool enable);
#ifndef CONF_ASPECT_4_3
#define CONF_ASPECT_4_3 0
#endif
#ifndef GX_AF_NONE
#define GX_AF_NONE 2
#endif
#ifndef GX_ALWAYS
#define GX_ALWAYS 7
#endif
#ifndef GX_BL_INVSRCALPHA
#define GX_BL_INVSRCALPHA 5
#endif
#ifndef GX_BL_SRCALPHA
#define GX_BL_SRCALPHA 4
#endif
#ifndef GX_BM_BLEND
#define GX_BM_BLEND 1
#endif
#ifndef GX_CLAMP
#define GX_CLAMP 0
#endif
#ifndef GX_CLIP_DISABLE
#define GX_CLIP_DISABLE 1
#endif
#ifndef GX_CLR_RGBA
#define GX_CLR_RGBA 1
#endif
#ifndef GX_COLOR0A0
#define GX_COLOR0A0 4
#endif
#ifndef GX_CULL_NONE
#define GX_CULL_NONE 0
#endif
#ifndef GX_DF_NONE
#define GX_DF_NONE 0
#endif
#ifndef GX_DIRECT
#define GX_DIRECT 1
#endif
#ifndef GX_DISABLE
#define GX_DISABLE 0
#endif
#ifndef GX_ENABLE
#define GX_ENABLE 1
#endif
#ifndef GX_F32
#define GX_F32 4
#endif
#ifndef GX_FALSE
#define GX_FALSE 0
#endif
#ifndef GX_INDEX8
#define GX_INDEX8 2
#endif
#ifndef GX_LIGHTNULL
#define GX_LIGHTNULL 0x000
#endif
#ifndef GX_LINEAR
#define GX_LINEAR 1
#endif
#ifndef GX_LO_CLEAR
#define GX_LO_CLEAR 0
#endif
#ifndef GX_MAX_Z24
#define GX_MAX_Z24 0x00ffffff
#endif
#ifndef GX_MODULATE
#define GX_MODULATE 0
#endif
#ifndef GX_NEAR
#define GX_NEAR 0
#endif
#ifndef GX_ORTHOGRAPHIC
#define GX_ORTHOGRAPHIC 1
#endif
#ifndef GX_PF_RGB8_Z24
#define GX_PF_RGB8_Z24 0
#endif
#ifndef GX_PNMTX0
#define GX_PNMTX0 0
#endif
#ifndef GX_PNMTX1
#define GX_PNMTX1 3
#endif
#ifndef GX_POS_XYZ
#define GX_POS_XYZ 1
#endif
#ifndef GX_RGBA8
#define GX_RGBA8 5
#endif
#ifndef GX_SRC_REG
#define GX_SRC_REG 0
#endif
#ifndef GX_SRC_VTX
#define GX_SRC_VTX 1
#endif
#ifndef GX_TEVSTAGE0
#define GX_TEVSTAGE0 0
#endif
#ifndef GX_TEXCOORD0
#define GX_TEXCOORD0 0x0
#endif
#ifndef GX_TEXMAP0
#define GX_TEXMAP0 0
#endif
#ifndef GX_TEX_ST
#define GX_TEX_ST 1
#endif
#ifndef GX_TF_RGB565
#define GX_TF_RGB565 0x4
#endif
#ifndef GX_TF_RGB5A3
#define GX_TF_RGB5A3 0x5
#endif
#ifndef GX_TF_RGBA8
#define GX_TF_RGBA8 0x6
#endif
#ifndef GX_TRIANGLESTRIP
#define GX_TRIANGLESTRIP 0x98
#endif
#ifndef GX_TRUE
#define GX_TRUE 1
#endif
#ifndef GX_VA_CLR0
#define GX_VA_CLR0 11
#endif
#ifndef GX_VA_POS
#define GX_VA_POS 9
#endif
#ifndef GX_VA_TEX0
#define GX_VA_TEX0 13
#endif
#ifndef GX_VTXFMT0
#define GX_VTXFMT0 0
#endif
#ifndef GX_ZC_LINEAR
#define GX_ZC_LINEAR 0
#endif
#ifndef LWP_TQUEUE_NULL
#define LWP_TQUEUE_NULL 0xffffffff
#endif
s32 CONF_GetAspectRatio(void);
s32 CONF_GetDisplayOffsetH(s8 *offset);
s32 CONF_GetEuRGB60(void);
s32 CONF_GetProgressiveScan(void);
s32 CONF_GetVideo(void);
void GX_AbortFrame(void);
void GX_Begin(u8 primitve,u8 vtxfmt,u16 vtxcnt);
void GX_BeginDispList(void *list,u32 size);
void GX_CallDispList(void *list,u32 nbytes);
void GX_ClearVtxDesc(void);
void GX_CopyDisp(void *dest,u8 clear);
void GX_DrawDone(void);
u32 GX_EndDispList(void);
void GX_Flush(void);
f32 GX_GetYScaleFactor(u16 efbHeight,u16 xfbHeight);
GXFifoObj* GX_Init(void *base,u32 size);
void GX_InitTexObj(GXTexObj *obj,void *img_ptr,u16 wd,u16 ht,u8 fmt,u8 wrap_s,u8 wrap_t,u8 mipmap);
void GX_InitTexObjFilterMode(GXTexObj *obj,u8 minfilt,u8 magfilt);
void GX_InvVtxCache(void);
void GX_InvalidateTexAll(void);
void GX_LoadPosMtxImm(Mtx mt,u32 pnidx);
void GX_LoadProjectionMtx(Mtx44 mt,u8 type);
void GX_LoadTexObj(GXTexObj *obj,u8 mapid);
void GX_PeekARGB(u16 x,u16 y,GXColor *color);
void GX_PokeARGB(u16 x,u16 y,GXColor color);
void GX_SetAlphaUpdate(u8 enable);
void GX_SetArray(u32 attr,void *ptr,u8 stride);
void GX_SetBlendMode(u8 type,u8 src_fact,u8 dst_fact,u8 op);
void GX_SetChanCtrl(s32 channel,u8 enable,u8 ambsrc,u8 matsrc,u8 litmask,u8 diff_fn,u8 attn_fn);
void GX_SetClipMode(u8 mode);
void GX_SetColorUpdate(u8 enable);
void GX_SetCopyClear(GXColor color,u32 zvalue);
void GX_SetCopyFilter(u8 aa,u8 sample_pattern[12][2],u8 vf,u8 vfilter[7]);
void GX_SetCullMode(u8 mode);
void GX_SetCurrentMtx(u32 mtx);
void GX_SetDispCopyDst(u16 wd,u16 ht);
void GX_SetDispCopyGamma(u8 gamma);
void GX_SetDispCopySrc(u16 left,u16 top,u16 wd,u16 ht);
u32 GX_SetDispCopyYScale(f32 yscale);
void GX_SetFieldMode(u8 field_mode,u8 half_aspect_ratio);
void GX_SetNumChans(u8 num);
void GX_SetNumTexGens(u32 nr);
void GX_SetPixelFmt(u8 pix_fmt,u8 z_fmt);
void GX_SetTevOp(u8 tevstage,u8 mode);
void GX_SetTevOrder(u8 tevstage,u8 texcoord,u32 texmap,u8 color);
void GX_SetViewportJitter(f32 xOrig,f32 yOrig,f32 wd,f32 ht,f32 nearZ,f32 farZ,u32 field);
void GX_SetVtxAttrFmt(u8 vtxfmt,u32 vtxattr,u32 comptype,u32 compsize,u32 frac);
void GX_SetVtxDesc(u8 attr,u8 type);
void GX_SetZMode(u8 enable,u8 func,u8 update_enable);
u32 SYS_GetArena1Size(void);
void VIDEO_ClearFrameBuffer(GXRModeObj *rmode,void *fb,u32 color);
void VIDEO_Configure(GXRModeObj *rmode);
void VIDEO_Flush(void);
u32 VIDEO_GetCurrentTvMode(void);
u32 VIDEO_GetNextField(void);
GXRModeObj * VIDEO_GetPreferredMode(GXRModeObj *mode);
u32 VIDEO_HaveComponentCable(void);
void VIDEO_Init(void);
void VIDEO_SetBlack(bool black);
void VIDEO_SetNextFramebuffer(void *fb);
VIRetraceCallback VIDEO_SetPostRetraceCallback(VIRetraceCallback callback);
void VIDEO_WaitVSync(void);
uint32_t SYS_GetArena1Size(void);
#endif
+2 -2
View File
@@ -1,4 +1,4 @@
#ifndef LIBOGC_STUB_OGCSYS_H
#define LIBOGC_STUB_OGCSYS_H
#ifndef STUB_OGCSYS_H
#define STUB_OGCSYS_H
#include <gccore.h>
#endif
+5 -54
View File
@@ -1,58 +1,9 @@
/* Stand-in for devkitPro's libnx <switch.h>.
*
* Only what the translation units checked here name, declared with the
* shapes libnx gives them. As the note at the top of compile-matrix.sh
* says, this does not prove the real SDK matches: it proves RetroArch's
* own Switch code is well formed and that every symbol it uses is one it
* has arranged to have. That is the class of breakage these lanes are
* for - a driver naming a struct member or a setting that moved.
*/
#ifndef LIBNX_STUB_SWITCH_H
#define LIBNX_STUB_SWITCH_H
#ifndef STUB_SWITCH_H
#define STUB_SWITCH_H
#include <stdint.h>
#include <stddef.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int32_t s32;
typedef uint32_t Result;
/* mem_stats.c */
#define R_SUCCEEDED(r) ((r) == 0)
#define CUR_PROCESS_HANDLE 0
typedef enum { InfoType_TotalMemorySize = 6, InfoType_UsedMemorySize = 7 } InfoType;
#define CUR_PROCESS_HANDLE 0xFFFF8001
#define R_SUCCEEDED(res) ((res) == 0)
#define R_FAILED(res) ((res) != 0)
Result svcGetInfo(u64 *out, u32 id, u32 handle, u64 sub);
/* The window and framebuffer the Switch video driver draws through */
typedef struct NWindow NWindow;
typedef struct
{
void *buf;
u32 stride;
} Framebuffer;
typedef enum
{
PIXEL_FORMAT_RGBA_8888 = 1
} PixelFormat;
NWindow *nwindowGetDefault(void);
Result nwindowSetDimensions(NWindow *nw, u32 width, u32 height);
Result framebufferCreate(Framebuffer *fb, NWindow *win,
u32 width, u32 height, u32 format, u32 num_fbs);
Result framebufferMakeLinear(Framebuffer *fb);
void *framebufferBegin(Framebuffer *fb, u32 *out_stride);
void framebufferEnd(Framebuffer *fb);
void framebufferClose(Framebuffer *fb);
/* the kernel random source the crypto's random path draws on */
void randomGet(void *buf, size_t len);
Result svcGetInfo(uint64_t *out, uint32_t id, uint32_t handle, uint64_t sub);
#endif
@@ -1,636 +0,0 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef WEBOS_FOREIGN_CLIENT_PROTOCOL_H
#define WEBOS_FOREIGN_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_webos_foreign The webos_foreign protocol
* @section page_ifaces_webos_foreign Interfaces
* - @subpage page_iface_wl_webos_foreign - interface for handling foreign surfaces
* - @subpage page_iface_wl_webos_exported - interface for handling exported window
* - @subpage page_iface_wl_webos_imported - interface for imported content or punchthrough region
* @section page_copyright_webos_foreign Copyright
* <pre>
*
* Copyright (c) 2018-2019 LG Electronics, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* </pre>
*/
struct wl_region;
struct wl_surface;
struct wl_webos_exported;
struct wl_webos_foreign;
struct wl_webos_imported;
#ifndef WL_WEBOS_FOREIGN_INTERFACE
#define WL_WEBOS_FOREIGN_INTERFACE
/**
* @page page_iface_wl_webos_foreign wl_webos_foreign
* @section page_iface_wl_webos_foreign_desc Description
*
* This interface defines a way to associate one or more foreign surfaces from
* different clients or a punch-through region to a surface that acts the main
* window.
*
* You can set a region on the main window where a foreign surface or a
* punch-through region can be placed. It is called "exported" region or window
* in this protocol. Then you can request the compositor to punch through that
* region or attach another surface as an "imported" content.
* @section page_iface_wl_webos_foreign_api API
* See @ref iface_wl_webos_foreign.
*/
/**
* @defgroup iface_wl_webos_foreign The wl_webos_foreign interface
*
* This interface defines a way to associate one or more foreign surfaces from
* different clients or a punch-through region to a surface that acts the main
* window.
*
* You can set a region on the main window where a foreign surface or a
* punch-through region can be placed. It is called "exported" region or window
* in this protocol. Then you can request the compositor to punch through that
* region or attach another surface as an "imported" content.
*/
extern const struct wl_interface wl_webos_foreign_interface;
#endif
#ifndef WL_WEBOS_EXPORTED_INTERFACE
#define WL_WEBOS_EXPORTED_INTERFACE
/**
* @page page_iface_wl_webos_exported wl_webos_exported
* @section page_iface_wl_webos_exported_desc Description
*
* This interface defines operations and notifications on an exported window.
* @section page_iface_wl_webos_exported_api API
* See @ref iface_wl_webos_exported.
*/
/**
* @defgroup iface_wl_webos_exported The wl_webos_exported interface
*
* This interface defines operations and notifications on an exported window.
*/
extern const struct wl_interface wl_webos_exported_interface;
#endif
#ifndef WL_WEBOS_IMPORTED_INTERFACE
#define WL_WEBOS_IMPORTED_INTERFACE
/**
* @page page_iface_wl_webos_imported wl_webos_imported
* @section page_iface_wl_webos_imported_desc Description
*
* This interface defines operations and notifications on an imported object.
* @section page_iface_wl_webos_imported_api API
* See @ref iface_wl_webos_imported.
*/
/**
* @defgroup iface_wl_webos_imported The wl_webos_imported interface
*
* This interface defines operations and notifications on an imported object.
*/
extern const struct wl_interface wl_webos_imported_interface;
#endif
#ifndef WL_WEBOS_FOREIGN_WEBOS_EXPORTED_TYPE_ENUM
#define WL_WEBOS_FOREIGN_WEBOS_EXPORTED_TYPE_ENUM
/**
* @ingroup iface_wl_webos_foreign
* type of webos_exported
*
* This indicates the type of the content that the exported window can show.
*/
enum wl_webos_foreign_webos_exported_type {
/**
* exported window for video object
*/
WL_WEBOS_FOREIGN_WEBOS_EXPORTED_TYPE_VIDEO_OBJECT = 0,
/**
* exported window for subtitle object
*/
WL_WEBOS_FOREIGN_WEBOS_EXPORTED_TYPE_SUBTITLE_OBJECT = 1,
/**
* exported window for transparent object that does not need to punch through other windows
*/
WL_WEBOS_FOREIGN_WEBOS_EXPORTED_TYPE_TRANSPARENT_OBJECT = 2,
/**
* exported window for opaque object that always needs to punch through other windows
*/
WL_WEBOS_FOREIGN_WEBOS_EXPORTED_TYPE_OPAQUE_OBJECT = 3,
};
#endif /* WL_WEBOS_FOREIGN_WEBOS_EXPORTED_TYPE_ENUM */
#define WL_WEBOS_FOREIGN_DESTROY 0
#define WL_WEBOS_FOREIGN_EXPORT_ELEMENT 1
#define WL_WEBOS_FOREIGN_IMPORT_ELEMENT 2
/**
* @ingroup iface_wl_webos_foreign
*/
#define WL_WEBOS_FOREIGN_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_foreign
*/
#define WL_WEBOS_FOREIGN_EXPORT_ELEMENT_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_foreign
*/
#define WL_WEBOS_FOREIGN_IMPORT_ELEMENT_SINCE_VERSION 1
/** @ingroup iface_wl_webos_foreign */
static inline void
wl_webos_foreign_set_user_data(struct wl_webos_foreign *wl_webos_foreign, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_foreign, user_data);
}
/** @ingroup iface_wl_webos_foreign */
static inline void *
wl_webos_foreign_get_user_data(struct wl_webos_foreign *wl_webos_foreign)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_foreign);
}
static inline uint32_t
wl_webos_foreign_get_version(struct wl_webos_foreign *wl_webos_foreign)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_foreign);
}
/**
* @ingroup iface_wl_webos_foreign
*
* Destroys the foreign object.
*/
static inline void
wl_webos_foreign_destroy(struct wl_webos_foreign *wl_webos_foreign)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_foreign,
WL_WEBOS_FOREIGN_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_foreign), WL_MARSHAL_FLAG_DESTROY);
}
/**
* @ingroup iface_wl_webos_foreign
*
* Requests to create an exported window on a given surface.
*/
static inline struct wl_webos_exported *
wl_webos_foreign_export_element(struct wl_webos_foreign *wl_webos_foreign, struct wl_surface *surface, uint32_t exported_type)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_foreign,
WL_WEBOS_FOREIGN_EXPORT_ELEMENT, &wl_webos_exported_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_foreign), 0, NULL, surface, exported_type);
return (struct wl_webos_exported *) id;
}
/**
* @ingroup iface_wl_webos_foreign
*
* Requests an import object that can be associated with a given exported window.
*/
static inline struct wl_webos_imported *
wl_webos_foreign_import_element(struct wl_webos_foreign *wl_webos_foreign, const char *window_id, uint32_t exported_type)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_foreign,
WL_WEBOS_FOREIGN_IMPORT_ELEMENT, &wl_webos_imported_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_foreign), 0, NULL, window_id, exported_type);
return (struct wl_webos_imported *) id;
}
/**
* @ingroup iface_wl_webos_exported
* @struct wl_webos_exported_listener
*/
struct wl_webos_exported_listener {
/**
* window is associated with this wl_webos_exported
*
* Notifies window_id of the exported window.
* @param window_id window_id of associated exported window
*/
void (*window_id_assigned)(void *data,
struct wl_webos_exported *wl_webos_exported,
const char *window_id,
uint32_t exported_type);
};
/**
* @ingroup iface_wl_webos_exported
*/
static inline int
wl_webos_exported_add_listener(struct wl_webos_exported *wl_webos_exported,
const struct wl_webos_exported_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_exported,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_EXPORTED_DESTROY 0
#define WL_WEBOS_EXPORTED_SET_EXPORTED_WINDOW 1
#define WL_WEBOS_EXPORTED_SET_CROP_REGION 2
#define WL_WEBOS_EXPORTED_SET_PROPERTY 3
/**
* @ingroup iface_wl_webos_exported
*/
#define WL_WEBOS_EXPORTED_WINDOW_ID_ASSIGNED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_exported
*/
#define WL_WEBOS_EXPORTED_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_exported
*/
#define WL_WEBOS_EXPORTED_SET_EXPORTED_WINDOW_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_exported
*/
#define WL_WEBOS_EXPORTED_SET_CROP_REGION_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_exported
*/
#define WL_WEBOS_EXPORTED_SET_PROPERTY_SINCE_VERSION 2
/** @ingroup iface_wl_webos_exported */
static inline void
wl_webos_exported_set_user_data(struct wl_webos_exported *wl_webos_exported, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_exported, user_data);
}
/** @ingroup iface_wl_webos_exported */
static inline void *
wl_webos_exported_get_user_data(struct wl_webos_exported *wl_webos_exported)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_exported);
}
static inline uint32_t
wl_webos_exported_get_version(struct wl_webos_exported *wl_webos_exported)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_exported);
}
/**
* @ingroup iface_wl_webos_exported
*
* Destroys the exported object.
*/
static inline void
wl_webos_exported_destroy(struct wl_webos_exported *wl_webos_exported)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_exported,
WL_WEBOS_EXPORTED_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_exported), WL_MARSHAL_FLAG_DESTROY);
}
/**
* @ingroup iface_wl_webos_exported
*
* Sets the exported window with source and destination regions.
*/
static inline void
wl_webos_exported_set_exported_window(struct wl_webos_exported *wl_webos_exported, struct wl_region *source_region, struct wl_region *destination_region)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_exported,
WL_WEBOS_EXPORTED_SET_EXPORTED_WINDOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_exported), 0, source_region, destination_region);
}
/**
* @ingroup iface_wl_webos_exported
*
* Sets a region to be cropped.
*/
static inline void
wl_webos_exported_set_crop_region(struct wl_webos_exported *wl_webos_exported, struct wl_region *original_input, struct wl_region *source_region, struct wl_region *destination_region)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_exported,
WL_WEBOS_EXPORTED_SET_CROP_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_exported), 0, original_input, source_region, destination_region);
}
/**
* @ingroup iface_wl_webos_exported
*
* Sets a property for this webos_exported. The property is given by a string pair (name, value).
*/
static inline void
wl_webos_exported_set_property(struct wl_webos_exported *wl_webos_exported, const char *name, const char *value)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_exported,
WL_WEBOS_EXPORTED_SET_PROPERTY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_exported), 0, name, value);
}
#ifndef WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_ENUM
#define WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_ENUM
/**
* @ingroup iface_wl_webos_imported
* surface alignment
*
* The alignment of an imported surface on the associated exported window.
*/
enum wl_webos_imported_surface_alignment {
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_STRETCH = 0,
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_NORTH = 1,
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_WEST = 2,
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_SOUTH = 4,
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_EAST = 8,
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_CENTER = 16,
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_CROP = 32,
WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_FIT = 64,
};
#endif /* WL_WEBOS_IMPORTED_SURFACE_ALIGNMENT_ENUM */
/**
* @ingroup iface_wl_webos_imported
* @struct wl_webos_imported_listener
*/
struct wl_webos_imported_listener {
/**
* destination region changed
*
* Notifies the change of the destination region of associated
* exported window.
* @param width destination width of exported window
* @param height destination height of exported window
*/
void (*destination_region_changed)(void *data,
struct wl_webos_imported *wl_webos_imported,
uint32_t width,
uint32_t height);
/**
* punchthrough attached
*
* Notifies that a punchthrough is attached to webos_imported.
* @since 2
*/
void (*punchthrough_attached)(void *data,
struct wl_webos_imported *wl_webos_imported,
const char *context_id);
/**
* punchthrough detached
*
* Notifies that a punchthrough is detached from webos_imported.
* @since 2
*/
void (*punchthrough_detached)(void *data,
struct wl_webos_imported *wl_webos_imported,
const char *context_id);
/**
* surface attached
*
* Notifies that a surface is attached to webos_imported.
* @since 2
*/
void (*surface_attached)(void *data,
struct wl_webos_imported *wl_webos_imported,
struct wl_surface *surface);
/**
* surface detached
*
* Notifies that a surface is detached from webos_imported.
* @since 2
*/
void (*surface_detached)(void *data,
struct wl_webos_imported *wl_webos_imported,
struct wl_surface *surface);
};
/**
* @ingroup iface_wl_webos_imported
*/
static inline int
wl_webos_imported_add_listener(struct wl_webos_imported *wl_webos_imported,
const struct wl_webos_imported_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_imported,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_IMPORTED_SET_SURFACE_ALIGNMENT 0
#define WL_WEBOS_IMPORTED_DESTROY 1
#define WL_WEBOS_IMPORTED_ATTACH_PUNCHTHROUGH 2
#define WL_WEBOS_IMPORTED_SET_PUNCHTHROUGH 3
#define WL_WEBOS_IMPORTED_DETACH_PUNCHTHROUGH 4
#define WL_WEBOS_IMPORTED_ATTACH_SURFACE 5
#define WL_WEBOS_IMPORTED_DETACH_SURFACE 6
#define WL_WEBOS_IMPORTED_ATTACH_PUNCHTHROUGH_WITH_CONTEXT 7
#define WL_WEBOS_IMPORTED_SET_Z_INDEX 8
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_DESTINATION_REGION_CHANGED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_PUNCHTHROUGH_ATTACHED_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_PUNCHTHROUGH_DETACHED_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_SURFACE_ATTACHED_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_SURFACE_DETACHED_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_SET_SURFACE_ALIGNMENT_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_ATTACH_PUNCHTHROUGH_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_SET_PUNCHTHROUGH_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_DETACH_PUNCHTHROUGH_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_ATTACH_SURFACE_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_DETACH_SURFACE_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_ATTACH_PUNCHTHROUGH_WITH_CONTEXT_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_imported
*/
#define WL_WEBOS_IMPORTED_SET_Z_INDEX_SINCE_VERSION 2
/** @ingroup iface_wl_webos_imported */
static inline void
wl_webos_imported_set_user_data(struct wl_webos_imported *wl_webos_imported, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_imported, user_data);
}
/** @ingroup iface_wl_webos_imported */
static inline void *
wl_webos_imported_get_user_data(struct wl_webos_imported *wl_webos_imported)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_imported);
}
static inline uint32_t
wl_webos_imported_get_version(struct wl_webos_imported *wl_webos_imported)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_imported);
}
/**
* @ingroup iface_wl_webos_imported
*
* Sets the alignment of the imported surface.
*/
static inline void
wl_webos_imported_set_surface_alignment(struct wl_webos_imported *wl_webos_imported, uint32_t format)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_SET_SURFACE_ALIGNMENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0, format);
}
/**
* @ingroup iface_wl_webos_imported
*
* Destroys the imported object.
*/
static inline void
wl_webos_imported_destroy(struct wl_webos_imported *wl_webos_imported)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), WL_MARSHAL_FLAG_DESTROY);
}
/**
* @ingroup iface_wl_webos_imported
*
* Requests a punch-through on the exporetd window associated with
* this import object.
*/
static inline void
wl_webos_imported_attach_punchthrough(struct wl_webos_imported *wl_webos_imported)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_ATTACH_PUNCHTHROUGH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0);
}
/**
* @ingroup iface_wl_webos_imported
*/
static inline void
wl_webos_imported_set_punchthrough(struct wl_webos_imported *wl_webos_imported, const char *context_id)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_SET_PUNCHTHROUGH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0, context_id);
}
/**
* @ingroup iface_wl_webos_imported
*
* Requests to detatch the punch-through from the exported window
* associated with this import object.
*/
static inline void
wl_webos_imported_detach_punchthrough(struct wl_webos_imported *wl_webos_imported)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_DETACH_PUNCHTHROUGH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0);
}
/**
* @ingroup iface_wl_webos_imported
*
* Requests to attach the surface as imported to the associated
* exported window.
*/
static inline void
wl_webos_imported_attach_surface(struct wl_webos_imported *wl_webos_imported, struct wl_surface *surface)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_ATTACH_SURFACE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0, surface);
}
/**
* @ingroup iface_wl_webos_imported
*
* Requests to detach the surface as imported from the associated
* exported window.
*/
static inline void
wl_webos_imported_detach_surface(struct wl_webos_imported *wl_webos_imported, struct wl_surface *surface)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_DETACH_SURFACE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0, surface);
}
/**
* @ingroup iface_wl_webos_imported
*
* Requests a punch-through on the exporetd window associated with
* this import object for a given context id.
*/
static inline void
wl_webos_imported_attach_punchthrough_with_context(struct wl_webos_imported *wl_webos_imported, const char *context_id)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_ATTACH_PUNCHTHROUGH_WITH_CONTEXT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0, context_id);
}
/**
* @ingroup iface_wl_webos_imported
*
* Set the z index for webos_imported. The compositor will move the surface,
* that is attached to webos_imported, to this layer. If no surface is attached to
* webos_imported, nothing will happen.
*/
static inline void
wl_webos_imported_set_z_index(struct wl_webos_imported *wl_webos_imported, int32_t z_index)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_imported,
WL_WEBOS_IMPORTED_SET_Z_INDEX, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_imported), 0, z_index);
}
#ifdef __cplusplus
}
#endif
#endif
@@ -1,530 +0,0 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef WEBOS_INPUT_MANAGER_CLIENT_PROTOCOL_H
#define WEBOS_INPUT_MANAGER_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_webos_input_manager The webos_input_manager protocol
* @section page_ifaces_webos_input_manager Interfaces
* - @subpage page_iface_wl_webos_input_manager - get additional input interface
* - @subpage page_iface_wl_webos_seat - interface for additional input data
* - @subpage page_iface_wl_webos_gyroscope - interface for gyroscope device
* - @subpage page_iface_wl_webos_accelerometer - interface for accelerometer device
* @section page_copyright_webos_input_manager Copyright
* <pre>
*
* Copyright (c) 2014-2020 LG Electronics, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* </pre>
*/
struct wl_seat;
struct wl_webos_accelerometer;
struct wl_webos_gyroscope;
struct wl_webos_input_manager;
struct wl_webos_seat;
#ifndef WL_WEBOS_INPUT_MANAGER_INTERFACE
#define WL_WEBOS_INPUT_MANAGER_INTERFACE
/**
* @page page_iface_wl_webos_input_manager wl_webos_input_manager
* @section page_iface_wl_webos_input_manager_desc Description
*
* wl_webos_seat has more information than wl_seat. User can get it using
* get_webos_seat(seat).
* @section page_iface_wl_webos_input_manager_api API
* See @ref iface_wl_webos_input_manager.
*/
/**
* @defgroup iface_wl_webos_input_manager The wl_webos_input_manager interface
*
* wl_webos_seat has more information than wl_seat. User can get it using
* get_webos_seat(seat).
*/
extern const struct wl_interface wl_webos_input_manager_interface;
#endif
#ifndef WL_WEBOS_SEAT_INTERFACE
#define WL_WEBOS_SEAT_INTERFACE
/**
* @page page_iface_wl_webos_seat wl_webos_seat
* @section page_iface_wl_webos_seat_desc Description
*
* This is a webOS extension for additional input data such as gyroscope or
* accelerometer. If the seat has additional input data, user can request it
* using get_*.
* @section page_iface_wl_webos_seat_api API
* See @ref iface_wl_webos_seat.
*/
/**
* @defgroup iface_wl_webos_seat The wl_webos_seat interface
*
* This is a webOS extension for additional input data such as gyroscope or
* accelerometer. If the seat has additional input data, user can request it
* using get_*.
*/
extern const struct wl_interface wl_webos_seat_interface;
#endif
#ifndef WL_WEBOS_GYROSCOPE_INTERFACE
#define WL_WEBOS_GYROSCOPE_INTERFACE
/**
* @page page_iface_wl_webos_gyroscope wl_webos_gyroscope
* @section page_iface_wl_webos_gyroscope_desc Description
*
* This is an interface for gyroscope device.
* @section page_iface_wl_webos_gyroscope_api API
* See @ref iface_wl_webos_gyroscope.
*/
/**
* @defgroup iface_wl_webos_gyroscope The wl_webos_gyroscope interface
*
* This is an interface for gyroscope device.
*/
extern const struct wl_interface wl_webos_gyroscope_interface;
#endif
#ifndef WL_WEBOS_ACCELEROMETER_INTERFACE
#define WL_WEBOS_ACCELEROMETER_INTERFACE
/**
* @page page_iface_wl_webos_accelerometer wl_webos_accelerometer
* @section page_iface_wl_webos_accelerometer_desc Description
*
* This is an interface for accelerometer device.
* @section page_iface_wl_webos_accelerometer_api API
* See @ref iface_wl_webos_accelerometer.
*/
/**
* @defgroup iface_wl_webos_accelerometer The wl_webos_accelerometer interface
*
* This is an interface for accelerometer device.
*/
extern const struct wl_interface wl_webos_accelerometer_interface;
#endif
/**
* @ingroup iface_wl_webos_input_manager
* @struct wl_webos_input_manager_listener
*/
struct wl_webos_input_manager_listener {
/**
* current cursor visibility
*
* If the current cursor visibility is chagned, notify it.
* @param visibility boolean vaule for visibility of current cursor
* @param webos_seat webos_seat cursor visibility changed, if this value is Null All cursors are hidden
*/
void (*cursor_visibility)(void *data,
struct wl_webos_input_manager *wl_webos_input_manager,
uint32_t visibility,
struct wl_webos_seat *webos_seat);
};
/**
* @ingroup iface_wl_webos_input_manager
*/
static inline int
wl_webos_input_manager_add_listener(struct wl_webos_input_manager *wl_webos_input_manager,
const struct wl_webos_input_manager_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_input_manager,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_INPUT_MANAGER_GET_WEBOS_SEAT 0
#define WL_WEBOS_INPUT_MANAGER_SET_CURSOR_VISIBILITY 1
/**
* @ingroup iface_wl_webos_input_manager
*/
#define WL_WEBOS_INPUT_MANAGER_CURSOR_VISIBILITY_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_input_manager
*/
#define WL_WEBOS_INPUT_MANAGER_GET_WEBOS_SEAT_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_input_manager
*/
#define WL_WEBOS_INPUT_MANAGER_SET_CURSOR_VISIBILITY_SINCE_VERSION 1
/** @ingroup iface_wl_webos_input_manager */
static inline void
wl_webos_input_manager_set_user_data(struct wl_webos_input_manager *wl_webos_input_manager, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_input_manager, user_data);
}
/** @ingroup iface_wl_webos_input_manager */
static inline void *
wl_webos_input_manager_get_user_data(struct wl_webos_input_manager *wl_webos_input_manager)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_input_manager);
}
static inline uint32_t
wl_webos_input_manager_get_version(struct wl_webos_input_manager *wl_webos_input_manager)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_input_manager);
}
/** @ingroup iface_wl_webos_input_manager */
static inline void
wl_webos_input_manager_destroy(struct wl_webos_input_manager *wl_webos_input_manager)
{
wl_proxy_destroy((struct wl_proxy *) wl_webos_input_manager);
}
/**
* @ingroup iface_wl_webos_input_manager
*
* Returns a webos_seat associated with the seat.
*/
static inline struct wl_webos_seat *
wl_webos_input_manager_get_webos_seat(struct wl_webos_input_manager *wl_webos_input_manager, struct wl_seat *seat)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_input_manager,
WL_WEBOS_INPUT_MANAGER_GET_WEBOS_SEAT, &wl_webos_seat_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_input_manager), 0, NULL, seat);
return (struct wl_webos_seat *) id;
}
/**
* @ingroup iface_wl_webos_input_manager
*
* Sets the cursor visibility.
*/
static inline void
wl_webos_input_manager_set_cursor_visibility(struct wl_webos_input_manager *wl_webos_input_manager, uint32_t visibility)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_input_manager,
WL_WEBOS_INPUT_MANAGER_SET_CURSOR_VISIBILITY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_input_manager), 0, visibility);
}
#ifndef WL_WEBOS_SEAT_CAPABILITY_ENUM
#define WL_WEBOS_SEAT_CAPABILITY_ENUM
/**
* @ingroup iface_wl_webos_seat
* webos seat capability bitmask
*
* This is a bitmask of capabilities this webOS seat has; if a member is
* set, then it is present on the seat.
*/
enum wl_webos_seat_capability {
/**
* this seat does not provide additional input
*/
WL_WEBOS_SEAT_CAPABILITY_DEFAULT = 0,
/**
* this seat can provide gyroscope data, wl_webos_gyroscope
*/
WL_WEBOS_SEAT_CAPABILITY_GYROSCOPE = 1,
/**
* this seat can provide accelerometer data, wl_webos_accelerometer
*/
WL_WEBOS_SEAT_CAPABILITY_ACCELEROMETER = 2,
};
#endif /* WL_WEBOS_SEAT_CAPABILITY_ENUM */
/**
* @ingroup iface_wl_webos_seat
* @struct wl_webos_seat_listener
*/
struct wl_webos_seat_listener {
/**
* info about the seat
*
* This event will be sent immediately after the client as
* requested the webOS seat from wl_webos_input_manager.
*
* The designator [0, 1, ... N] indicates if this is the
* primary(=0), secondary, etc seat.
* @param id an unique identifier for the seat
* @param name a human readable name for the seat
* @param designator a value for the designation of this seat
*/
void (*info)(void *data,
struct wl_webos_seat *wl_webos_seat,
uint32_t id,
const char *name,
uint32_t designator,
uint32_t capabilities);
};
/**
* @ingroup iface_wl_webos_seat
*/
static inline int
wl_webos_seat_add_listener(struct wl_webos_seat *wl_webos_seat,
const struct wl_webos_seat_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_seat,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_SEAT_GET_GYROSCOPE 0
#define WL_WEBOS_SEAT_GET_ACCELEROMETER 1
/**
* @ingroup iface_wl_webos_seat
*/
#define WL_WEBOS_SEAT_INFO_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_seat
*/
#define WL_WEBOS_SEAT_GET_GYROSCOPE_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_seat
*/
#define WL_WEBOS_SEAT_GET_ACCELEROMETER_SINCE_VERSION 1
/** @ingroup iface_wl_webos_seat */
static inline void
wl_webos_seat_set_user_data(struct wl_webos_seat *wl_webos_seat, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_seat, user_data);
}
/** @ingroup iface_wl_webos_seat */
static inline void *
wl_webos_seat_get_user_data(struct wl_webos_seat *wl_webos_seat)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_seat);
}
static inline uint32_t
wl_webos_seat_get_version(struct wl_webos_seat *wl_webos_seat)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_seat);
}
/** @ingroup iface_wl_webos_seat */
static inline void
wl_webos_seat_destroy(struct wl_webos_seat *wl_webos_seat)
{
wl_proxy_destroy((struct wl_proxy *) wl_webos_seat);
}
/**
* @ingroup iface_wl_webos_seat
*
* If the seat has gyroscope sensor, user can get this interface.
*/
static inline struct wl_webos_gyroscope *
wl_webos_seat_get_gyroscope(struct wl_webos_seat *wl_webos_seat)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_seat,
WL_WEBOS_SEAT_GET_GYROSCOPE, &wl_webos_gyroscope_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_seat), 0, NULL);
return (struct wl_webos_gyroscope *) id;
}
/**
* @ingroup iface_wl_webos_seat
*
* If the seat has accelerometer sensor, user can get this interface.
*/
static inline struct wl_webos_accelerometer *
wl_webos_seat_get_accelerometer(struct wl_webos_seat *wl_webos_seat)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_seat,
WL_WEBOS_SEAT_GET_ACCELEROMETER, &wl_webos_accelerometer_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_seat), 0, NULL);
return (struct wl_webos_accelerometer *) id;
}
/**
* @ingroup iface_wl_webos_gyroscope
* @struct wl_webos_gyroscope_listener
*/
struct wl_webos_gyroscope_listener {
/**
* sensor data from the seat
*
* The gyroscope sensor data will be delivered only if the client
* explicitly requested it via "requeest_data".
* @param x data for x-axis
* @param y data for y-axis
* @param z data for z-axis
*/
void (*sensor_data)(void *data,
struct wl_webos_gyroscope *wl_webos_gyroscope,
wl_fixed_t x,
wl_fixed_t y,
wl_fixed_t z);
};
/**
* @ingroup iface_wl_webos_gyroscope
*/
static inline int
wl_webos_gyroscope_add_listener(struct wl_webos_gyroscope *wl_webos_gyroscope,
const struct wl_webos_gyroscope_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_gyroscope,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_GYROSCOPE_REQUEST_DATA 0
/**
* @ingroup iface_wl_webos_gyroscope
*/
#define WL_WEBOS_GYROSCOPE_SENSOR_DATA_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_gyroscope
*/
#define WL_WEBOS_GYROSCOPE_REQUEST_DATA_SINCE_VERSION 1
/** @ingroup iface_wl_webos_gyroscope */
static inline void
wl_webos_gyroscope_set_user_data(struct wl_webos_gyroscope *wl_webos_gyroscope, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_gyroscope, user_data);
}
/** @ingroup iface_wl_webos_gyroscope */
static inline void *
wl_webos_gyroscope_get_user_data(struct wl_webos_gyroscope *wl_webos_gyroscope)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_gyroscope);
}
static inline uint32_t
wl_webos_gyroscope_get_version(struct wl_webos_gyroscope *wl_webos_gyroscope)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_gyroscope);
}
/** @ingroup iface_wl_webos_gyroscope */
static inline void
wl_webos_gyroscope_destroy(struct wl_webos_gyroscope *wl_webos_gyroscope)
{
wl_proxy_destroy((struct wl_proxy *) wl_webos_gyroscope);
}
/**
* @ingroup iface_wl_webos_gyroscope
*
* Requests to enable/disable sending data for gyroscope device.
*/
static inline void
wl_webos_gyroscope_request_data(struct wl_webos_gyroscope *wl_webos_gyroscope, uint32_t enabled)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_gyroscope,
WL_WEBOS_GYROSCOPE_REQUEST_DATA, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_gyroscope), 0, enabled);
}
/**
* @ingroup iface_wl_webos_accelerometer
* @struct wl_webos_accelerometer_listener
*/
struct wl_webos_accelerometer_listener {
/**
* sensor data from the seat
*
* The accelerometer sensor data will be delivered only if the
* client explicitly requested it via "request_data".
* @param x data for x-axis
* @param y data for y-axis
* @param z data for z-axis
*/
void (*sensor_data)(void *data,
struct wl_webos_accelerometer *wl_webos_accelerometer,
wl_fixed_t x,
wl_fixed_t y,
wl_fixed_t z);
};
/**
* @ingroup iface_wl_webos_accelerometer
*/
static inline int
wl_webos_accelerometer_add_listener(struct wl_webos_accelerometer *wl_webos_accelerometer,
const struct wl_webos_accelerometer_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_accelerometer,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_ACCELEROMETER_REQUEST_DATA 0
/**
* @ingroup iface_wl_webos_accelerometer
*/
#define WL_WEBOS_ACCELEROMETER_SENSOR_DATA_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_accelerometer
*/
#define WL_WEBOS_ACCELEROMETER_REQUEST_DATA_SINCE_VERSION 1
/** @ingroup iface_wl_webos_accelerometer */
static inline void
wl_webos_accelerometer_set_user_data(struct wl_webos_accelerometer *wl_webos_accelerometer, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_accelerometer, user_data);
}
/** @ingroup iface_wl_webos_accelerometer */
static inline void *
wl_webos_accelerometer_get_user_data(struct wl_webos_accelerometer *wl_webos_accelerometer)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_accelerometer);
}
static inline uint32_t
wl_webos_accelerometer_get_version(struct wl_webos_accelerometer *wl_webos_accelerometer)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_accelerometer);
}
/** @ingroup iface_wl_webos_accelerometer */
static inline void
wl_webos_accelerometer_destroy(struct wl_webos_accelerometer *wl_webos_accelerometer)
{
wl_proxy_destroy((struct wl_proxy *) wl_webos_accelerometer);
}
/**
* @ingroup iface_wl_webos_accelerometer
*
* Requests to enable/disable sending data for accelerometer device.
*/
static inline void
wl_webos_accelerometer_request_data(struct wl_webos_accelerometer *wl_webos_accelerometer, uint32_t enabled)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_accelerometer,
WL_WEBOS_ACCELEROMETER_REQUEST_DATA, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_accelerometer), 0, enabled);
}
#ifdef __cplusplus
}
#endif
#endif
@@ -1,506 +0,0 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef WEBOS_SHELL_CLIENT_PROTOCOL_H
#define WEBOS_SHELL_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_webos_shell The webos_shell protocol
* @section page_ifaces_webos_shell Interfaces
* - @subpage page_iface_wl_webos_shell - interface for webOS shell
* - @subpage page_iface_wl_webos_shell_surface - interface to handle webos shell surfaces
* @section page_copyright_webos_shell Copyright
* <pre>
*
* Copyright (c) 2013-2020 LG Electronics, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* </pre>
*/
struct wl_surface;
struct wl_webos_shell;
struct wl_webos_shell_surface;
#ifndef WL_WEBOS_SHELL_INTERFACE
#define WL_WEBOS_SHELL_INTERFACE
/**
* @page page_iface_wl_webos_shell wl_webos_shell
* @section page_iface_wl_webos_shell_desc Description
*
* This interface provides handlings on webOS shell surfaces.
* @section page_iface_wl_webos_shell_api API
* See @ref iface_wl_webos_shell.
*/
/**
* @defgroup iface_wl_webos_shell The wl_webos_shell interface
*
* This interface provides handlings on webOS shell surfaces.
*/
extern const struct wl_interface wl_webos_shell_interface;
#endif
#ifndef WL_WEBOS_SHELL_SURFACE_INTERFACE
#define WL_WEBOS_SHELL_SURFACE_INTERFACE
/**
* @page page_iface_wl_webos_shell_surface wl_webos_shell_surface
* @section page_iface_wl_webos_shell_surface_desc Description
*
* This allows the client to associate an normal surface with a
* shell surface. The shell surface provides webOS specific functionality
* to surfaces.
* @section page_iface_wl_webos_shell_surface_api API
* See @ref iface_wl_webos_shell_surface.
*/
/**
* @defgroup iface_wl_webos_shell_surface The wl_webos_shell_surface interface
*
* This allows the client to associate an normal surface with a
* shell surface. The shell surface provides webOS specific functionality
* to surfaces.
*/
extern const struct wl_interface wl_webos_shell_surface_interface;
#endif
#define WL_WEBOS_SHELL_GET_SYSTEM_PIP 0
#define WL_WEBOS_SHELL_GET_SHELL_SURFACE 1
/**
* @ingroup iface_wl_webos_shell
*/
#define WL_WEBOS_SHELL_GET_SYSTEM_PIP_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell
*/
#define WL_WEBOS_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1
/** @ingroup iface_wl_webos_shell */
static inline void
wl_webos_shell_set_user_data(struct wl_webos_shell *wl_webos_shell, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_shell, user_data);
}
/** @ingroup iface_wl_webos_shell */
static inline void *
wl_webos_shell_get_user_data(struct wl_webos_shell *wl_webos_shell)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_shell);
}
static inline uint32_t
wl_webos_shell_get_version(struct wl_webos_shell *wl_webos_shell)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_shell);
}
/** @ingroup iface_wl_webos_shell */
static inline void
wl_webos_shell_destroy(struct wl_webos_shell *wl_webos_shell)
{
wl_proxy_destroy((struct wl_proxy *) wl_webos_shell);
}
/**
* @ingroup iface_wl_webos_shell
*
* This request is deprecated. If you want to create a new request,
* you can reuse this one. FYI, in that case, you also need to modify
* get_system_pip method in luna-surfacemanager as well.
*/
static inline void
wl_webos_shell_get_system_pip(struct wl_webos_shell *wl_webos_shell)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell,
WL_WEBOS_SHELL_GET_SYSTEM_PIP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell), 0);
}
/**
* @ingroup iface_wl_webos_shell
*
* Creates an webOS shell surface for an existing surface.
*/
static inline struct wl_webos_shell_surface *
wl_webos_shell_get_shell_surface(struct wl_webos_shell *wl_webos_shell, struct wl_surface *surface)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell,
WL_WEBOS_SHELL_GET_SHELL_SURFACE, &wl_webos_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell), 0, NULL, surface);
return (struct wl_webos_shell_surface *) id;
}
#ifndef WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_ENUM
#define WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_ENUM
/**
* @ingroup iface_wl_webos_shell_surface
* location mask for the surface
*
* Using this mask the surface can be positioned onto
* different locations on screen. By not using absolute
* coordinates we can create greater flexibility in the
* compositor and the clients.
*/
enum wl_webos_shell_surface_location_hint {
WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_NORTH = 1,
WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_WEST = 2,
WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_SOUTH = 4,
WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_EAST = 8,
WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_CENTER = 16,
};
#endif /* WL_WEBOS_SHELL_SURFACE_LOCATION_HINT_ENUM */
#ifndef WL_WEBOS_SHELL_SURFACE_STATE_ENUM
#define WL_WEBOS_SHELL_SURFACE_STATE_ENUM
/**
* @ingroup iface_wl_webos_shell_surface
* the state of the surface
*
* The state provides info to the client on how the compositor has placed
* the surface.
*
* The default state will indicate to the client that it is windowed. The
* "position_changed" event will tell the position in screen coordinates
* when the surface is in this state.
*/
enum wl_webos_shell_surface_state {
WL_WEBOS_SHELL_SURFACE_STATE_DEFAULT = 0,
WL_WEBOS_SHELL_SURFACE_STATE_MINIMIZED = 1,
WL_WEBOS_SHELL_SURFACE_STATE_MAXIMIZED = 2,
WL_WEBOS_SHELL_SURFACE_STATE_FULLSCREEN = 3,
};
#endif /* WL_WEBOS_SHELL_SURFACE_STATE_ENUM */
#ifndef WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_ENUM
#define WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_ENUM
/**
* @ingroup iface_wl_webos_shell_surface
* the key that the surface handles
*
* The client uses wl_webos_shell_surface.set_key_mask to notify server
* that it will handle specific keys only.
*/
enum wl_webos_shell_surface_webos_key {
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_HOME = 1,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_BACK = 2,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_EXIT = 4,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_NAVIGATION_LEFT = 8,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_NAVIGATION_RIGHT = 16,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_NAVIGATION_UP = 32,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_NAVIGATION_DOWN = 64,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_NAVIGATION_OK = 128,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_NUMERIC_KEYS = 256,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_COLOR_RED = 512,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_COLOR_GREEN = 1024,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_COLOR_YELLOW = 2048,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_COLOR_BLUE = 4096,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_PROGRAMME_GROUP = 8192,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_PLAYBACK_GROUP = 16384,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_TELETEXT_GROUP = 32768,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_LOCAL_LEFT = 65536,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_LOCAL_RIGHT = 131072,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_LOCAL_UP = 262144,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_LOCAL_DOWN = 524288,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_LOCAL_OK = 1048576,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_REMOTE_MAGNIFIER_GROUP = 2097152,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_MINIMAL_PLAYBACK_GROUP = 4194304,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_GUIDE = 8388608,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_TELETEXT_ACTIVE_GROUP = 16777216,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_DATA = 33554432,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_INFO = 67108864,
WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_DEFAULT = 0xFFFFFFF8,
};
#endif /* WL_WEBOS_SHELL_SURFACE_WEBOS_KEY_ENUM */
#ifndef WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_ENUM
#define WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_ENUM
/**
* @ingroup iface_wl_webos_shell_surface
* the status of the add-on
*
* Status of the add-on for the given shell surface.
* null: neither server-side add-on set nor loaded
* loaded: the server-side add-on is loaded and visible
* denied: the server-side add-on is not allowed to load
* error: the server-side add-on is not loaded due to an error
*/
enum wl_webos_shell_surface_addon_status {
WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_NULL = 0,
WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_LOADED = 1,
WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_DENIED = 2,
WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_ERROR = 3,
};
#endif /* WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_ENUM */
/**
* @ingroup iface_wl_webos_shell_surface
* @struct wl_webos_shell_surface_listener
*/
struct wl_webos_shell_surface_listener {
/**
* the surface state was changed
*
* The compositor or the user has taken action that has resulted
* in this surface to change state.
*/
void (*state_changed)(void *data,
struct wl_webos_shell_surface *wl_webos_shell_surface,
uint32_t state);
/**
* the surface position on screen changed
*
* This event will only be sent the surfaces that are in their
* default state. It will be not sent for fullscreen surfaces nor
* for surfaces that are minimized.
*/
void (*position_changed)(void *data,
struct wl_webos_shell_surface *wl_webos_shell_surface,
int32_t x,
int32_t y);
/**
* request closing of window
*
* The close event is sent when the compositor requests closing
* of a window, e.g. through some gesture or other interaction,
* without explicitly quitting or killing the client.
*/
void (*close)(void *data,
struct wl_webos_shell_surface *wl_webos_shell_surface);
/**
* indicates what areas are exposed
*
* The array contains non-overlapping rectangles that define
* areas that are visible in this surface. The array elements are a
* series of ints arranged as follows x,y,w,h,x,y,w,h,-1. The
* values will not contain negative numbers and the -1 is treated
* as a terminating marker.
*/
void (*exposed)(void *data,
struct wl_webos_shell_surface *wl_webos_shell_surface,
struct wl_array *rectangles);
/**
* the surface state is about to change
*
* Be sure that the actual state should not be changed with this.
* Client can only prepare that state will be changed.
*/
void (*state_about_to_change)(void *data,
struct wl_webos_shell_surface *wl_webos_shell_surface,
uint32_t state);
/**
* notify the add-on status when changed
*
* Notifies when the add-on status changes.
* @since 2
*/
void (*addon_status_changed)(void *data,
struct wl_webos_shell_surface *wl_webos_shell_surface,
uint32_t addon_status);
};
/**
* @ingroup iface_wl_webos_shell_surface
*/
static inline int
wl_webos_shell_surface_add_listener(struct wl_webos_shell_surface *wl_webos_shell_surface,
const struct wl_webos_shell_surface_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_shell_surface,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_SHELL_SURFACE_SET_LOCATION_HINT 0
#define WL_WEBOS_SHELL_SURFACE_SET_STATE 1
#define WL_WEBOS_SHELL_SURFACE_SET_PROPERTY 2
#define WL_WEBOS_SHELL_SURFACE_SET_KEY_MASK 3
#define WL_WEBOS_SHELL_SURFACE_SET_ADDON 4
#define WL_WEBOS_SHELL_SURFACE_RESET_ADDON 5
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_STATE_CHANGED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_POSITION_CHANGED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_CLOSE_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_EXPOSED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_STATE_ABOUT_TO_CHANGE_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_ADDON_STATUS_CHANGED_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_SET_LOCATION_HINT_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_SET_STATE_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_SET_PROPERTY_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_SET_KEY_MASK_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_SET_ADDON_SINCE_VERSION 2
/**
* @ingroup iface_wl_webos_shell_surface
*/
#define WL_WEBOS_SHELL_SURFACE_RESET_ADDON_SINCE_VERSION 2
/** @ingroup iface_wl_webos_shell_surface */
static inline void
wl_webos_shell_surface_set_user_data(struct wl_webos_shell_surface *wl_webos_shell_surface, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_shell_surface, user_data);
}
/** @ingroup iface_wl_webos_shell_surface */
static inline void *
wl_webos_shell_surface_get_user_data(struct wl_webos_shell_surface *wl_webos_shell_surface)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_shell_surface);
}
static inline uint32_t
wl_webos_shell_surface_get_version(struct wl_webos_shell_surface *wl_webos_shell_surface)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_shell_surface);
}
/** @ingroup iface_wl_webos_shell_surface */
static inline void
wl_webos_shell_surface_destroy(struct wl_webos_shell_surface *wl_webos_shell_surface)
{
wl_proxy_destroy((struct wl_proxy *) wl_webos_shell_surface);
}
/**
* @ingroup iface_wl_webos_shell_surface
*
* The location hint is a guideline to the compositor where
* to place the surface. The compositor will do its best to
* place it there, however this is not guaranteed. Currently
* The location hint is only applied to _WEBOS_WINDOW_TYPE_POPUP
* and _WEBOS_WINDOW_TYPE_SYSTEM_UI surfaces.
*/
static inline void
wl_webos_shell_surface_set_location_hint(struct wl_webos_shell_surface *wl_webos_shell_surface, uint32_t hint)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell_surface,
WL_WEBOS_SHELL_SURFACE_SET_LOCATION_HINT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell_surface), 0, hint);
}
/**
* @ingroup iface_wl_webos_shell_surface
*
* The client requests its surface state to the compositor.
*/
static inline void
wl_webos_shell_surface_set_state(struct wl_webos_shell_surface *wl_webos_shell_surface, uint32_t state)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell_surface,
WL_WEBOS_SHELL_SURFACE_SET_STATE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell_surface), 0, state);
}
/**
* @ingroup iface_wl_webos_shell_surface
*
* The client sets the surface property to the compositor. The property
* is given by a string pair (name, value).
*/
static inline void
wl_webos_shell_surface_set_property(struct wl_webos_shell_surface *wl_webos_shell_surface, const char *name, const char *value)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell_surface,
WL_WEBOS_SHELL_SURFACE_SET_PROPERTY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell_surface), 0, name, value);
}
/**
* @ingroup iface_wl_webos_shell_surface
*
* A value of '1' in the mask indicates that the respective key event (both press and release)
* will be delivered to the client. Bitwise XOR operation against the default mask value and
* a supported individual values will result in that key not being delivered to the client.
* Notice that the default value omits certain keys.
*
* The compositor is free to ignore certain keys even if set to '1' depending on the overall
* system UI behaviour, most commonly this will mean the HOME key.
*
* NOTE: This protocol will eventually replace the string property based key filtering.
*/
static inline void
wl_webos_shell_surface_set_key_mask(struct wl_webos_shell_surface *wl_webos_shell_surface, uint32_t webos_key)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell_surface,
WL_WEBOS_SHELL_SURFACE_SET_KEY_MASK, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell_surface), 0, webos_key);
}
/**
* @ingroup iface_wl_webos_shell_surface
*
* Sets the path to the server-side add-on. The compositor loads the add-on
* on receiving this request if the add-on is identified as a valid one.
*/
static inline void
wl_webos_shell_surface_set_addon(struct wl_webos_shell_surface *wl_webos_shell_surface, const char *path)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell_surface,
WL_WEBOS_SHELL_SURFACE_SET_ADDON, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell_surface), 0, path);
}
/**
* @ingroup iface_wl_webos_shell_surface
*
* Requests to unload the add-on if it is loaded.
* If there is no add-on loaded this request is silently ignored.
*/
static inline void
wl_webos_shell_surface_reset_addon(struct wl_webos_shell_surface *wl_webos_shell_surface)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_shell_surface,
WL_WEBOS_SHELL_SURFACE_RESET_ADDON, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_shell_surface), 0);
}
#ifdef __cplusplus
}
#endif
#endif
@@ -1,597 +0,0 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef WEBOS_SURFACE_GROUP_CLIENT_PROTOCOL_H
#define WEBOS_SURFACE_GROUP_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_webos_surface_group The webos_surface_group protocol
* @section page_ifaces_webos_surface_group Interfaces
* - @subpage page_iface_wl_webos_surface_group_compositor - a way to group multi client surfaces together
* - @subpage page_iface_wl_webos_surface_group -
* - @subpage page_iface_wl_webos_surface_group_layer - the handle for the group owner to manipulate the layer
* @section page_copyright_webos_surface_group Copyright
* <pre>
*
* Copyright (c) 2014-2020 LG Electronics, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* </pre>
*/
struct wl_surface;
struct wl_webos_surface_group;
struct wl_webos_surface_group_compositor;
struct wl_webos_surface_group_layer;
#ifndef WL_WEBOS_SURFACE_GROUP_COMPOSITOR_INTERFACE
#define WL_WEBOS_SURFACE_GROUP_COMPOSITOR_INTERFACE
/**
* @page page_iface_wl_webos_surface_group_compositor wl_webos_surface_group_compositor
* @section page_iface_wl_webos_surface_group_compositor_desc Description
*
* A surface group is a mechanism to group surfaces together that are
* not part of the same client, hence transiency, nor subsurfaces will
* fit the bill. However the compositor will treat surfaces belonging
* to a group very similarly as to surfaces that are transient.
*
* The group will be controlled by the process that creates it. The group
* will have a root surface and the grouped surfaces will be added as
* layers on top or below it. The creator of the group will designate a z order
* and a name for each layer. Other processes wanting to add their
* surface into the group need to know the both the name of the group and
* the name of the layer.
*
* A group can allow anonymous surfaces to be attached to them as well.
*
* Practical suggestion, the name of the group should match the appId of
* parent surface.
* @section page_iface_wl_webos_surface_group_compositor_api API
* See @ref iface_wl_webos_surface_group_compositor.
*/
/**
* @defgroup iface_wl_webos_surface_group_compositor The wl_webos_surface_group_compositor interface
*
* A surface group is a mechanism to group surfaces together that are
* not part of the same client, hence transiency, nor subsurfaces will
* fit the bill. However the compositor will treat surfaces belonging
* to a group very similarly as to surfaces that are transient.
*
* The group will be controlled by the process that creates it. The group
* will have a root surface and the grouped surfaces will be added as
* layers on top or below it. The creator of the group will designate a z order
* and a name for each layer. Other processes wanting to add their
* surface into the group need to know the both the name of the group and
* the name of the layer.
*
* A group can allow anonymous surfaces to be attached to them as well.
*
* Practical suggestion, the name of the group should match the appId of
* parent surface.
*/
extern const struct wl_interface wl_webos_surface_group_compositor_interface;
#endif
#ifndef WL_WEBOS_SURFACE_GROUP_INTERFACE
#define WL_WEBOS_SURFACE_GROUP_INTERFACE
/**
* @page page_iface_wl_webos_surface_group wl_webos_surface_group
* @section page_iface_wl_webos_surface_group_api API
* See @ref iface_wl_webos_surface_group.
*/
/**
* @defgroup iface_wl_webos_surface_group The wl_webos_surface_group interface
*/
extern const struct wl_interface wl_webos_surface_group_interface;
#endif
#ifndef WL_WEBOS_SURFACE_GROUP_LAYER_INTERFACE
#define WL_WEBOS_SURFACE_GROUP_LAYER_INTERFACE
/**
* @page page_iface_wl_webos_surface_group_layer wl_webos_surface_group_layer
* @section page_iface_wl_webos_surface_group_layer_desc Description
*
* The handle can be used to change the z order of a particular layer
* @section page_iface_wl_webos_surface_group_layer_api API
* See @ref iface_wl_webos_surface_group_layer.
*/
/**
* @defgroup iface_wl_webos_surface_group_layer The wl_webos_surface_group_layer interface
*
* The handle can be used to change the z order of a particular layer
*/
extern const struct wl_interface wl_webos_surface_group_layer_interface;
#endif
#define WL_WEBOS_SURFACE_GROUP_COMPOSITOR_CREATE_SURFACE_GROUP 0
#define WL_WEBOS_SURFACE_GROUP_COMPOSITOR_GET_SURFACE_GROUP 1
/**
* @ingroup iface_wl_webos_surface_group_compositor
*/
#define WL_WEBOS_SURFACE_GROUP_COMPOSITOR_CREATE_SURFACE_GROUP_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group_compositor
*/
#define WL_WEBOS_SURFACE_GROUP_COMPOSITOR_GET_SURFACE_GROUP_SINCE_VERSION 1
/** @ingroup iface_wl_webos_surface_group_compositor */
static inline void
wl_webos_surface_group_compositor_set_user_data(struct wl_webos_surface_group_compositor *wl_webos_surface_group_compositor, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_surface_group_compositor, user_data);
}
/** @ingroup iface_wl_webos_surface_group_compositor */
static inline void *
wl_webos_surface_group_compositor_get_user_data(struct wl_webos_surface_group_compositor *wl_webos_surface_group_compositor)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_surface_group_compositor);
}
static inline uint32_t
wl_webos_surface_group_compositor_get_version(struct wl_webos_surface_group_compositor *wl_webos_surface_group_compositor)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group_compositor);
}
/** @ingroup iface_wl_webos_surface_group_compositor */
static inline void
wl_webos_surface_group_compositor_destroy(struct wl_webos_surface_group_compositor *wl_webos_surface_group_compositor)
{
wl_proxy_destroy((struct wl_proxy *) wl_webos_surface_group_compositor);
}
/**
* @ingroup iface_wl_webos_surface_group_compositor
*
* The group will be identified by the 'name' parameter. If a group already
* exists with the given name an error will be reported to the client.
*/
static inline struct wl_webos_surface_group *
wl_webos_surface_group_compositor_create_surface_group(struct wl_webos_surface_group_compositor *wl_webos_surface_group_compositor, struct wl_surface *parent, const char *name)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group_compositor,
WL_WEBOS_SURFACE_GROUP_COMPOSITOR_CREATE_SURFACE_GROUP, &wl_webos_surface_group_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group_compositor), 0, NULL, parent, name);
return (struct wl_webos_surface_group *) id;
}
/**
* @ingroup iface_wl_webos_surface_group_compositor
*
* A handle to an existing group.
*/
static inline struct wl_webos_surface_group *
wl_webos_surface_group_compositor_get_surface_group(struct wl_webos_surface_group_compositor *wl_webos_surface_group_compositor, const char *name)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group_compositor,
WL_WEBOS_SURFACE_GROUP_COMPOSITOR_GET_SURFACE_GROUP, &wl_webos_surface_group_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group_compositor), 0, NULL, name);
return (struct wl_webos_surface_group *) id;
}
#ifndef WL_WEBOS_SURFACE_GROUP_Z_HINT_ENUM
#define WL_WEBOS_SURFACE_GROUP_Z_HINT_ENUM
/**
* @ingroup iface_wl_webos_surface_group
* hint for the z position of the anonymous surfaces
*
* The position of anonymous layer is always relative to the root element
* and the named layers in this group.
*
* If there are multiple entries with the same index designator they will
* get positioned in the order of which they get attached.
*/
enum wl_webos_surface_group_z_hint {
/**
* below the root surface and the lowest named layer
*/
WL_WEBOS_SURFACE_GROUP_Z_HINT_BELOW = 0,
/**
* above the root surface and above the highest named layer
*/
WL_WEBOS_SURFACE_GROUP_Z_HINT_ABOVE = 1,
/**
* above all of the anonymous surfaces
*/
WL_WEBOS_SURFACE_GROUP_Z_HINT_TOP = 2,
};
#endif /* WL_WEBOS_SURFACE_GROUP_Z_HINT_ENUM */
/**
* @ingroup iface_wl_webos_surface_group
* @struct wl_webos_surface_group_listener
*/
struct wl_webos_surface_group_listener {
/**
* sent to clients attached to this group
*
* If the owner crashes or normally destroys this group the
* attached client will receive this notification.
*
* Since compositor does not know what to do with client surface
* still attached to this group it will not show them. A well
* behaving client will 'detach' from this group and release its
* assosicated resource
*/
void (*owner_destroyed)(void *data,
struct wl_webos_surface_group *wl_webos_surface_group);
};
/**
* @ingroup iface_wl_webos_surface_group
*/
static inline int
wl_webos_surface_group_add_listener(struct wl_webos_surface_group *wl_webos_surface_group,
const struct wl_webos_surface_group_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_surface_group,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_SURFACE_GROUP_CREATE_LAYER 0
#define WL_WEBOS_SURFACE_GROUP_ATTACH 1
#define WL_WEBOS_SURFACE_GROUP_ATTACH_ANONYMOUS 2
#define WL_WEBOS_SURFACE_GROUP_ALLOW_ANONYMOUS_LAYERS 3
#define WL_WEBOS_SURFACE_GROUP_DETACH 4
#define WL_WEBOS_SURFACE_GROUP_DESTROY 5
#define WL_WEBOS_SURFACE_GROUP_FOCUS_OWNER 6
#define WL_WEBOS_SURFACE_GROUP_FOCUS_LAYER 7
#define WL_WEBOS_SURFACE_GROUP_COMMIT_KEY_INDEX 8
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_OWNER_DESTROYED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_CREATE_LAYER_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_ATTACH_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_ATTACH_ANONYMOUS_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_ALLOW_ANONYMOUS_LAYERS_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_DETACH_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_FOCUS_OWNER_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_FOCUS_LAYER_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group
*/
#define WL_WEBOS_SURFACE_GROUP_COMMIT_KEY_INDEX_SINCE_VERSION 1
/** @ingroup iface_wl_webos_surface_group */
static inline void
wl_webos_surface_group_set_user_data(struct wl_webos_surface_group *wl_webos_surface_group, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_surface_group, user_data);
}
/** @ingroup iface_wl_webos_surface_group */
static inline void *
wl_webos_surface_group_get_user_data(struct wl_webos_surface_group *wl_webos_surface_group)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_surface_group);
}
static inline uint32_t
wl_webos_surface_group_get_version(struct wl_webos_surface_group *wl_webos_surface_group)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* The layer will be identified by the 'name' parameter. The compositor
* will place the layer in the given z-index relative to the root layer.
* If negative z-indecies are provided they will be placed underneath the
* root surface accordingly
*
* The creator will get a handle 'wl_webos_surface_group_layer' to the
* newly created group. The handle can be used to manipulate the layer.
*
* If a layer group already exists with the given parameters an error
* will be reported to the client.
*/
static inline struct wl_webos_surface_group_layer *
wl_webos_surface_group_create_layer(struct wl_webos_surface_group *wl_webos_surface_group, const char *name, int32_t z_index)
{
struct wl_proxy *id;
id = wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_CREATE_LAYER, &wl_webos_surface_group_layer_interface, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0, NULL, name, z_index);
return (struct wl_webos_surface_group_layer *) id;
}
/**
* @ingroup iface_wl_webos_surface_group
*
* Processes that want to attach a surface to an existing group and layer
* will call this function.
*
* An error will be reported if either the group, the layer or the layer
* already has a surface attached to it.
*/
static inline void
wl_webos_surface_group_attach(struct wl_webos_surface_group *wl_webos_surface_group, struct wl_surface *surface, const char *layer_name)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0, surface, layer_name);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* Clients that have a "multi-purpose" surface that might apply to many use
* cases can try to attach their surface to a named group. The group controls
* if that is allowed or not.
*
* An error will be reported if the group is not available or it does not
* allow anonymous surfaces
*/
static inline void
wl_webos_surface_group_attach_anonymous(struct wl_webos_surface_group *wl_webos_surface_group, struct wl_surface *surface, uint32_t z_hint)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_ATTACH_ANONYMOUS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0, surface, z_hint);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* Anonymous layers are layers that do not belong to any named layer.
* They do not enjoy the same benefits as named layers. Their actucal
* z-index might change if there are named layers or a z index of a
* named layer is updated.
*/
static inline void
wl_webos_surface_group_allow_anonymous_layers(struct wl_webos_surface_group *wl_webos_surface_group, uint32_t allow)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_ALLOW_ANONYMOUS_LAYERS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0, allow);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* When a client detaches from a group the compositor will treat is as any other surface.
* In practice this means that if the client does not want the surface to appear "dangling"
* or visible in recents the client should hide/destroy the surface, then detach it from
* the group to avoid any unwanted behavior.
*/
static inline void
wl_webos_surface_group_detach(struct wl_webos_surface_group *wl_webos_surface_group, struct wl_surface *surface)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_DETACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0, surface);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* Destroys the surface group object.
*/
static inline void
wl_webos_surface_group_destroy(struct wl_webos_surface_group *wl_webos_surface_group)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), WL_MARSHAL_FLAG_DESTROY);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* Using "focus_owner" a surface-group-client or a surface-group-owner can transfer
* keybord-focus to surface-group-owner.
*/
static inline void
wl_webos_surface_group_focus_owner(struct wl_webos_surface_group *wl_webos_surface_group)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_FOCUS_OWNER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* Using "focus_layer" a surface-group-owner or a surface-group-client can transfer
* keybord-focus to specific surface-group-client attached to surface-group-layer "layer".
*/
static inline void
wl_webos_surface_group_focus_layer(struct wl_webos_surface_group *wl_webos_surface_group, const char *layer)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_FOCUS_LAYER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0, layer);
}
/**
* @ingroup iface_wl_webos_surface_group
*
* Using "commit_key_index", the compositor will send key events in key index order
* regardless of z-order in the surface group.
* Key index set to each layer becomes effective after "commit_key_index" request.
* Parameter 'commit' should be 1 when applying the key index order.
* Set parameter 'commit' to 0 not to use the key index order.
* If anonymous layer is allowed, the key index order doesn't work.
*/
static inline void
wl_webos_surface_group_commit_key_index(struct wl_webos_surface_group *wl_webos_surface_group, uint32_t commit)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group,
WL_WEBOS_SURFACE_GROUP_COMMIT_KEY_INDEX, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group), 0, commit);
}
/**
* @ingroup iface_wl_webos_surface_group_layer
* @struct wl_webos_surface_group_layer_listener
*/
struct wl_webos_surface_group_layer_listener {
/**
* notify surface-group-owner that surface is attached to this layer
*
* When any surafce is attached to this layer, the compositor
* needs to notify surface-group-owner.
*/
void (*surface_attached)(void *data,
struct wl_webos_surface_group_layer *wl_webos_surface_group_layer);
/**
* notify surface-group-owner that surface is detached from this layer
*
* When any surafce is detached from this layer, the compositor
* needs to notify surface-group-owner. This will be usefull if
* surface attached to this layer is destroyed by associated
* surface-group-client.
*/
void (*surface_detached)(void *data,
struct wl_webos_surface_group_layer *wl_webos_surface_group_layer);
};
/**
* @ingroup iface_wl_webos_surface_group_layer
*/
static inline int
wl_webos_surface_group_layer_add_listener(struct wl_webos_surface_group_layer *wl_webos_surface_group_layer,
const struct wl_webos_surface_group_layer_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) wl_webos_surface_group_layer,
(void (**)(void)) listener, data);
}
#define WL_WEBOS_SURFACE_GROUP_LAYER_SET_Z_INDEX 0
#define WL_WEBOS_SURFACE_GROUP_LAYER_SET_KEY_INDEX 1
#define WL_WEBOS_SURFACE_GROUP_LAYER_DESTROY 2
/**
* @ingroup iface_wl_webos_surface_group_layer
*/
#define WL_WEBOS_SURFACE_GROUP_LAYER_SURFACE_ATTACHED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group_layer
*/
#define WL_WEBOS_SURFACE_GROUP_LAYER_SURFACE_DETACHED_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group_layer
*/
#define WL_WEBOS_SURFACE_GROUP_LAYER_SET_Z_INDEX_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group_layer
*/
#define WL_WEBOS_SURFACE_GROUP_LAYER_SET_KEY_INDEX_SINCE_VERSION 1
/**
* @ingroup iface_wl_webos_surface_group_layer
*/
#define WL_WEBOS_SURFACE_GROUP_LAYER_DESTROY_SINCE_VERSION 1
/** @ingroup iface_wl_webos_surface_group_layer */
static inline void
wl_webos_surface_group_layer_set_user_data(struct wl_webos_surface_group_layer *wl_webos_surface_group_layer, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wl_webos_surface_group_layer, user_data);
}
/** @ingroup iface_wl_webos_surface_group_layer */
static inline void *
wl_webos_surface_group_layer_get_user_data(struct wl_webos_surface_group_layer *wl_webos_surface_group_layer)
{
return wl_proxy_get_user_data((struct wl_proxy *) wl_webos_surface_group_layer);
}
static inline uint32_t
wl_webos_surface_group_layer_get_version(struct wl_webos_surface_group_layer *wl_webos_surface_group_layer)
{
return wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group_layer);
}
/**
* @ingroup iface_wl_webos_surface_group_layer
*
* Updates the z index for this layer. The compositor will move the surface
* attached to this layer accordingly. If no surface is attached to this
* layer nothing will happen
*/
static inline void
wl_webos_surface_group_layer_set_z_index(struct wl_webos_surface_group_layer *wl_webos_surface_group_layer, int32_t z_index)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group_layer,
WL_WEBOS_SURFACE_GROUP_LAYER_SET_Z_INDEX, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group_layer), 0, z_index);
}
/**
* @ingroup iface_wl_webos_surface_group_layer
*
* Sets the key index for this layer. The compositor will send key events
* to this layer accordingly after "commit_key_index" request.
* If no surface is attached to this layer nothing will happen.
* Key index should be neither redundant nor 0 (0 is onwner's key index).
* The larger the key index, the faster the layer receives the key event.
*/
static inline void
wl_webos_surface_group_layer_set_key_index(struct wl_webos_surface_group_layer *wl_webos_surface_group_layer, int32_t key_index)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group_layer,
WL_WEBOS_SURFACE_GROUP_LAYER_SET_KEY_INDEX, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group_layer), 0, key_index);
}
/**
* @ingroup iface_wl_webos_surface_group_layer
*
* Destroys the surface group layer object.
*/
static inline void
wl_webos_surface_group_layer_destroy(struct wl_webos_surface_group_layer *wl_webos_surface_group_layer)
{
wl_proxy_marshal_flags((struct wl_proxy *) wl_webos_surface_group_layer,
WL_WEBOS_SURFACE_GROUP_LAYER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_webos_surface_group_layer), WL_MARSHAL_FLAG_DESTROY);
}
#ifdef __cplusplus
}
#endif
#endif
+2 -43
View File
@@ -19,7 +19,6 @@ env:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Check Out Repo
@@ -42,20 +41,11 @@ jobs:
out-file-path: "temp"
- name: Update packages
timeout-minutes: 5
run: |
for i in 1 2 3; do
sudo timeout 90 apt-get -yq update \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
run: sudo apt-get -yq update
- name: Install webOS CLI
timeout-minutes: 5
run: |
sudo apt-get -yq install \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
./temp/ares-package_*_amd64.deb \
./temp/webosbrew-toolbox-gen-manifest_*.deb
@@ -91,32 +81,6 @@ jobs:
RARCH_VERSION=$(grep -Po '(?<=#define PACKAGE_VERSION ")[^"]+' version.all)
echo "RARCH_VERSION=$RARCH_VERSION" >> "$GITHUB_ENV"
- name: Resolve SDL2 prebuilt archive
id: sdl2
shell: bash
run: |
URL=$(sed -n 's/^SDL2_PREBUILT_ARCHIVE *?= *//p' Makefile.webos)
echo "url=$URL" >> "$GITHUB_OUTPUT"
echo "name=$(basename "$URL")" >> "$GITHUB_OUTPUT"
- name: Cache SDL2 prebuilt
id: sdl2-cache
uses: actions/cache@v4
with:
path: /tmp/sdl2-prebuilt
key: sdl2-prebuilt-${{ steps.sdl2.outputs.name }}
- name: Download SDL2 prebuilt
if: steps.sdl2-cache.outputs.cache-hit != 'true'
shell: bash
env:
SDL2_URL: ${{ steps.sdl2.outputs.url }}
SDL2_NAME: ${{ steps.sdl2.outputs.name }}
run: |
mkdir -p /tmp/sdl2-prebuilt
curl -fsSL --retry 5 --retry-all-errors --retry-delay 5 \
--connect-timeout 30 -o "/tmp/sdl2-prebuilt/$SDL2_NAME" "$SDL2_URL"
- name: Compile RA (GLES2, no wayland legacy variant)
shell: bash
run: |
@@ -124,14 +88,12 @@ jobs:
export SDK_PATH=/tmp/arm-webos-linux-gnueabi_sdk-buildroot
make -f Makefile.webos clean
make -f Makefile.webos ipk PACKAGE_NAME=${PACKAGE_NAME} ADD_SDL2_LIB=1 \
SDL2_PREBUILT_ARCHIVE="file:///tmp/sdl2-prebuilt/${SDL2_NAME}" \
-j"$(getconf _NPROCESSORS_ONLN)"
mkdir -p webos/arm
mv webos/com.retroarch.webos_${RARCH_VERSION}_arm.ipk \
webos/arm/com.retroarch.webos-legacy-gles2-no-wayland_${RARCH_VERSION}_arm.ipk
env:
DEBUG: ${{ github.event_name == 'release' && '0' || '1' }}
SDL2_NAME: ${{ steps.sdl2.outputs.name }}
- name: Upload GLES2 artifact
uses: actions/upload-artifact@v7
@@ -148,7 +110,6 @@ jobs:
make -f Makefile.webos clean
bash gfx/common/wayland/generate_wayland_protos.sh
make -f Makefile.webos ipk PACKAGE_NAME=${PACKAGE_NAME} ADD_SDL2_LIB=1 \
SDL2_PREBUILT_ARCHIVE="file:///tmp/sdl2-prebuilt/${SDL2_NAME}" \
HAVE_XKBCOMMON=1 HAVE_USERLAND=1 HAVE_EGL=1 HAVE_WAYLAND=1 \
HAVE_OPENGLES3=1 HAVE_OPENGLES3_1=1 HAVE_OPENGLES3_2=1 -j"$(getconf _NPROCESSORS_ONLN)"
mkdir -p webos/arm
@@ -156,7 +117,6 @@ jobs:
webos/arm/com.retroarch.webos_${RARCH_VERSION}_arm.ipk
env:
DEBUG: ${{ github.event_name == 'release' && '0' || '1' }}
SDL2_NAME: ${{ steps.sdl2.outputs.name }}
- name: Upload default artifact
uses: actions/upload-artifact@v7
@@ -181,8 +141,7 @@ jobs:
export SDK_PATH=/tmp/aarch64-webos-linux-gnu_sdk-buildroot
make -f Makefile.webos clean
bash gfx/common/wayland/generate_wayland_protos.sh
make -f Makefile.webos ipk PACKAGE_NAME=${PACKAGE_NAME} \
ADD_SDL2_LIB=0 HAVE_SDL2=0 HAVE_SDL3=1 \
make -f Makefile.webos ipk PACKAGE_NAME=${PACKAGE_NAME} ADD_SDL2_LIB=0 \
HAVE_XKBCOMMON=1 HAVE_USERLAND=1 HAVE_EGL=1 HAVE_WAYLAND=1 \
HAVE_OPENGLES3=1 HAVE_OPENGLES3_1=1 HAVE_OPENGLES3_2=1 \
HAVE_WAYLAND_BACKPORT=0 HAVE_64TO32BIT_BRIDGE=1 SET_ELF_INTERPRETER=1 HAVE_UDEV=1 \
+2 -52
View File
@@ -4,8 +4,6 @@
*.exe
*.bmpobj
*.binobj
*.shbin
*.shbin.s
*.so
*.so.*
*.dll
@@ -16,10 +14,6 @@
*.swp
*.cache
*.gcda
# clang --analyze drops a .plist report per translation unit into the
# working directory. Anchored to the repository root so the tracked
# Info.plist / ExportOptions.plist files under pkg/apple are unaffected.
/*.plist
*.lcbk
*.gcno
.tmp
@@ -71,7 +65,6 @@ apple/RetroArch_iOS.xcodeproj/project.xcworkspace/*
/Cg/
/GL/
/SDL/
/SDL3/
/ffmpeg/
/freetype2/
/ft2build.h
@@ -86,7 +79,7 @@ apple/RetroArch_iOS.xcodeproj/project.xcworkspace/*
.cproject
.settings
libretro-super
/run.sh
run.sh
convert_rumble.awk
*~
assets
@@ -99,7 +92,7 @@ content_video_history.lpl
saves
screenshots
autoconfig
/config
config
/database
overlays
playlists
@@ -266,41 +259,6 @@ gfx/common/wayland/webos-surface-group.c
gfx/common/wayland/webos-surface-group.h
gfx/common/wayland/tearing-control-v1.h
gfx/common/wayland/tearing-control-v1.c
gfx/common/wayland/drm-lease-v1.h
gfx/common/wayland/drm-lease-v1.c
# samples/: built harness executables and objects. Each directory's
# test is <dir>_test; nothing built there is source.
samples/**/*_test
samples/**/*_test_*
samples/audio/stretch/stretch_bench
samples/**/*.o
libretro-common/samples/**/*_test
libretro-common/samples/**/*_test_*
!libretro-common/samples/**/*_test/
!samples/**/*_test_*.c
!libretro-common/samples/**/*_test_*.c
!samples/**/*_test_*.h
!libretro-common/samples/**/*_test_*.h
# Harness executables that are not named <dir>_test. This one had been
# committed as a built binary, which made any make clean in that
# directory show up as a deletion.
samples/audio/embedded_alsa/abi_check
libretro-common/samples/rthreads/retro_eventcount_bench/retro_eventcount_bench
libretro-common/samples/rthreads/retro_eventcount_bench/retro_eventcount_bench_*
# The driver's text with its Windows includes swapped, produced by each
# suite's Makefile from audio/drivers/wasapi.c. Committed copies went
# stale against the driver they are generated from.
samples/audio/wasapi_exclusive_pacing/wasapi_sim.c
samples/audio/discrete_multichannel/wasapi_sim.c
samples/gfx/font_lifecycle/lifecycle
samples/gfx/font_lifecycle/lifecycle-threaded
samples/gfx/font_lifecycle/create
# Generated by samples/gfx/wayland_drm_lease from the bundled protocol
# XML; the client half of the same pair lands in gfx/common/wayland.
samples/gfx/wayland_drm_lease/drm-lease-v1-client-protocol.h
samples/gfx/wayland_drm_lease/drm-lease-v1-server-protocol.h
samples/gfx/wayland_drm_lease/drm-lease-v1-protocol.c
# libretro-common samples
libretro-common/samples/streams/rzip/rzip
@@ -338,11 +296,3 @@ gfx/drivers/rsx_shaders/modern_opaque.fpo
gfx/drivers/rsx_shaders/modern_opaque.vpo
pkg/psl1ght/pkg/USRDIR/shaders_cg/
!pkg/psl1ght/pkg/USRDIR/system/
samples/audio/embedded_alsa/ealsa_abi.h
# Python bytecode caches, written by tools/*.py whenever they run.
__pycache__/
*.pyc
samples/audio/asio_clock/asio_clock_driver.h
samples/gfx/integer_scale_axis/integer_scale_driver.h
samples/gfx/integer_scale_axis/integer_scale_axis_test
+5 -5
View File
@@ -7,7 +7,7 @@ stages:
- trigger-static-cores
build-retroarch-windows-x64:
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-mxe-win64-cross:gcc16
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-mxe-win64-cross:gcc10
stage: build
variables:
MEDIA_PATH: .media
@@ -51,7 +51,7 @@ build-retroarch-windows-x64:
- "rm -f ${MEDIA_PATH}/${CI_PROJECT_NAME}/redist/opengl32.dll"
build-retroarch-windows-i686:
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-mxe-win32-cross:gcc16
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-mxe-win32-cross:gcc10
stage: build
variables:
MEDIA_PATH: .media
@@ -782,7 +782,7 @@ build-static-retroarch-dummy-psp:
- "cp -f pkg/psp1/PIC1.PNG ${MEDIA_PATH}/${CI_PROJECT_NAME}/pkg"
build-static-retroarch-vita:
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-vita:latest-20260905
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-vita:latest
stage: prepare-for-static-cores
before_script:
- export NUMPROC=$(($(nproc)/3))
@@ -808,7 +808,7 @@ build-static-retroarch-vita:
- "mv .retroarch-precompiled-gl/ retroarch-precompiled-gl/"
build-static-retroarch-dummy-vita:
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-vita:latest-20260905
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-vita:latest
stage: build
variables:
MEDIA_PATH: .media
@@ -991,7 +991,7 @@ build-static-retroarch-ctr-legacy:
needs: []
script:
# Allow failure since we don't have a core
- "make -f Makefile.ctr -j$NUMPROC USE_CTRULIB_2=0 ||:"
- "make -f Makefile.ctr -j$NUMPROC ||:"
- "mkdir .retroarch-precompiled"
- "cp -r ./* .retroarch-precompiled/"
- "mv .retroarch-precompiled/ retroarch-precompiled/"
-118
View File
@@ -1,118 +0,0 @@
AGENTS.md
## Project
RetroArch is primarily written in C89. Preserve the existing language and style of the file being edited.
- New C code must be C89-compatible unless the surrounding code explicitly requires otherwise.
- Do not introduce C99/C11 features into C89 code.
- Existing files written in C++, Objective-C, or another language should remain in that language.
- Follow the conventions of surrounding code rather than introducing a new style.
- Prefer the smallest change that completely solves the task.
- Preserve existing architecture
RetroArch contains deliberately complex, cross-file systems. Do not simplify, consolidate, refactor, or redesign an existing subsystem merely because its structure appears unnecessarily complicated.
Complexity may exist for compatibility, platform, driver, or architectural reasons.
When implementing a feature, find an existing feature with similar behavior and follow its implementation pattern. The current source tree takes precedence over historical examples.
Do not make unrelated cleanup or refactoring changes.
## Comments
Keep comments as short as possible.
- Prefer no comment when the code is self-explanatory.
- When a comment is necessary, prefer a few words or a few lines at most.
- Explain why something is non-obvious, rather than describing what obvious code does.
- Do not add comments merely because code was changed.
- Do not describe the previous implementation or behavior unless that historical context is necessary to understand the current code.
- Do not use comments as miniature documentation or change logs.
- Prefer clear names and straightforward code over explanatory comments.
Comments should describe information that will remain useful after the current change is forgotten.
## Commit messages
Keep commit messages concise and focused.
- Explain what changed and why.
- Prefer a short subject line and a brief body when additional context is useful.
- Do not enumerate every changed file or implementation detail.
- Do not describe intermediate attempts, discarded approaches, or the development process.
- Do not explain the previous implementation unless it is necessary to understand the change.
- Keep the complete commit message below approximately 600 words.
- A commit message is not a changelog or development diary.
## Menu changes
Adding or modifying a menu option commonly requires changes in several parts of the codebase.
Do not assume that a menu option can be implemented by modifying only the file where it is displayed.
### Before adding a menu option:
- Find an existing menu option with similar behavior.
- Trace its complete implementation through the menu, settings, configuration, and message systems.
- Identify every part of that pattern that applies to the new option.
- Implement the new option consistently across all required layers.
- Do not modify unrelated menu code.
#### Useful reference commits:
- 6e9aa66aea2b2b3d0687585e41bac658ac9ae252 — SMB timeout/context settings exposed as menu options.
- 434f41b935232325ed13024786653f9dfef49643 — CRT menu additions.
- 23170b82ec58c2b283a7132b85fa73e18050a5ae — MIDI device dropdown menu items.
05faba73e3fed69a5e118df2cc28d31309089243 — menu implementation example.
These are reference implementations, not fixed lists of files to modify. The required files depend on the feature.
## Shader and video backend changes
Shader functionality frequently crosses shared shader code and multiple video backends.
### When adding or modifying shader functionality:
- Find an existing shader feature with similar behavior.
- Trace the feature through the shared shader infrastructure.
- Identify every applicable shader implementation and video backend.
- Keep backend implementations consistent where the feature is supported.
- Do not update only the backend currently being tested if the feature is expected to work elsewhere.
- Check platform/backend-specific differences rather than blindly duplicating code.
#### Useful reference commits:
- da5ecaa45a862e51783eca1280f46fbfb7984ede — OriginalAspect and OriginalAspectRot uniforms.
- 2a56a827e8a97a3838a9d455f1dca442c0ffbb07 — frametime/original-FPS shader uniforms.
- 37cfa4857d064464754e800bad89ce69e81230fe — sensor shader uniforms across multiple shader and video/input backends.
These commits demonstrate the breadth of changes that may be required. They are examples of implementation patterns, not instructions to reproduce their exact file lists.
## Historical commits
Historical commits may be used to understand established implementation patterns.
- Treat examples as references, not specifications.
- Prefer the current source tree when it differs from an historical commit.
- Do not copy historical changes mechanically.
- Do not reproduce obsolete workarounds merely because they appear in an old commit.
- Inspect surrounding current code before applying a historical pattern.
## Scope of changes
Keep changes focused.
### Do not:
- reformat unrelated code;
- rename unrelated symbols;
- modernize C89 code;
- replace established patterns with preferred patterns;
- refactor neighboring code without a direct need;
- add documentation or comments solely to explain the current change;
- make speculative improvements.
If a task requires a broad change, make the breadth necessary for the feature rather than artificially minimizing the number of files changed.
A change touching many files is not inherently a problem in RetroArch. Missing a required layer of an established multi-file system is a problem.
+513
View File
@@ -0,0 +1,513 @@
static const char *retroarch_contributors_list = R"(
RetroArch and the libretro team would like to
acknowledge the following contributors:
1ch (L0sted)
23rd
6lackmag3
A Schain (aschain)
Aaron Oneal (aarononeal)
Aaron Ramirez (aaronbytes)
Abadede
Adam Londero (alondero)
Adam Mechtley (amechtley)
Adriano de Moura Leite (amlib)
Adrien Moulin (elyosh)
Aethyrion
ajefr
AKuHAK
Alberto Alonso Ruibal (albertoruibal)
Alberto Fustinoni (albertofustinoni)
Alberto Simon (asimonf)
Alcaro
aldebaran27
Aleksey Samoilov (Sunderland93)
Alessandro Mangone (Vektor) (zevektor)
Alex Folland (AlexFolland)
Alex Kornitzer (alexkornitzer)
Alexander Spady (alkaseltzerspadt)
Alexander Trufanov (trufanov-nok)
Alexandre Garcia (Alexandre-Garcia)
Alfredo Monclus (alfrix)
aliaspider
alphanu1
altiereslima
Alwin Garside (Yogarine)
amtz
Anders Storhaug (andersstorhaug)
Andre Leiradella (leiradel)
Andrés (fr500)
Andy Nguyen (TheOfficialFloW)
Anthony J. Bentley (bentley)
Antonio Jose Ramos Marquez (psxdev)
antonioginer
Apaczer
AridRayne
ArnaudFaucher
arpruss
arstn
Artem Polishchuk (tim77)
Arto Vainiolehto (arakerlu)
asavah
Ash (ashquarky)
Ashura (CoalaJoe)
Avton1
ayssia
BananaRama203
barbudreadmon
Barry Rowe (BarryJRowe)
Bartłomiej Burdukiewicz (dev-0x7C6)
Bashar Astifan (basharast)
bearoso
Ben Hamilton (Ben Gertzfield) (bhamiltoncx)
benklop
benutzer193
Bernhard Schelling (schellingb)
blackgur
bmaupin
Bobby Smith (bslenul)
Boris Timofeev (btimofeev)
Brad (SpiralBrad)
Braden Farmer (farmerbb)
Brandon Johnson (BinaryFissionGames)
Breno Dantas Mendonça (brenodantas10)
Brian Hoem (ZornTaov)
Brian Koropoff (bkoropoff)
Brian S. Stephan (bsstephan)
BringerethOfLight
Brunnis
bsmith (DogParty)
bubuleur
bulzipke
C.W. Betts (MaddTheSane)
Casey Borders (CaseyB)
CatGreen90
ceb33
cedorg
celerizer
Charlène (julianaito)
CheezeCake
Chris Merrett (chrisfu)
Christian Murphy (grimpunch)
christianhaitian
Christoffer Tibell (Brottweiler)
Christopher Snowhill (kode54)
chu (9chu)
Chuck Smith (chucksmith)
CidVonHighwind
clienthax
cold-brewed
Colin Kinloch (ColinKinloch)
CompCom
ComradeEcho
confusedguy9
Conn O'Griofa (psyke83)
Connor McLaughlin (stenzek)
Conrad Kreyling (konistehrad)
CozmoP
Cpasjuste
cpsw
Cray Elliott (MP2E)
Crestwave
CrewMdk
Cristi Mitrana (cmitu)
Cristian Sandu (crazyquark)
crystalct
CTCaer
cucholix
cudencuden
CyberLabSystems
Daehan Kim (iAmGhost)
dalter
Dan Weiss (Dwedit)
danieljg
Daniil Zhilin (LaserMoai)
dankcushions
Darren Thompson (DiscoStarslayer)
Dave (freakdave)
Dave Leaver (danzel)
David CARLIER (devnexen)
David Demelier (markand)
David Erickson (daviderickson)
David G. F. (davidgfnet)
David Lawson (dmrlawson)
David Walters (hiddenasbestos)
dbaronica
DEX357
diablodiab
dibas
Diego A. (SuperrSonic)
Diego Viola (diegoviola)
digitalisland-nino
Diogo Barros (BlueKore)
Dmitry Sergeenkov (DuMOHsmol)
dor3k
Doug Christman (dobyrch)
driver1998
Dudu Akiva (duduke)
duganchen
dukemiller
duskgao
Dylan Scott (dyscott)
Dystopian
eadmaster
Eduard Strehlau (Herdinger)
ekipan
Elvira Khabirova (parport0)
embercold
Emmanuel Martin (daliaetnano)
Ethan Lee (flibitijibibo)
extrowerk
Ezio-PS
F (erbridge)
Fabio (Oibaf66)
Fabio Ritrovato (Sephiroth87)
Fayne Aldan (FayneAldan)
fff (felinben)
Filipe Azevedo (pasnox)
FIX94
Flame Sage (flamesage)
flyinghead
FmT0
francescotintori
Francisco Javier Trujillo Mata (fjtrujy)
Francisco José García García (frangarcj)
FreeShippingParty
fuzzydunlops732 (JKoppel93)
GABO1423
Gabriel (Ghabry)
GameDragon2k
Garrett Brown (garbear)
gatecat (daveshah1)
GavinDarkglider
gblues
Geoffrey Plitt (GeoffreyPlitt)
Giovanni Cascione (spleen1981)
Glenn Hevey (hevey)
Googer
gordon-fish
gouchi
Gregor Richards (GregorR)
Grzegorz Raciborski (graciborski)
Gui Andrade (archshift)
Guillaume Thiolliere (thiolliere)
Guo Yunhe (guoyunhe)
Gustavo Maciel Dias Vieira (gmdvieira)
gvbr
hadess
Hans-Kristian Arntzen (Themaister)
Henri Gomez (hgomez)
Henri Gomez (hgomez-sonarsource)
Henry Castro (hcvcastro)
Higor E. (heuripedes)
hizzlekizzle
Hugo B. (hug0b)
Hugo Hromic (hhromic)
hunterk
Hyllian
HyperspaceMadness
i30817
im4potato
ImJezze
İbrahim Güngör (igungor)
Jack (jakcron)
Jacob (cubtekki)
Jacob (RegenJacob)
Jacob Patterson (jacobpa)
jacobsson (Roet-Ivar)
Jahed
Jake Stine (jstine35)
James Le Cuirot (chewi)
James Sexton (Bezier89)
Jamiras
Jan Holthuis (Holzhaus)
Jason Tomsic (plaidman)
Javier Martinez Canillas (martinezjavier)
Jay McCarthy (jeapostrophe)
jdgleaver
Jean-André Santoni (kivutar)
Jean-Paul Mari (djipi)
Jean-Sébastien Guay (Skylark13)
Jeff (jeffbdavenport)
Jeff Sousa (LordeIlluminati)
jess (winneon)
Jesse Talavera-Greenberg (JesseTG)
Joan Coll Cerdán (johanbcn)
Job Adrian Salinas Gonzalez (efylan)
Joe Osborn (JoeOsborn)
Joel (joel16)
Joel Puig Rubio (XXLuigiMario)
Joerg Sonnenberger (jsonn)
Johannes Schickel (lordhoto)
John Parton (john-parton)
John Regan (jprjr)
Jon Maddox (maddox)
Jonathan (JonnyMe)
Jonathan Relf (jonathanrelf)
Joohan Lee (losernator)
Jools Wills (joolswills)
Jose Lage Miguez (Joselagem)
Joseph Carter (knghtbrd)
Joseph Conan Montgomery (Grotke)
jsd1982 (JamesDunne)
jSTE0
JuanVCS
Justin Jacobs (dorkster)
Justin Weiss (justinweiss)
JustMeDaFaq
Kangmo-Ahn
Karl Forshaw (karlforshaw)
Kate Eckhart (katepango)
Keith Bowes (keithbowes)
Ken Rossato (rossato)
kikmon
Kopert
Krzysztof Haładyn (krzys_h) (krzys-h)
kurumushi
kwyxz
l3iggs
lambolighting
lasers
Lawrence Kesteloot (lkesteloot)
LazyBumHorse
LazyFunker
Lennard Kittner (Lennard599)
LibretroAdmin
Lionel Flandrin (simias)
littleguy77
liushuyu
Logan McNaughton (loganmc10)
lordashram
Lothar Serra Mari (lotharsm)
Lubosz Sarnecki (lubosz)
lucasmr
lucianposton
lxerandrew
m4xw
mahoneyt944
Mahyar Koshkouei (deltabeard)
Mai (lioncash)
MajorPainTheCactus
maksun
Manuel Alfayate Corchete (vanfanel)
Marcelo Munhoz Pélos (mpelos)
Marcus Crisostomo (mcrisostomo)
markwkidd
Maschell
Mats (Myaats)
Matt Sephton (gingerbeardman)
Matthew Bauer (matthewbauer)
Matthew Wang (asakous)
Max K. (langerhans)
Maxime Gauduin (alucryd)
meancoot
meepingsnesroms
meleu
Merry Mello (merryMellody)
micechal
Michael Burgardt (DisasterMo)
Michael K. (kuxii2016)
Michael Lelli (ToadKing)
mickski56
Mico Chopitea (micochops)
miguelpinheiro
Mike Swanson (chungy)
mikeOSX
minucce
misson20000
esoptron
Monroe88
Morgane (MorganeAD)
mprobinson
MrHuu
MrJs (mrjschulte)
Muhamed Hobi (mmhobi7)
muzuiget
N/A (inactive123)
Nargash
Nathan S. (natinusala)
NathanStrong-Tripwire
nattycleopatra
Naveen (naveensrinivasan)
nayslayer
negativeExponent
Neil Barkhina (nbarkhina)
neil4
netux79
nfnty
nfp0
nia (alarixnia)
Nicolas Adenis-Lamarre (nadenislamarre)
Nicolas Guillaumin (nguillaumin)
Nicolas Roehm (NicolasRoehm)
Nik (WerWolv)
Nikita Vakhrushev (XF10C)
Nikola Kocić (nikola-kocic)
Nikos Chantziaras (realnc)
Nils Hasenbanck (hasenbanck)
njordan64
nosh01
not6 (r-type)
notaz
nstCactus
nurupo
Oggom
Oh Won Sik (dnjstlr555)
Oleg Shevchenko (olsh)
Omar Saleem (ofsaleem)
opendata26
Ophidon
orbea
Oschowa
OsirizX
OV2
Palmic (mpalomas)
pamapa
Paolo Bonzini (bonzini)
Paul McCarty (notabeatle)
pcjco
Pedro Ferraz (ferrazpedro)
Pedro Ribeiro (pedrib)
Peter J Kos (pkos)
Philippe Simons (loki666)
pinumbernumber
Piotr Dobrowolski (Informatic)
pjft
Poligraf
pponso1
pyroesp
R-YaTian
Rafael Toledo (rafaeltoledo)
Ramiro Morales (ramiro)
Raphaël Zumer (rzumer)
redenvelope2000
Reid Kleckner (rnk)
repojohnray
retrotails
revvv
reztek
Richard Howell (rmaz)
Rinnegatamante
rlnilsen
Rob Loach (RobLoach)
Robin de Rooij (rrooij)
Romain Gay (vikbez)
Romain Graillot (notnotme)
Romain TISSERAND (rtissera)
Roman Fomin (rfomin)
Roman Kalashnikov (lunixoid)
Royerson
rsn8887
Ruben Nine (rnine)
Ryan C. Gordon (icculus)
Ryan Kuba (thelamer)
Ryunam
rz5
Sage (neonfuz)
Saggi Mizrahi (ficoos)
SAKUJ0
Salvador (salvacam)
Sam (44100hertz)
Sam Lantinga (slouken)
Sam Stenvall (Jalle19)
Samuel P. (p-sam)
Sanaki
Scheiker
Sean O'Neil (seanocali)
Sebastien Ronsse (sronsse)
SecularSteve
Sefa Eyeoglu (Scrumplex)
Sergei Nikitin (Kert)
Sergei Trofimovich (trofi)
Sergi Granell (xerpi)
Sergio Padrino (sergiou87)
sergio-br2 (sergiobenrocha2)
Seth Kingsley (sethk)
Shadow (ShadowOne333)
Shane Mouton (ismouton)
shantigilbert
Shfty
Shizeeg Unadequatov (shizeeg)
SimpleTease
SindenLightgun
Sirrempat
slotek
Soar Qin (soarqin)
sonninnos
Sou Bunnbu (iyzsong)
sparklewind
spec-chum
Stefan (gizmo98)
stefan-gr
stellarporter
Stephanie Gawroriski (XerTheSquirrel)
Steve Cox (stevenjamescox)
Stevoisiak
stoofin
StormedBubbles
strotlog
Stuart Carnie (stuartcarnie)
Sunguk Lee (d3m3vilurr)
Supernature2k
Sven (RetroSven)
Swizzy
Sylvain Colinet (Skarsnik)
Szunti
Tadek Kijkowski (monkeyman79)
Tatsuya79
Terry Lewis (terry-au)
thedax
theheroGAC
TheMrIron2
ThePhxRises
TheRhysWyrill
Thomas Lorblanchès (Zlika)
Tilman M. Jaeschke (asciibeats)
Tim Van den Langenbergh (tmtvl)
Tobias Gruetzmacher (TobiX)
Tobias Jakobi (tobiasjakobi)
Todd Laney (ToddLa)
Tomáš Kelemen (ToKe79)
Tor Arne Vestbø (torarnv)
Torsten Paul (t-paul)
TotalCaesar659
tr12345
TroggleMonkey
tunip3
txorion
Tyler Loch (TylerLoch)
URBANsUNITED
vaguerant
Val Packett (valpackett)
Valerio Proietti (kamicane)
vgmoose
Viachaslau Khalikin (viachaslavic)
Vicki Pfau (endrift)
Vicky C Lau (vickychenglau)
vin (suseme)
Vincent Pelletier (vpelletier)
Vladimir Panteleev (CyberShadow)
Vladimir Serbinenko (phcoder)
Víctor "IlDucci" (IlDucci)
waitingmoon
Warning: Non-Potable Water (warningnonpotablewater)
webgeek1234
Weedy Weed Smoker (WeedyWeedSmoker)
whorsemaster
Wiimpathy
Wiktor Strzębała (wiktorek140)
Woohyun Shin (sinusinu)
xenomorph-us
xhp-creations
Xitee (Xitee1)
Yari (hyarsan)
yesfish (huwpascoe)
Yongwoon Cho (ssangkong)
yoshisuga
Zer0xFF
zeromus
zlice
Érico Nogueira Rolim (ericonr)
Ömercan Kömür (fpscan)
シーはディー四を取る (cxd4)
)";
-20
View File
@@ -9,7 +9,6 @@
- ANDROID: Enable network commands
- ANDROID: Fix dual-motor rumble for USB-connected DS4 and DualSense controllers
- AUDIO: ASIO driver for Windows platforms
- AUDIO: SDL3 audio and microphone drivers
- AUDIO/MICROPHONE: Fix resampling, apple drivers
- APPLE: Use coreaudio3 resampling
- APPLE: Add coreaudio3 driver to iOS/TVOS
@@ -39,7 +38,6 @@
- INPUT/MFI: Controller disconnection fix
- INPUT/SDL: Fix controller vid/pid detection on Windows
- INPUT/SDL: Add wiimote sensor capabilities
- INPUT/SDL3: Add SDL3 input driver
- INPUT/UDEV: Fix multi-touch detection
- INPUT/UDEV: Gyroscope and accelerometer sensor support
- INPUT/UDEV: Add wiimote sensor capabilities
@@ -90,23 +88,6 @@
- MENU/XMB: Tab change possible by gestures
- MENU/XMB: Horizontal menu is now optional
- NETWORK: New network commands SAVE_STATE_SLOT N and GET_CONFIG_PARAM
- NETWORK: HELP network command lists every command with what it does
- NETWORK: LIST_CORES, LIST_PLAYLISTS and GET_PLAYLIST network commands, to find content and the core to load it with
- NETWORK: MCP server: AI assistants can drive RetroArch through the Model Context Protocol, every network command a tool (off by default, see docs/mcp-server.md)
- NETWORK: Built-in TLS 1.2/1.3 client; mbedTLS and BearSSL are no longer bundled (--enable-mbedtls / --enable-bearssl use a system one)
- NETWORK: Built-in SMB2/3 client with signing, AES-CCM/GCM encryption and Kerberos; libsmb2 is no longer bundled (--enable-libsmb uses a system one)
- NETWORK: Built-in NFSv3 and NFSv4 (4.0, 4.1, 4.2) client for loading content from nfs:// exports
- NETWORK: NFS files stay usable across a server restart, a dropped connection or a long pause: the client reconnects and reopens what it needs
- 3DS/VITA/SWITCH/WIIU: nfs:// content through the built-in NFS client
- 3DS/VITA/SWITCH: smb:// content through the built-in SMB client
- WINDOWS/MSVC: the Visual Studio 2005 - 2017 projects build the TLS client, the keychain, SMB and NFS
- NETWORK: SMB files stay usable across a server restart: the connection is mended and the file opened again where it was
- NETWORK: NFSv4.2 reads use READ_PLUS: holes in sparse files no longer cross the network
- 3DS/SWITCH: nfs:// content through the built-in NFS client
- NETWORK: Optional SMB/NFS read-ahead with background prefetch, for large disc images over a slow link (off by default)
- NETWORK: Saved passwords are encrypted in retroarch-keychain.cfg; an optional passphrase lets the keychain move to another machine (see docs/network-stack.md)
- NETWORK: SMB 3.1.1 signs with AES-GMAC where the server offers it, several times faster than AES-CMAC on signed reads
- NETWORK: HTTPS downloads whose length is set by the server closing the connection now finish instead of hanging
- OVERLAY: Allow overlays to position the viewport
- OVERLAY: Hold button function
- OVERLAY: Allow interaction during next overlay swap
@@ -143,7 +124,6 @@
- VIDEO/METAL: Add HDR10/scRGB output support
- VIDEO/METAL: Add support for GPU index
- VIDEO/SDL2: Add hardware-accelerated support for widgets, XMB, Ozone
- VIDEO/SDL3: Add SDL3 video driver (software/gl/glcore/vulkan)
- VIDEO/VULKAN: VK_EXT_full_screen_exclusive is now optional
- VIDEO/WAYLAND: Fix fullscreen window offset/incorrect sizing
- VIDEO/WAYLAND: Fix issue with tiny menu in case of fullscreen
-1
View File
@@ -1 +0,0 @@
@AGENTS.md
+6 -179
View File
@@ -71,131 +71,13 @@ Stack size
----------
You have to assume that stack size is going to be limited in
RetroArch. These are the thread stacks the tree creates today:
RetroArch. Some game consoles (and other embedded systems)
might have a default stack size as low as 128Kb or less.
Be conservative with stack size but don't try to put very
small structs on heap either [to avoid memory fragmentation
among other things]. A balancing act here is necessary.
* GEKKO (Wii/GC) 8 KiB STACKSIZE, rthreads/rthreads.c
* 3DS 32 KiB STACKSIZE, rthreads/rthreads.c
* PSP 32 KiB STACKSIZE, rthreads/rthreads.c
* Vita 64 KiB STACKSIZE, rthreads/rthreads.c
* WiiU 128 KiB STACKSIZE, rthreads/rthreads.c
* Switch 128 KiB STACKSIZE, rthreads/rthreads.c
* PS2 32 KiB STACKSIZE, rthreads/rthreads.c
* Vita 64 KiB rthreads.c, 0x10000
* Apple 2 MiB rthreads.c, raised from a 512 KiB default
* Windows 1 MiB reserved by default, committed lazily
8 KiB on GEKKO is the floor, and it is the number to design
against.
Which thread your code runs on is not something you get to assume.
Anything reachable from a task handler can end up on one of these:
retro_task_regular_gather() runs handlers on the main thread, but
with a threaded task queue the same handler runs on a worker.
*** THE BUDGET ***
- 4 KiB is the ceiling for a single stack frame anywhere in the
tree.
- 2 KiB is the ceiling for anything under libretro-common, and it
is enforced. tools/stack_budget.py measures every shipped .c
there with -fstack-usage and fails the build over it; it runs in
CI as part of Linux-libretro-common-tests.yml. Read the header
of that script before adding an entry to its allowlist - an
entry there is debt, not an exemption.
Neither number is a per-function allowance to spend. A frame does
not run alone, it runs on top of everything that called it. Ten
1.5 KiB frames in a row pass every per-frame check ever written
and still overflow an 8 KiB stack, which is why the budget sits so
far below the smallest stack.
*** WHY 4 KIB ***
- Small-stack targets. See the table above. A 16 KiB local buffer
is twice the whole GEKKO stack, and nothing warns about it: the
code builds everywhere and overflows only on a target most
contributors cannot build, at whatever moment it first runs on a
worker. config_file_write() carried a 16 KiB stdio buffer as a
local on a path reached from input_autoconfigure_connect_handler
- a task handler - and nothing noticed for years.
- Stack probes on Windows. 4 KiB is the page size, and Windows
commits thread stacks lazily: one guard page sits below the
committed region, and touching it is what makes the OS commit
another page and move the guard down. A frame that moves the
stack pointer past the guard page without touching it faults
outside the guard page, which the OS treats as a plain access
violation rather than a request to grow the stack - the process
dies. Compilers avoid that by emitting a probe: MSVC's default
is /Gs4096 on x86, x64, ARM and ARM64, so any function needing
more than one page of locals gets a call to __chkstk (or
___chkstk_ms under mingw-w64, which uses the same threshold)
that walks the frame page by page in order. So crossing 4 KiB
turns a single subtract into an out-of-line loop at every entry
to that function, and commits every page it touches for the life
of the thread. GCC's -fstack-clash-protection does the same
thing on Linux, and the kernel-side reason is the same.
- Recursion and reentrancy. A frame you can afford once is a frame
you cannot afford at depth 40. Anything recursive - directory
walks, archive nesting, parsers - should carry its state in a
heap-allocated context and bound its depth explicitly, not lean
on the stack to hold the recursion for it.
*** IN PRACTICE ***
- Measure rather than guess. For one file:
gcc -O2 -DPSP -fstack-usage -c foo.c -Ilibretro-common/include
and read foo.su. Or point the script at a file or a directory:
tools/stack_budget.py libretro-common/formats/. -DPSP matters,
because PATH_MAX_LENGTH is 512 on those targets and 2048
elsewhere - a host-shaped measurement overstates every function
holding a path buffer. Adding -Wstack-usage=4096 to a local
build turns the ceiling into a warning while you work.
Frame size is a property of an ABI, not of the source; the same
function measures 16 to 192 bytes larger under mingw-w64 than
under SysV. Do not compare an absolute number against one taken
from a different target triple.
- Per-frame is necessary and not sufficient. tools/stack_chain.py
sums frames along the call graph from a set of roots (task
handlers being the roots that matter) and reports the deepest
chain. It is a screening tool rather than a verdict, which is
why it is not in CI - read its header for what it cannot see.
- Path buffers are the usual culprit. On desktop PATH_MAX_LENGTH
is 2048, so two of them in one frame is already over the
ceiling. Use DIR_MAX_LENGTH (1024) and NAME_MAX_LENGTH (128)
when that is what the buffer actually holds, and reuse one
buffer rather than carrying a second.
- No VLAs and no alloca(). VLAs are not C89 (see below); alloca()
additionally makes the frame unbounded at compile time, and
-fstack-usage can only report such a frame as dynamic, so it
drops out of every check above.
- When a frame is too large, the question is not "can this
overflow today" but "does this need to be on the stack at all".
The answer is usually no, and the fix is usually one of: move
the buffer to the heap, or move it into a state object that is
already allocated once per stream/session, or shrink it. Real
examples, all done rather than argued about:
vh_build 16784 -> 400 scratch to the heap
config_file_write 16432 -> 48 stdio buffer to heap
chd_read_header_core_file 57504 -> 32 chd_file to the heap
rd_gen_lengths 12768 -> 352 scratch into the struct
sha1_calculate 4304 -> 224 mapped view, else heap
- None of this means small structs belong on the heap. Heap
allocations are slow compared to the stack, and scattering tiny
ones fragments memory - which matters most on exactly the
platforms with the small stacks. A balancing act is necessary:
a few hundred bytes of locals is fine and idiomatic, a kilobyte
wants a reason, and 4 KiB is where the decision is made for you.
Be mindful that heap allocations are slow compared to stack.
Functions
---------
@@ -229,61 +111,6 @@ VLA (Variable Length Array)
Do not use VLAs (Variable Length Array) in C source files. These are not
C89-compliant.
Main thread and task handlers
-----------------------------
The UI and the main thread must never block. When Threaded Tasks is
disabled - which it is on several platforms, and which users turn off
deliberately - task handlers run on the same thread that drives the
frame loop, so anything a handler does between returns is a frame the
UI cannot paint.
- Do not call task_queue_wait() from code reachable while the menu is
visible or a core is running. Cancel the work and guard against a
stale completion, or move what follows the wait into the task's own
callback. A last-resort safety net is acceptable only where an
invariant genuinely requires it (a worker must not call into a core
that is about to be unloaded, for instance), and then it must be
bounded and commented.
- Never pass a NULL condition to task_queue_wait(). It does not mean
"wait for my task": both queue implementations read it as "until the
queue is empty", so the caller ends up waiting out every unrelated
task in flight - a content scan, a core download. Pass a condition
that describes your own work.
- A handler that processes a collection must consult the shared
per-frame I/O window (task_nbio_slice_open /
task_nbio_slice_within_budget / task_nbio_slice_close) between
items, and must always complete at least one item per invocation so
an exhausted window cannot stall it. Do NOT chunk by a count derived
from the workload - "half the entries", "a quarter of the files" -
because that is not pacing: a bigger job simply produces bigger
chunks and the same number of invocations.
- Putting work on a background thread is not a substitute for pacing
it. The threaded queue is optional; the budget is what protects the
frame loop in the configuration that has no worker.
Debug builds report handlers that overrun a frame - see
task_queue_set_slow_handler_cb() - which is the cheapest way to find
out whether a handler you are adding respects any of this.
The waits that remain are the accepted ones, none of them reachable
while the menu is up or a core runs, each commented where it is:
* the command-line scan without a menu, which exits once done
(retroarch.c);
* the save/load state waits on exit, at startup and when an init
fails (content_wait_for_save_state_task() and
content_wait_for_load_state_task());
* the Wii U main loop's vsync wait (platform_wiiu.c).
Win32 file dialogs are modal by nature and stay so.
Commit message density
----------------------
Keep commit message short and appropriate for the size of the change. One or two
paragraphs appropriately sized based on the size of the change. Only explain how the
code works moving forward, not how it worked historically. Latter rule should also apply to code comments.
Miscellaneous
-------------
- Brace usage follows "Allman style". The brace associated with a control statement is placed on the following line,
+11 -51
View File
@@ -10,12 +10,6 @@ endif
include config.mk
# The absolute include paths configure found on the system
# (/usr/local/include on the BSDs, /opt/vc/include, ...) are searched after
# the tree's own; the relative ones (gfx/include/ANGLE) are the tree's.
SYSTEM_INCLUDE_DIRS := $(filter -I/%,$(INCLUDE_DIRS))
INCLUDE_DIRS := $(filter-out -I/%,$(INCLUDE_DIRS))
# Put your favorite compile flags in this file, if you want different defaults than upstream.
# Do not attempt to create that file upstream.
# (It'd be better to put this comment in that file, but .gitignore doesn't work on files that exist in the repo.)
@@ -119,11 +113,7 @@ endif
ifneq ($(CXX_BUILD), 1)
ifneq ($(C89_BUILD),)
# The shader sources built into gfx/drivers/gl_shaders are longer
# than the 509 characters C90 guarantees a compiler will take in a
# string literal, which no declaration of ours can help: this lane
# is here for declarations, comments and C99 syntax.
CFLAGS += -std=c89 -ansi -pedantic -Werror=pedantic -Wno-long-long -Werror=declaration-after-statement -Wno-variadic-macros -Wno-overlength-strings
CFLAGS += -std=c89 -ansi -pedantic -Werror=pedantic -Wno-long-long -Werror=declaration-after-statement -Wno-variadic-macros
else ifeq ($(HAVE_C99), 1)
CFLAGS += $(C99_CFLAGS)
endif
@@ -131,11 +121,7 @@ ifneq ($(CXX_BUILD), 1)
CFLAGS += -D_GNU_SOURCE
endif
# The tree's own headers come before any system or pkg-config path, so a
# same-named header installed on the system cannot stand in for one of
# ours.
DEF_FLAGS := -I. $(INCLUDE_DIRS) -Ideps $(filter-out -I.,$(DEF_FLAGS)) \
$(SYSTEM_INCLUDE_DIRS)
DEF_FLAGS += $(INCLUDE_DIRS) -Ideps
CFLAGS += $(DEF_FLAGS)
CXXFLAGS += $(DEF_FLAGS) -D__STDC_CONSTANT_MACROS
@@ -170,15 +156,6 @@ ifneq ($(SANITIZER),)
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
endif
# GFX_INSTRUMENT=1 counts what the image and surface paths do - uploads,
# in-place updates, allocations, canvas copies, overlay pages - so the
# budgets those paths are written to can be checked instead of argued.
# Off by default: without it the counters do not exist and no call to
# them survives the preprocessor.
ifeq ($(GFX_INSTRUMENT), 1)
DEFINES += -DHAVE_GFX_INSTRUMENT
endif
ifneq ($(findstring $(GPERFTOOLS),profiler),)
LIBS += -lprofiler
endif
@@ -245,10 +222,7 @@ config.mk:
else
-include $(RARCH_OBJ:.o=.d)
ifeq ($(HAVE_CONFIG_MK),)
# The Wayland protocol sources are generated by configure, so a tree
# configured before a protocol was added has no way to make the new
# object: ask for the reconfigure rather than fail on a missing file.
config.mk: configure qb/* gfx/common/wayland/generate_wayland_protos.sh
config.mk: configure qb/*
@echo "config.mk is outdated or non-existing. Run ./configure again."
@exit 1
endif
@@ -265,7 +239,7 @@ $(TARGET): $(RARCH_OBJ)
# Metal.xcodeproj build; the commandline build has to do it by hand.
# The .metallib must sit next to the retroarch binary at runtime.
ifeq ($(HAVE_METAL), 1)
METAL_SHADER_SRCS := gfx/drivers/metal_shaders/Shaders.metal
METAL_SHADER_SRCS := gfx/common/metal/Shaders.metal
METAL_AIR_FILES := $(METAL_SHADER_SRCS:.metal=.air)
%.air: %.metal
@@ -298,26 +272,12 @@ $(OBJDIR)/%.o: %.m
# RetroArch Objective-C code is MRC-written (explicit retain/release,
# NSAutoreleasePool, etc.) and would fail to compile under ARC — so
# we cannot set -fobjc-arc globally. Xcode does the equivalent via
# per-file CLANG_ENABLE_OBJC_ARC=YES build settings. ARC is a clang
# feature; GCC (a PowerPC cross build, Xcode 3) has no such switch and
# builds these files under MRC through the RARCH_* ownership macros.
#
# metal.m compiles correctly under BOTH ARC and MRC (its ownership
# transfers go through the RARCH_* ownership layer in libretro-common's
# defines/cocoa_defines.h, keyed on __has_feature(objc_arc)); it has to,
# because the griffin_objc.m unity TU inherits whatever mode the
# enclosing Xcode configuration uses. ARC is kept for the standalone
# object as the preferred mode: it elides the autorelease-pool traffic
# the MRC expansion pays on the per-frame paths.
# --version rather than -v: the latter prints the configure line, and a
# GCC configured with CC=clang would be taken for clang.
ifeq ($(shell $(CC) --version 2>&1 | head -n 1 | grep -c "clang"),1)
OBJC_ARC_FLAGS := -fobjc-arc
endif
$(OBJDIR)/gfx/drivers/metal.o: OBJCFLAGS += $(OBJC_ARC_FLAGS)
$(OBJDIR)/input/drivers_joypad/mfi_joypad.o: OBJCFLAGS += $(OBJC_ARC_FLAGS)
$(OBJDIR)/input/drivers/cocoa_input.o: OBJCFLAGS += $(OBJC_ARC_FLAGS)
$(OBJDIR)/location/drivers/corelocation.o: OBJCFLAGS += $(OBJC_ARC_FLAGS)
# per-file CLANG_ENABLE_OBJC_ARC=YES build settings.
$(OBJDIR)/gfx/drivers/metal.o: OBJCFLAGS += -fobjc-arc
$(OBJDIR)/input/drivers_joypad/mfi_joypad.o: OBJCFLAGS += -fobjc-arc
$(OBJDIR)/audio/drivers/coreaudio3.o: OBJCFLAGS += -fobjc-arc
$(OBJDIR)/input/drivers/cocoa_input.o: OBJCFLAGS += -fobjc-arc
$(OBJDIR)/location/drivers/corelocation.o: OBJCFLAGS += -fobjc-arc
$(OBJDIR)/%.o: %.S config.h config.mk $(HEADERS)
@mkdir -p $(dir $@)
@@ -393,7 +353,7 @@ clean:
$(Q)rm -rf $(OBJDIR_BASE)
$(Q)rm -f $(TARGET)
$(Q)rm -f *.d
$(Q)rm -f default.metallib gfx/drivers/metal_shaders/*.air
$(Q)rm -f default.metallib gfx/common/metal/*.air
$(Q)rm -rf $(BUNDLE)
# ---------------------------------------------------------------------------
Loaded 100 of 3138 files, more files were not shown because too many files have changed in this diff. Show more