mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-09 17:29:21 -10:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
928d1a0810 | ||
|
|
6919bc9cd7 | ||
|
|
a8c5b1815e | ||
|
|
cf6aab7ad2 | ||
|
|
f0cce58206 | ||
|
|
07ac0685e2 | ||
|
|
e3e1d87705 | ||
|
|
05a483cbe6 | ||
|
|
2c5cde4125 | ||
|
|
5f8bbcd1b6 | ||
|
|
e81d65d51b | ||
|
|
193133d616 | ||
|
|
d2cf7a113b | ||
|
|
4e07070e86 | ||
|
|
4562153839 |
No files matched your search
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }}'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
@@ -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
@@ -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)"
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
@@ -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 +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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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: |
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
@@ -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,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
|
||||
@@ -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: |
|
||||
|
||||
@@ -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 }}
|
||||
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
@@ -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)"
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)"
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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/"
|
||||
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
|
||||
|
||||
+6
-179
@@ -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,
|
||||
|
||||
@@ -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
Reference in new issue
Block a user