fix(linux): add frame processing latency and logging improvements #7383
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
name: CI | |
on: | |
pull_request: | |
branches: [master, nightly] | |
types: [opened, synchronize, reopened] | |
push: | |
branches: [master, nightly] | |
workflow_dispatch: | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref }} | |
cancel-in-progress: true | |
jobs: | |
github_env: | |
name: GitHub Env Debug | |
runs-on: ubuntu-latest | |
steps: | |
- name: Dump github context | |
run: echo "$GITHUB_CONTEXT" | |
shell: bash | |
env: | |
GITHUB_CONTEXT: ${{ toJson(github) }} | |
check_changelog: | |
name: Check Changelog | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }} | |
uses: actions/checkout@v4 | |
- name: Verify Changelog | |
id: verify_changelog | |
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }} | |
# base_ref for pull request check, ref for push | |
uses: LizardByte/.github/actions/verify_changelog@master | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
outputs: | |
next_version: ${{ steps.verify_changelog.outputs.changelog_parser_version }} | |
next_version_bare: ${{ steps.verify_changelog.outputs.changelog_parser_version_bare }} | |
last_version: ${{ steps.verify_changelog.outputs.latest_release_tag_name }} | |
release_body: ${{ steps.verify_changelog.outputs.changelog_parser_description }} | |
# todo - remove this job once versioning is fully automated by cmake | |
check_versions: | |
name: Check Versions | |
runs-on: ubuntu-latest | |
needs: check_changelog | |
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }} | |
# base_ref for pull request check, ref for push | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Check CMakeLists.txt Version | |
run: | | |
version=$(grep -o -E '^project\(Sunshine VERSION [0-9]+\.[0-9]+\.[0-9]+' CMakeLists.txt | \ | |
grep -o -E '[0-9]+\.[0-9]+\.[0-9]+') | |
echo "cmakelists_version=${version}" >> $GITHUB_ENV | |
- name: Compare CMakeList.txt Version | |
if: ${{ env.cmakelists_version != needs.check_changelog.outputs.next_version_bare }} | |
run: | | |
echo CMakeLists version: "$cmakelists_version" | |
echo Changelog version: "${{ needs.check_changelog.outputs.next_version_bare }}" | |
echo Within 'CMakeLists.txt' change "project(Sunshine [VERSION $cmakelists_version]" to \ | |
"project(Sunshine [VERSION ${{ needs.check_changelog.outputs.next_version_bare }}]" | |
exit 1 | |
setup_release: | |
name: Setup Release | |
needs: check_changelog | |
runs-on: ubuntu-latest | |
steps: | |
- name: Set release details | |
id: release_details | |
env: | |
RELEASE_BODY: ${{ needs.check_changelog.outputs.release_body }} | |
run: | | |
# determine to create a release or not | |
if [[ $GITHUB_EVENT_NAME == "push" ]]; then | |
RELEASE=true | |
else | |
RELEASE=false | |
fi | |
# set the release tag | |
COMMIT=${{ github.sha }} | |
if [[ $GITHUB_REF == refs/heads/master ]]; then | |
TAG="${{ needs.check_changelog.outputs.next_version }}" | |
RELEASE_NAME="${{ needs.check_changelog.outputs.next_version }}" | |
RELEASE_BODY="$RELEASE_BODY" | |
PRE_RELEASE="false" | |
elif [[ $GITHUB_REF == refs/heads/nightly ]]; then | |
TAG="nightly-dev" | |
RELEASE_NAME="nightly" | |
RELEASE_BODY="automated nightly release - $(date -u +'%Y-%m-%dT%H:%M:%SZ') - ${COMMIT}" | |
PRE_RELEASE="true" | |
fi | |
echo "create_release=${RELEASE}" >> $GITHUB_OUTPUT | |
echo "release_tag=${TAG}" >> $GITHUB_OUTPUT | |
echo "release_commit=${COMMIT}" >> $GITHUB_OUTPUT | |
echo "release_name=${RELEASE_NAME}" >> $GITHUB_OUTPUT | |
echo "pre_release=${PRE_RELEASE}" >> $GITHUB_OUTPUT | |
# this is stupid but works for multiline strings | |
echo "RELEASE_BODY<<EOF" >> $GITHUB_ENV | |
echo "$RELEASE_BODY" >> $GITHUB_ENV | |
echo "EOF" >> $GITHUB_ENV | |
outputs: | |
create_release: ${{ steps.release_details.outputs.create_release }} | |
release_tag: ${{ steps.release_details.outputs.release_tag }} | |
release_commit: ${{ steps.release_details.outputs.release_commit }} | |
release_name: ${{ steps.release_details.outputs.release_name }} | |
release_body: ${{ env.RELEASE_BODY }} | |
pre_release: ${{ steps.release_details.outputs.pre_release }} | |
setup_flatpak_matrix: | |
name: Setup Flatpak Matrix | |
runs-on: ubuntu-latest | |
steps: | |
- name: Set release details | |
id: flatpak_matrix | |
# https://www.cynkra.com/blog/2020-12-23-dynamic-gha | |
run: | | |
# determine which architectures to build | |
if [[ $GITHUB_EVENT_NAME == "push" ]]; then | |
matrix=$(( | |
echo '{ "arch" : ["x86_64", "aarch64"] }' | |
) | jq -c .) | |
else | |
matrix=$(( | |
echo '{ "arch" : ["x86_64"] }' | |
) | jq -c .) | |
fi | |
echo $matrix | |
echo $matrix | jq . | |
echo "matrix=$matrix" >> $GITHUB_OUTPUT | |
outputs: | |
matrix: ${{ steps.flatpak_matrix.outputs.matrix }} | |
build_linux_flatpak: | |
name: Linux Flatpak | |
runs-on: ubuntu-22.04 | |
needs: [setup_release, setup_flatpak_matrix] | |
strategy: | |
fail-fast: false # false to test all, true to fail entire job if any fail | |
matrix: ${{fromJson(needs.setup_flatpak_matrix.outputs.matrix)}} | |
steps: | |
- name: Maximize build space | |
uses: easimon/maximize-build-space@v8 | |
with: | |
root-reserve-mb: 10240 | |
remove-dotnet: 'true' | |
remove-android: 'true' | |
remove-haskell: 'true' | |
remove-codeql: 'true' | |
remove-docker-images: 'true' | |
- name: Checkout | |
uses: actions/checkout@v4 | |
with: | |
submodules: recursive | |
- name: Setup Dependencies Linux Flatpak | |
run: | | |
PLATFORM_VERSION=22.08 | |
sudo apt-get update -y | |
sudo apt-get install -y \ | |
cmake \ | |
flatpak \ | |
qemu-user-static | |
sudo su $(whoami) -c "flatpak --user remote-add --if-not-exists flathub \ | |
https://flathub.org/repo/flathub.flatpakrepo" | |
sudo su $(whoami) -c "flatpak --user install -y flathub \ | |
org.flatpak.Builder \ | |
org.freedesktop.Platform/${{ matrix.arch }}/${PLATFORM_VERSION} \ | |
org.freedesktop.Sdk/${{ matrix.arch }}/${PLATFORM_VERSION} \ | |
org.freedesktop.Sdk.Extension.node18/${{ matrix.arch }}/${PLATFORM_VERSION} \ | |
org.freedesktop.Sdk.Extension.vala/${{ matrix.arch }}/${PLATFORM_VERSION} \ | |
" | |
- name: Cache Flatpak build | |
uses: actions/cache@v3 | |
with: | |
path: ./build/.flatpak-builder | |
key: flatpak-${{ matrix.arch }}-${{ github.sha }} | |
restore-keys: | | |
flatpak-${{ matrix.arch }}- | |
- name: Configure Flatpak Manifest | |
run: | | |
# variables for manifest | |
branch=${GITHUB_HEAD_REF} | |
# check the branch variable | |
if [ -z "$branch" ] | |
then | |
echo "This is a PUSH event" | |
branch=${{ github.ref_name }} | |
build_version=${{ needs.check_changelog.outputs.next_version }} | |
commit=${{ github.sha }} | |
clone_url=${{ github.event.repository.clone_url }} | |
else | |
echo "This is a PR event" | |
commit=${{ github.event.pull_request.head.sha }} | |
clone_url=${{ github.event.pull_request.head.repo.clone_url }} | |
fi | |
echo "Branch: ${branch}" | |
echo "Commit: ${commit}" | |
echo "Clone URL: ${clone_url}" | |
mkdir -p build | |
mkdir -p artifacts | |
cd build | |
cmake -DGITHUB_CLONE_URL=${clone_url} \ | |
-DBUILD_VERSION=${build_version} \ | |
-DGITHUB_BRANCH=${branch} \ | |
-DGITHUB_COMMIT=${commit} \ | |
-DSUNSHINE_CONFIGURE_FLATPAK_MAN=ON \ | |
-DSUNSHINE_CONFIGURE_ONLY=ON \ | |
.. | |
- name: Build Linux Flatpak | |
working-directory: build | |
run: | | |
sudo su $(whoami) -c 'flatpak run org.flatpak.Builder --arch=${{ matrix.arch }} --repo=repo --force-clean \ | |
--stop-at=cuda build-sunshine dev.lizardbyte.sunshine.yml' | |
cp -r .flatpak-builder copy-of-flatpak-builder | |
sudo su $(whoami) -c 'flatpak run org.flatpak.Builder --arch=${{ matrix.arch }} --repo=repo --force-clean \ | |
build-sunshine dev.lizardbyte.sunshine.yml' | |
rm -rf .flatpak-builder | |
mv copy-of-flatpak-builder .flatpak-builder | |
sudo su $(whoami) -c 'flatpak build-bundle --arch=${{ matrix.arch }} ./repo \ | |
../artifacts/sunshine_${{ matrix.arch }}.flatpak dev.lizardbyte.sunshine' | |
sudo su $(whoami) -c 'flatpak build-bundle --runtime --arch=${{ matrix.arch }} ./repo \ | |
../artifacts/sunshine_debug_${{ matrix.arch }}.flatpak dev.lizardbyte.sunshine.Debug' | |
- name: Upload Artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: sunshine-linux-flatpak-${{ matrix.arch }} | |
path: artifacts/ | |
- name: Create/Update GitHub Release | |
if: ${{ needs.setup_release.outputs.create_release == 'true' }} | |
uses: ncipollo/release-action@v1 | |
with: | |
name: ${{ needs.setup_release.outputs.release_name }} | |
tag: ${{ needs.setup_release.outputs.release_tag }} | |
commit: ${{ needs.setup_release.outputs.release_commit }} | |
artifacts: "*artifacts/*" | |
token: ${{ secrets.GH_BOT_TOKEN }} | |
allowUpdates: true | |
body: ${{ needs.setup_release.outputs.release_body }} | |
discussionCategory: announcements | |
prerelease: ${{ needs.setup_release.outputs.pre_release }} | |
build_linux: | |
name: Linux ${{ matrix.type }} | |
runs-on: ubuntu-${{ matrix.dist }} | |
needs: [check_changelog, setup_release] | |
strategy: | |
fail-fast: false # false to test all, true to fail entire job if any fail | |
matrix: | |
include: # package these differently | |
- type: AppImage | |
EXTRA_ARGS: '-DSUNSHINE_BUILD_APPIMAGE=ON' | |
dist: 22.04 | |
steps: | |
- name: Maximize build space | |
uses: easimon/maximize-build-space@v8 | |
with: | |
root-reserve-mb: 30720 | |
remove-dotnet: 'true' | |
remove-android: 'true' | |
remove-haskell: 'true' | |
remove-codeql: 'true' | |
remove-docker-images: 'true' | |
- name: Checkout | |
uses: actions/checkout@v4 | |
with: | |
submodules: recursive | |
- name: Install wget | |
run: | | |
sudo apt-get update -y | |
sudo apt-get install -y \ | |
wget | |
- name: Install CUDA | |
env: | |
CUDA_VERSION: 11.8.0 | |
CUDA_BUILD: 520.61.05 | |
timeout-minutes: 4 | |
run: | | |
url_base="https://developer.download.nvidia.com/compute/cuda/${CUDA_VERSION}/local_installers" | |
url="${url_base}/cuda_${CUDA_VERSION}_${CUDA_BUILD}_linux.run" | |
sudo wget -q -O /root/cuda.run ${url} | |
sudo chmod a+x /root/cuda.run | |
sudo /root/cuda.run --silent --toolkit --toolkitpath=/usr/local/cuda --no-opengl-libs --no-man-page --no-drm | |
sudo rm /root/cuda.run | |
- name: Setup Dependencies Linux | |
timeout-minutes: 5 | |
run: | | |
# allow newer gcc | |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y | |
# allow libfuse2 for appimage on 22.04 | |
sudo add-apt-repository universe | |
sudo apt-get install -y \ | |
build-essential \ | |
cmake \ | |
gcc-10 \ | |
g++-10 \ | |
libayatana-appindicator3-dev \ | |
libavdevice-dev \ | |
libboost-filesystem-dev \ | |
libboost-locale-dev \ | |
libboost-log-dev \ | |
libboost-program-options-dev \ | |
libcap-dev \ | |
libcurl4-openssl-dev \ | |
libdrm-dev \ | |
libevdev-dev \ | |
libfuse2 \ | |
libminiupnpc-dev \ | |
libmfx-dev \ | |
libnotify-dev \ | |
libnuma-dev \ | |
libopus-dev \ | |
libpulse-dev \ | |
libssl-dev \ | |
libva-dev \ | |
libvdpau-dev \ | |
libwayland-dev \ | |
libx11-dev \ | |
libxcb-shm0-dev \ | |
libxcb-xfixes0-dev \ | |
libxcb1-dev \ | |
libxfixes-dev \ | |
libxrandr-dev \ | |
libxtst-dev \ | |
python3 | |
# clean apt cache | |
sudo apt-get clean | |
sudo rm -rf /var/lib/apt/lists/* | |
# Update gcc alias | |
# https://stackoverflow.com/a/70653945/11214013 | |
sudo update-alternatives --install \ | |
/usr/bin/gcc gcc /usr/bin/gcc-10 100 \ | |
--slave /usr/bin/g++ g++ /usr/bin/g++-10 \ | |
--slave /usr/bin/gcov gcov /usr/bin/gcov-10 \ | |
--slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-10 \ | |
--slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-10 | |
- name: Setup python | |
id: python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.11' | |
- name: Build Linux | |
env: | |
BRANCH: ${{ github.head_ref || github.ref_name }} | |
BUILD_VERSION: ${{ needs.check_changelog.outputs.next_version }} | |
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }} | |
timeout-minutes: 10 | |
run: | | |
echo "nproc: $(nproc)" | |
mkdir -p build | |
mkdir -p artifacts | |
cd build | |
cmake \ | |
-DBUILD_WERROR=ON \ | |
-DCMAKE_BUILD_TYPE=Release \ | |
-DCMAKE_CUDA_COMPILER:PATH=/usr/local/cuda/bin/nvcc \ | |
-DCMAKE_INSTALL_PREFIX=/usr \ | |
-DSUNSHINE_ASSETS_DIR=share/sunshine \ | |
-DSUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine \ | |
-DSUNSHINE_ENABLE_WAYLAND=ON \ | |
-DSUNSHINE_ENABLE_X11=ON \ | |
-DSUNSHINE_ENABLE_DRM=ON \ | |
-DSUNSHINE_ENABLE_CUDA=ON \ | |
${{ matrix.EXTRA_ARGS }} \ | |
.. | |
make -j $(expr $(nproc) - 1) # use all but one core | |
- name: Set AppImage Version | |
if: | | |
matrix.type == 'AppImage' && | |
(needs.check_changelog.outputs.next_version_bare != needs.check_changelog.outputs.last_version) | |
run: | | |
version=${{ needs.check_changelog.outputs.next_version_bare }} | |
echo "VERSION=${version}" >> $GITHUB_ENV | |
- name: Package Linux - AppImage | |
if: ${{ matrix.type == 'AppImage' }} | |
working-directory: build | |
run: | | |
# install sunshine to the DESTDIR | |
make install DESTDIR=AppDir | |
# custom AppRun file | |
cp -f ../packaging/linux/AppImage/AppRun ./AppDir/ | |
chmod +x ./AppDir/AppRun | |
# variables | |
DESKTOP_FILE="${DESKTOP_FILE:-sunshine.desktop}" | |
ICON_FILE="${ICON_FILE:-sunshine.png}" | |
# AppImage | |
# https://docs.appimage.org/packaging-guide/index.html | |
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage | |
chmod +x linuxdeploy-x86_64.AppImage | |
# https://github.com/linuxdeploy/linuxdeploy-plugin-gtk | |
sudo apt-get install libgtk-3-dev librsvg2-dev -y | |
wget -q https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh | |
chmod +x linuxdeploy-plugin-gtk.sh | |
export DEPLOY_GTK_VERSION=3 | |
./linuxdeploy-x86_64.AppImage \ | |
--appdir ./AppDir \ | |
--plugin gtk \ | |
--executable ./sunshine \ | |
--icon-file "../$ICON_FILE" \ | |
--desktop-file "./$DESKTOP_FILE" \ | |
--output appimage | |
# move | |
mv Sunshine*.AppImage ../artifacts/sunshine.AppImage | |
# permissions | |
chmod +x ../artifacts/sunshine.AppImage | |
- name: Delete cuda | |
# free up space on the runner | |
run: | | |
sudo rm -rf /usr/local/cuda | |
- name: Verify AppImage | |
if: ${{ matrix.type == 'AppImage' }} | |
run: | | |
wget https://github.com/TheAssassin/appimagelint/releases/download/continuous/appimagelint-x86_64.AppImage | |
chmod +x appimagelint-x86_64.AppImage | |
./appimagelint-x86_64.AppImage ./artifacts/sunshine.AppImage | |
- name: Upload Artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: sunshine-linux-${{ matrix.type }}-${{ matrix.dist }} | |
path: artifacts/ | |
- name: Install test deps | |
run: | | |
sudo apt-get update -y | |
sudo apt-get install -y \ | |
doxygen \ | |
graphviz \ | |
python3-venv \ | |
x11-xserver-utils \ | |
xvfb | |
# clean apt cache | |
sudo apt-get clean | |
sudo rm -rf /var/lib/apt/lists/* | |
- name: Run tests | |
id: test | |
working-directory: build/tests | |
run: | | |
export DISPLAY=:1 | |
Xvfb ${DISPLAY} -screen 0 1024x768x24 & | |
./test_sunshine --gtest_color=yes | |
- name: Generate gcov report | |
# any except canceled or skipped | |
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure') | |
id: test_report | |
working-directory: build | |
run: | | |
${{ steps.python.outputs.python-path }} -m pip install gcovr | |
${{ steps.python.outputs.python-path }} -m gcovr -r .. \ | |
--exclude-noncode-lines \ | |
--exclude-throw-branches \ | |
--exclude-unreachable-branches \ | |
--exclude '.*tests/.*' \ | |
--exclude '.*third-party/.*' \ | |
--xml-pretty \ | |
-o coverage.xml | |
- name: Upload coverage | |
# any except canceled or skipped | |
if: >- | |
always() && | |
(steps.test_report.outcome == 'success') && | |
startsWith(github.repository, 'LizardByte/') | |
uses: codecov/codecov-action@v4 | |
with: | |
disable_search: true | |
fail_ci_if_error: true | |
files: ./build/coverage.xml | |
flags: ${{ runner.os }} | |
token: ${{ secrets.CODECOV_TOKEN }} | |
verbose: true | |
- name: Create/Update GitHub Release | |
if: ${{ needs.setup_release.outputs.create_release == 'true' }} | |
uses: ncipollo/release-action@v1 | |
with: | |
name: ${{ needs.setup_release.outputs.release_name }} | |
tag: ${{ needs.setup_release.outputs.release_tag }} | |
commit: ${{ needs.setup_release.outputs.release_commit }} | |
artifacts: "*artifacts/*" | |
token: ${{ secrets.GH_BOT_TOKEN }} | |
allowUpdates: true | |
body: ${{ needs.setup_release.outputs.release_body }} | |
discussionCategory: announcements | |
prerelease: ${{ needs.setup_release.outputs.pre_release }} | |
build_mac_brew: | |
needs: [check_changelog, setup_release] | |
strategy: | |
fail-fast: false # false to test all, true to fail entire job if any fail | |
matrix: | |
include: | |
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories | |
# while GitHub has larger macOS runners, they are not available for our repos :( | |
- os_version: "12" | |
release: true | |
- os_version: "13" | |
- os_version: "14" | |
name: Homebrew (macOS-${{ matrix.os_version }}) | |
runs-on: macos-${{ matrix.os_version }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Setup Dependencies Homebrew | |
run: | | |
# install dependencies using homebrew | |
brew install cmake | |
- name: Configure formula | |
run: | | |
# variables for formula | |
branch=${GITHUB_HEAD_REF} | |
# check the branch variable | |
if [ -z "$branch" ] | |
then | |
echo "This is a PUSH event" | |
build_version=${{ needs.check_changelog.outputs.next_version }} | |
clone_url=${{ github.event.repository.clone_url }} | |
branch="${{ github.ref_name }}" | |
commit=${{ github.sha }} | |
default_branch="${{ github.event.repository.default_branch }}" | |
else | |
echo "This is a PR event" | |
clone_url=${{ github.event.pull_request.head.repo.clone_url }} | |
branch="${{ github.event.pull_request.head.ref }}" | |
commit=${{ github.event.pull_request.head.sha }} | |
default_branch="${{ github.event.pull_request.head.repo.default_branch }}" | |
fi | |
echo "Branch: ${branch}" | |
echo "Clone URL: ${clone_url}" | |
mkdir build | |
cd build | |
cmake \ | |
-DBUILD_VERSION="${build_version}" \ | |
-DGITHUB_BRANCH="${branch}" \ | |
-DGITHUB_COMMIT="${commit}" \ | |
-DGITHUB_CLONE_URL="${clone_url}" \ | |
-DGITHUB_DEFAULT_BRANCH="${default_branch}" \ | |
-DSUNSHINE_CONFIGURE_HOMEBREW=ON \ | |
-DSUNSHINE_CONFIGURE_ONLY=ON \ | |
.. | |
cd .. | |
# copy formula to artifacts | |
mkdir -p homebrew | |
cp -f ./build/sunshine.rb ./homebrew/sunshine.rb | |
# testing | |
cat ./homebrew/sunshine.rb | |
- name: Upload Artifacts | |
if: ${{ matrix.release }} | |
uses: actions/upload-artifact@v4 | |
with: | |
name: sunshine-homebrew | |
path: homebrew/ | |
- name: Should Publish Homebrew Formula | |
id: homebrew_publish | |
run: | | |
PUBLISH=false | |
if [[ \ | |
"${{ matrix.release }}" == "true" && \ | |
"${{ github.repository_owner }}" == "LizardByte" && \ | |
"${{ needs.setup_release.outputs.create_release }}" == "true" && \ | |
"${{ github.ref }}" == "refs/heads/master" \ | |
]]; then | |
PUBLISH=true | |
fi | |
echo "publish=${PUBLISH}" >> $GITHUB_OUTPUT | |
- name: Validate and Publish Homebrew Formula | |
uses: LizardByte/homebrew-release-action@v2024.417.220943 | |
with: | |
formula_file: ${{ github.workspace }}/homebrew/sunshine.rb | |
git_email: ${{ secrets.GH_BOT_EMAIL }} | |
git_username: ${{ secrets.GH_BOT_NAME }} | |
publish: ${{ steps.homebrew_publish.outputs.publish }} | |
token: ${{ secrets.GH_BOT_TOKEN }} | |
build_mac_port: | |
needs: [check_changelog, setup_release] | |
strategy: | |
fail-fast: false # false to test all, true to fail entire job if any fail | |
matrix: | |
include: | |
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories | |
# while GitHub has larger macOS runners, they are not available for our repos :( | |
- os_version: "12" | |
release: true | |
- os_version: "13" | |
- os_version: "14" | |
name: Macports (macOS-${{ matrix.os_version }}) | |
runs-on: macos-${{ matrix.os_version }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Checkout ports | |
uses: actions/checkout@v4 | |
with: | |
repository: macports/macports-ports | |
fetch-depth: 64 | |
path: ports | |
- name: Checkout mpbb | |
uses: actions/checkout@v4 | |
with: | |
repository: macports/mpbb | |
path: mpbb | |
- name: Setup Dependencies Macports | |
run: | | |
# install dependencies using homebrew | |
brew install cmake | |
- name: Setup python | |
id: python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.11' | |
- name: Configure Portfile | |
run: | | |
# variables for Portfile | |
branch=${GITHUB_HEAD_REF} | |
# check the branch variable | |
if [ -z "$branch" ] | |
then | |
echo "This is a PUSH event" | |
branch="${{ github.ref_name }}" | |
build_version=${{ needs.check_changelog.outputs.next_version }} | |
commit=${{ github.sha }} | |
clone_url=${{ github.event.repository.clone_url }} | |
else | |
echo "This is a PR event" | |
commit=${{ github.event.pull_request.head.sha }} | |
clone_url=${{ github.event.pull_request.head.repo.clone_url }} | |
fi | |
echo "Commit: ${commit}" | |
echo "Clone URL: ${clone_url}" | |
mkdir build | |
cd build | |
cmake \ | |
-DBUILD_VERSION=${build_version} \ | |
-DGITHUB_BRANCH=${branch} \ | |
-DGITHUB_COMMIT=${commit} \ | |
-DGITHUB_CLONE_URL=${clone_url} \ | |
-DSUNSHINE_CONFIGURE_PORTFILE=ON \ | |
-DSUNSHINE_CONFIGURE_ONLY=ON \ | |
.. | |
cd .. | |
# copy Portfile to artifacts | |
mkdir -p artifacts | |
cp -f ./build/Portfile ./artifacts/ | |
# copy Portfile to ports | |
mkdir -p ./ports/multimedia/Sunshine | |
cp -f ./build/Portfile ./ports/multimedia/Sunshine/Portfile | |
# testing | |
cat ./artifacts/Portfile | |
- name: Bootstrap MacPorts | |
run: | | |
. ports/.github/workflows/bootstrap.sh | |
# Add getopt, mpbb and the MacPorts paths to $PATH for the subsequent steps. | |
echo "/opt/mports/bin" >> $GITHUB_PATH | |
echo "${PWD}/mpbb" >> $GITHUB_PATH | |
echo "/opt/local/bin" >> $GITHUB_PATH | |
echo "/opt/local/sbin" >> $GITHUB_PATH | |
- name: Run port lint | |
run: | | |
port -q lint "Sunshine" | |
- name: Build port | |
env: | |
subportlist: ${{ steps.subportlist.outputs.subportlist }} | |
id: build | |
run: | | |
subport="Sunshine" | |
workdir="/tmp/mpbb/$subport" | |
mkdir -p "$workdir/logs" | |
echo "::group::Installing dependencies" | |
sudo mpbb \ | |
--work-dir "$workdir" \ | |
install-dependencies \ | |
"$subport" | |
echo "::endgroup::" | |
echo "::group::Installing ${subport}" | |
sudo mpbb \ | |
--work-dir "$workdir" \ | |
install-port \ | |
--source \ | |
"$subport" | |
echo "::endgroup::" | |
- name: Build Logs | |
if: always() | |
run: | | |
logfile="/opt/local/var/macports/logs/_Users_runner_work_Sunshine_Sunshine_ports_multimedia_Sunshine/Sunshine/main.log" | |
cat "$logfile" | |
sudo mv "${logfile}" "${logfile}.bak" | |
- name: Upload Artifacts | |
if: ${{ matrix.release }} | |
uses: actions/upload-artifact@v4 | |
with: | |
name: sunshine-macports | |
path: artifacts/ | |
- name: Fix screen capture permissions | |
if: ${{ matrix.os_version != 12 }} # macOS-12 is okay | |
# can be removed if the following is fixed in the runner image | |
# https://github.com/actions/runner-images/issues/9529 | |
# https://github.com/actions/runner-images/pull/9530 | |
run: | | |
# https://apple.stackexchange.com/questions/362865/macos-list-apps-authorized-for-full-disk-access | |
# permissions for screen capture | |
values="'kTCCServiceScreenCapture','/opt/off/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159" | |
if [[ "${{ matrix.os_version }}" == "14" ]]; then | |
# TCC access table in Sonoma has extra 4 columns: pid, pid_version, boot_uuid, last_reminded | |
values="${values},NULL,NULL,'UNUSED',${values##*,}" | |
fi | |
# system and user databases | |
dbPaths=( | |
"/Library/Application Support/com.apple.TCC/TCC.db" | |
"$HOME/Library/Application Support/com.apple.TCC/TCC.db" | |
) | |
sqlQuery="INSERT OR IGNORE INTO access VALUES($values);" | |
for dbPath in "${dbPaths[@]}"; do | |
echo "Column names for $dbPath" | |
echo "-------------------" | |
sudo sqlite3 "$dbPath" "PRAGMA table_info(access);" | |
echo "Current permissions for $dbPath" | |
echo "-------------------" | |
sudo sqlite3 "$dbPath" "SELECT * FROM access WHERE service='kTCCServiceScreenCapture';" | |
sudo sqlite3 "$dbPath" "$sqlQuery" | |
echo "Updated permissions for $dbPath" | |
echo "-------------------" | |
sudo sqlite3 "$dbPath" "SELECT * FROM access WHERE service='kTCCServiceScreenCapture';" | |
done | |
- name: Run tests | |
id: test | |
timeout-minutes: 10 | |
run: | | |
sudo port test "Sunshine" | |
- name: Test Logs | |
if: always() | |
run: | | |
logfile="/opt/local/var/macports/logs/_Users_runner_work_Sunshine_Sunshine_ports_multimedia_Sunshine/Sunshine/main.log" | |
cat "$logfile" | |
- name: Generate gcov report | |
# any except canceled or skipped | |
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure') | |
id: test_report | |
working-directory: | |
/opt/local/var/macports/build/_Users_runner_work_Sunshine_Sunshine_ports_multimedia_Sunshine/Sunshine/work | |
run: | | |
base_dir=$(pwd) | |
build_dir=${base_dir}/build | |
# get the directory name that starts with Sunshine-* | |
dir=$(ls -d Sunshine-*) | |
cd ${build_dir} | |
${{ steps.python.outputs.python-path }} -m pip install gcovr | |
sudo ${{ steps.python.outputs.python-path }} -m gcovr -r ../${dir} \ | |
--exclude-noncode-lines \ | |
--exclude-throw-branches \ | |
--exclude-unreachable-branches \ | |
--exclude '.*${dir}/tests/.*' \ | |
--exclude '.*${dir}/third-party/.*' \ | |
--gcov-object-directory $(pwd) \ | |
--verbose \ | |
--xml-pretty \ | |
-o ${{ github.workspace }}/build/coverage.xml | |
- name: Upload coverage | |
# any except canceled or skipped | |
if: >- | |
always() && | |
(steps.test_report.outcome == 'success') && | |
startsWith(github.repository, 'LizardByte/') | |
uses: codecov/codecov-action@v4 | |
with: | |
disable_search: true | |
fail_ci_if_error: false # todo: re-enable this when action is fixed | |
files: ./build/coverage.xml | |
flags: ${{ runner.os }}-${{ matrix.os_version }} | |
token: ${{ secrets.CODECOV_TOKEN }} | |
verbose: true | |
- name: Create/Update GitHub Release | |
if: ${{ needs.setup_release.outputs.create_release == 'true' && matrix.release }} | |
uses: ncipollo/release-action@v1 | |
with: | |
name: ${{ needs.setup_release.outputs.release_name }} | |
tag: ${{ needs.setup_release.outputs.release_tag }} | |
commit: ${{ needs.setup_release.outputs.release_commit }} | |
artifacts: "*artifacts/*" | |
token: ${{ secrets.GH_BOT_TOKEN }} | |
allowUpdates: true | |
body: ${{ needs.setup_release.outputs.release_body }} | |
discussionCategory: announcements | |
prerelease: ${{ needs.setup_release.outputs.pre_release }} | |
build_win: | |
name: Windows | |
runs-on: windows-2019 | |
needs: [check_changelog, setup_release] | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
with: | |
submodules: recursive | |
- name: Prepare tests | |
id: prepare-tests | |
if: false # todo: DirectX11 is not available, so even software encoder fails | |
run: | | |
# function to download and extract a zip file | |
function DownloadAndExtract { | |
param ( | |
[string]$Uri, | |
[string]$OutFile | |
) | |
$maxRetries = 5 | |
$retryCount = 0 | |
$success = $false | |
while (-not $success -and $retryCount -lt $maxRetries) { | |
$retryCount++ | |
Write-Host "Downloading $Uri to $OutFile, attempt $retryCount of $maxRetries" | |
try { | |
Invoke-WebRequest -Uri $Uri -OutFile $OutFile | |
$success = $true | |
} catch { | |
Write-Host "Attempt $retryCount of $maxRetries failed with error: $($_.Exception.Message). Retrying..." | |
Start-Sleep -Seconds 5 | |
} | |
} | |
if (-not $success) { | |
Write-Host "Failed to download the file after $maxRetries attempts." | |
exit 1 | |
} | |
# use .NET to get the base name of the file | |
$baseName = (Get-Item $OutFile).BaseName | |
# Extract the zip file | |
Expand-Archive -Path $OutFile -DestinationPath $baseName | |
} | |
# virtual display driver | |
DownloadAndExtract ` | |
-Uri "https://www.amyuni.com/downloads/usbmmidd_v2.zip" ` | |
-OutFile "usbmmidd_v2.zip" | |
# install | |
Set-Location -Path usbmmidd_v2/usbmmidd_v2 | |
./deviceinstaller64 install usbmmidd.inf usbmmidd | |
# create the virtual display | |
./deviceinstaller64 enableidd 1 | |
# move up a directory | |
Set-Location -Path ../.. | |
# install devcon | |
DownloadAndExtract ` | |
-Uri "https://github.com/Drawbackz/DevCon-Installer/releases/download/1.4-rc/Devcon.Installer.zip" ` | |
-OutFile "Devcon.Installer.zip" | |
Set-Location -Path Devcon.Installer | |
# hash needs to match OS version | |
# https://github.com/Drawbackz/DevCon-Installer/blob/master/devcon_sources.json | |
Start-Process -FilePath "./Devcon Installer.exe" -Wait -ArgumentList ` | |
'install', ` | |
'-hash', '54004C83EE34F6A55380528A8B29F4C400E61FBB947A19E0AB9E5A193D7D961E', ` | |
'-addpath', ` | |
'-update', ` | |
'-dir', 'C:\Windows\System32' | |
# disable Hyper-V Video | |
# https://stackoverflow.com/a/59490940 | |
C:\Windows\System32\devcon.exe disable "VMBUS\{da0a7802-e377-4aac-8e77-0558eb1073f8}" | |
# move up a directory | |
Set-Location -Path .. | |
# multi monitor tool | |
DownloadAndExtract ` | |
-Uri "http://www.nirsoft.net/utils/multimonitortool-x64.zip" ` | |
-OutFile "multimonitortool.zip" | |
# enable the virtual display | |
# http://www.nirsoft.net/utils/multi_monitor_tool.html | |
Set-Location -Path multimonitortool | |
# Original Hyper-V is \\.\DISPLAY1, it will recreate itself as \\.\DISPLAY6 (or something higher than 2) | |
# USB Mobile Monitor Virtual Display is \\.\DISPLAY2 | |
# these don't seem to work if not using runAs | |
# todo: do they work if not using runAs? | |
Start-Process powershell -Verb runAs -ArgumentList '-Command ./MultiMonitorTool.exe /enable \\.\DISPLAY2' | |
Start-Process powershell -Verb runAs -ArgumentList '-Command ./MultiMonitorTool.exe /SetPrimary \\.\DISPLAY2' | |
# wait a few seconds | |
Start-Sleep -s 5 | |
# list monitors | |
./MultiMonitorTool.exe /stext monitor_list.txt | |
# wait a few seconds | |
Start-Sleep -s 5 | |
# print the monitor list | |
Get-Content -Path monitor_list.txt | |
- name: Setup Dependencies Windows | |
uses: msys2/setup-msys2@v2 | |
with: | |
update: true | |
install: >- | |
base-devel | |
diffutils | |
doxygen | |
git | |
make | |
mingw-w64-x86_64-binutils | |
mingw-w64-x86_64-boost | |
mingw-w64-x86_64-cmake | |
mingw-w64-x86_64-curl | |
mingw-w64-x86_64-graphviz | |
mingw-w64-x86_64-miniupnpc | |
mingw-w64-x86_64-nlohmann-json | |
mingw-w64-x86_64-nodejs | |
mingw-w64-x86_64-nsis | |
mingw-w64-x86_64-onevpl | |
mingw-w64-x86_64-openssl | |
mingw-w64-x86_64-opus | |
mingw-w64-x86_64-toolchain | |
nasm | |
wget | |
yasm | |
- name: Setup python | |
# use this instead of msys2 python due to known issues using wheels, https://www.msys2.org/docs/python/ | |
id: setup-python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.11' | |
- name: Python Path | |
id: python-path | |
shell: msys2 {0} | |
run: | | |
# replace backslashes with double backslashes | |
python_path=$(echo "${{ steps.setup-python.outputs.python-path }}" | sed 's/\\/\\\\/g') | |
# step output | |
echo "python-path=${python_path}" | |
echo "python-path=${python_path}" >> $GITHUB_OUTPUT | |
- name: Build Windows | |
shell: msys2 {0} | |
env: | |
BRANCH: ${{ github.head_ref || github.ref_name }} | |
BUILD_VERSION: ${{ needs.check_changelog.outputs.next_version }} | |
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }} | |
run: | | |
mkdir build | |
cd build | |
cmake \ | |
-DBUILD_WERROR=ON \ | |
-DCMAKE_BUILD_TYPE=RelWithDebInfo \ | |
-DSUNSHINE_ASSETS_DIR=assets \ | |
-DTESTS_PYTHON_EXECUTABLE='${{ steps.python-path.outputs.python-path }}' \ | |
-DTESTS_SOFTWARE_ENCODER_UNAVAILABLE='skip' \ | |
-G "MinGW Makefiles" \ | |
.. | |
mingw32-make -j$(nproc) | |
- name: Package Windows | |
shell: msys2 {0} | |
run: | | |
mkdir -p artifacts | |
cd build | |
# package | |
cpack -G NSIS | |
cpack -G ZIP | |
# move | |
mv ./cpack_artifacts/Sunshine.exe ../artifacts/sunshine-windows-installer.exe | |
mv ./cpack_artifacts/Sunshine.zip ../artifacts/sunshine-windows-portable.zip | |
- name: Run tests | |
id: test | |
shell: msys2 {0} | |
working-directory: build/tests | |
run: | | |
./test_sunshine.exe --gtest_color=yes | |
- name: Generate gcov report | |
# any except canceled or skipped | |
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure') | |
id: test_report | |
shell: msys2 {0} | |
working-directory: build | |
run: | | |
${{ steps.python-path.outputs.python-path }} -m pip install gcovr | |
${{ steps.python-path.outputs.python-path }} -m gcovr -r .. \ | |
--exclude-noncode-lines \ | |
--exclude-throw-branches \ | |
--exclude-unreachable-branches \ | |
--exclude '.*tests/.*' \ | |
--exclude '.*third-party/.*' \ | |
--xml-pretty \ | |
-o coverage.xml | |
- name: Upload coverage | |
# any except canceled or skipped | |
if: >- | |
always() && | |
(steps.test_report.outcome == 'success') && | |
startsWith(github.repository, 'LizardByte/') | |
uses: codecov/codecov-action@v4 | |
with: | |
disable_search: true | |
fail_ci_if_error: true | |
files: ./build/coverage.xml | |
flags: ${{ runner.os }} | |
token: ${{ secrets.CODECOV_TOKEN }} | |
verbose: true | |
- name: Package Windows Debug Info | |
working-directory: build | |
run: | | |
# use .dbg file extension for binaries to avoid confusion with real packages | |
Get-ChildItem -File -Recurse | ` | |
% { Rename-Item -Path $_.PSPath -NewName $_.Name.Replace(".exe",".dbg") } | |
# save the binaries with debug info | |
7z -r ` | |
"-xr!CMakeFiles" ` | |
"-xr!cpack_artifacts" ` | |
a "../artifacts/sunshine-win32-debuginfo.7z" "*.dbg" | |
- name: Upload Artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: sunshine-windows | |
path: artifacts/ | |
- name: Create/Update GitHub Release | |
if: ${{ needs.setup_release.outputs.create_release == 'true' }} | |
uses: ncipollo/release-action@v1 | |
with: | |
name: ${{ needs.setup_release.outputs.release_name }} | |
tag: ${{ needs.setup_release.outputs.release_tag }} | |
commit: ${{ needs.setup_release.outputs.release_commit }} | |
artifacts: "*artifacts/*" | |
token: ${{ secrets.GH_BOT_TOKEN }} | |
allowUpdates: true | |
body: ${{ needs.setup_release.outputs.release_body }} | |
discussionCategory: announcements | |
prerelease: ${{ needs.setup_release.outputs.pre_release }} | |
release-winget: | |
name: Release to WinGet | |
needs: [setup_release, build_win] | |
if: | | |
(github.repository_owner == 'LizardByte' && | |
needs.setup_release.outputs.create_release == 'true' && | |
github.ref == 'refs/heads/master') | |
runs-on: ubuntu-latest | |
steps: | |
- name: Release to WinGet | |
uses: vedantmgoyal2009/winget-releaser@v2 | |
with: | |
identifier: LizardByte.Sunshine | |
release-tag: ${{ needs.setup_release.outputs.release_tag }} | |
installers-regex: '\.exe$' # only .exe files | |
token: ${{ secrets.GH_BOT_TOKEN }} |