Merge pull request #2216 from LizardByte/nightly

v0.22.1
This commit is contained in:
ReenigneArcher
2024-03-13 23:17:30 -04:00
committed by GitHub
41 changed files with 603 additions and 311 deletions

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
# ensure dockerfiles are checked out with LF line endings
Dockerfile text eol=lf
*.dockerfile text eol=lf

View File

@@ -505,124 +505,111 @@ jobs:
discussionCategory: announcements
prerelease: ${{ needs.setup_release.outputs.pre_release }}
build_mac:
name: MacOS
runs-on: macos-11
build_mac_brew:
needs: [check_changelog, setup_release]
env:
BOOST_VERSION: 1.83.0
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
with:
submodules: recursive
- name: Setup Dependencies MacOS
- name: Setup Dependencies Homebrew
run: |
# install dependencies using homebrew
brew install cmake curl miniupnpc node openssl opus pkg-config
brew install cmake
# fix openssl header not found
# ln -sf /usr/local/opt/openssl/include/openssl /usr/local/include/openssl
# by installing boost from source, several headers cannot be found...
# the above commented out link only works if boost is installed from homebrew... does not make sense
ln -sf $(find /usr/local/Cellar -type d -name "openssl" -path "*/openssl@3/*/include" | head -n 1) \
/usr/local/include/openssl
# fix opus header not found
ln -sf $(find /usr/local/Cellar -type d -name "opus" -path "*/opus/*/include" | head -n 1) \
/usr/local/include/opus
# fix miniupnpc header not found
ln -sf $(find /usr/local/Cellar -type d -name "miniupnpc" -path "*/miniupnpc/*/include" | head -n 1) \
/usr/local/include/miniupnpc
- name: Install Boost
# installing boost from homebrew takes 30 minutes in a GitHub runner
- name: Configure formula
run: |
export BOOST_ROOT=${HOME}/boost-${BOOST_VERSION}
# variables for formula
branch=${GITHUB_HEAD_REF}
# install boost
wget \
https://github.com/boostorg/boost/releases/download/boost-${BOOST_VERSION}/boost-${BOOST_VERSION}.tar.gz \
--progress=bar:force:noscroll -q --show-progress
tar xf boost-${BOOST_VERSION}.tar.gz
cd boost-${BOOST_VERSION}
# check the branch variable
if [ -z "$branch" ]
then
echo "This is a PUSH event"
clone_url=${{ github.event.repository.clone_url }}
branch="${{ github.ref_name }}"
else
echo "This is a PR event"
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
branch="${{ github.event.pull_request.head.ref }}"
fi
echo "Branch: ${branch}"
echo "Clone URL: ${clone_url}"
# libdir should be set by --prefix but isn't
./bootstrap.sh \
--prefix=${BOOST_ROOT} \
--libdir=${BOOST_ROOT}/lib \
--with-libraries=locale,log,program_options,system,thread
./b2 headers
./b2 install \
--prefix=${BOOST_ROOT} \
--libdir=${BOOST_ROOT}/lib \
-j$(sysctl -n hw.ncpu) \
link=shared,static \
variant=release \
cxxflags=-std=c++14 \
cxxflags=-stdlib=libc++ \
linkflags=-stdlib=libc++
# put boost in cmake prefix path
echo "BOOST_ROOT=${BOOST_ROOT}" >> ${GITHUB_ENV}
- name: Build MacOS
env:
BRANCH: ${{ github.head_ref || github.ref_name }}
BUILD_VERSION: ${{ needs.check_changelog.outputs.next_version_bare }}
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
mkdir build
cd build
cmake \
-DBUILD_WERROR=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DSUNSHINE_ASSETS_DIR=local/sunshine/assets \
-DSUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine \
-DGITHUB_BRANCH="${branch}" \
-DGITHUB_CLONE_URL="${clone_url}" \
-DSUNSHINE_CONFIGURE_HOMEBREW=ON \
-DSUNSHINE_CONFIGURE_ONLY=ON \
..
make -j $(sysctl -n hw.ncpu)
cd ..
- name: Package MacOS
run: |
mkdir -p artifacts
cd build
# copy formula to artifacts
mkdir -p homebrew
cp -f ./build/sunshine.rb ./homebrew/sunshine.rb
# package
cpack -G DragNDrop
mv ./cpack_artifacts/Sunshine.dmg ../artifacts/sunshine.dmg
# cpack -G Bundle
# mv ./cpack_artifacts/Sunshine.dmg ../artifacts/sunshine-bundle.dmg
# testing
cat ./homebrew/sunshine.rb
- name: Upload Artifacts
if: ${{ matrix.release }}
uses: actions/upload-artifact@v4
with:
name: sunshine-macos
path: artifacts/
name: sunshine-homebrew
path: homebrew/
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.create_release == 'true' }}
uses: ncipollo/release-action@v1
- 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.311.172824
with:
name: ${{ needs.setup_release.outputs.release_name }}
tag: ${{ needs.setup_release.outputs.release_tag }}
commit: ${{ needs.setup_release.outputs.release_commit }}
artifacts: "*artifacts/*"
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 }}
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}
discussionCategory: announcements
prerelease: ${{ needs.setup_release.outputs.pre_release }}
build_mac_port:
name: Macports
needs: [check_changelog, setup_release]
runs-on: macos-11
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
@@ -725,13 +712,14 @@ jobs:
echo "::endgroup::"
- name: Upload Artifacts
if: ${{ matrix.release }}
uses: actions/upload-artifact@v4
with:
name: sunshine-macports
path: artifacts/
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.create_release == 'true' }}
if: ${{ needs.setup_release.outputs.create_release == 'true' && matrix.release }}
uses: ncipollo/release-action@v1
with:
name: ${{ needs.setup_release.outputs.release_name }}
@@ -814,11 +802,15 @@ jobs:
- name: Package Windows Debug Info
working-directory: build
run: |
# save the original binaries with debug info
# 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-debuginfo-win32.zip" "*.exe"
a "../artifacts/sunshine-win32-debuginfo.7z" "*.dbg"
- name: Upload Artifacts
uses: actions/upload-artifact@v4

View File

@@ -1,5 +1,43 @@
# Changelog
## [0.22.1] - 2024-03-13
**Breaking**
- (ArchLinux) Drop support for standalone PKGBUILD files. Use the binary Arch package or install via AUR instead.
- (macOS) Drop support for experimental dmg package. Use Homebrew or MacPorts instead.
**Added**
- (macOS) Added Homebrew support
**Changed**
- (Process/Windows) The working directory is now searched first when the command contains a relative path
- (ArchLinux) The kmsgrab capture backend is now compiled by default to support Wayland capture on non-wlroots-based compositors
- (Capture/Linux) X11 capture is now preferred over kmsgrab for cards that lack atomic modesetting support to ensure cursor capture works
- (Capture/Linux) Kmsgrab will only choose NVENC by default if the display is connected to the Nvidia GPU to avoid possible EGL import failures
**Fixed**
- (Config) Fix unsupported resolution error with some Moonlight clients
- (Capture/Windows) Fix crash when streaming Ryujinx, Red Alert 2, and other apps that use unusually sized monochrome cursors
- (Capture/Linux) Fix crash in KMS cursor capture when running on Arch-based distros
- (Capture/Linux) Fix crash if CUDA GPU has a PCI ID with hexadecimal digits greater than 9
- (Process/Windows) Fix starting apps when the working directory is enclosed in quotes
- (Process/Windows) Fix process tree tracking when the app is launched via a cmd.exe trampoline
- (Installer/Windows) Fix slow operation during ViGEmBus installation that may cause the installer to appear stuck
- (Build/macOS) Fix issues building on macOS 13 and 14
- (Build/Linux) Fix missing install script in the Arch binary package
- (Build/Linux) Fix missing optional dependencies in the Arch binary package
- (Build/Linux) Ensure correct Arch pkg is published to GitHub releases
- (Capture/Linux) Fix mismatched case and unhandled exception in CUDA device lookup
- (Config) Add missing resolution to default config ui
- (Linux) Fix udev rules for uinput access not working until after reboot
- (Linux) Fix wrong path in desktop files
- (Tray) Cache icons to avoid possible DRM issues
- (Tray) Fix attempt to update tray icon after it was destroyed
- (Linux) Migrate old config files to new location if env SUNSHINE_MIGRATE_CONFIG=1 is set (automatically set for Flatpak)
- (Linux/Fedora) Re-enable CUDA support and bump to 12.4.0
**Misc**
- (Build/Windows) Adjust Windows debuginfo artifact to reduce confusion with real release binaries
## [0.22.0] - 2024-03-03
**Breaking**
- (Network) Clients must now be paired with the host before they can use Wake-on-LAN
@@ -720,3 +758,4 @@ settings. In v0.17.0, games now run under your user account without elevated pri
[0.20.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.20.0
[0.21.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.21.0
[0.22.0]: https://github.com/LizardByte/Sunshine/releases/tag/v0.22.0
[0.22.1]: https://github.com/LizardByte/Sunshine/releases/tag/v0.22.1

View File

@@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.18)
# todo - set this conditionally
# todo - set version to 0.0.0 once confident in automated versioning
project(Sunshine VERSION 0.22.0
DESCRIPTION "Sunshine is a self-hosted game stream host for Moonlight."
project(Sunshine VERSION 0.22.1
DESCRIPTION "Self-hosted game stream host for Moonlight"
HOMEPAGE_URL "https://app.lizardbyte.dev/Sunshine")
set(PROJECT_LICENSE "GPL-3.0")

View File

@@ -32,11 +32,11 @@ System Requirements
+------------+------------------------------------------------------------+
| OS | Windows: 10+ (Windows Server not supported) |
| +------------------------------------------------------------+
| | macOS: 11.7+ |
| | macOS: 12+ |
| +------------------------------------------------------------+
| | Linux/Debian: 11 (bullseye) |
| +------------------------------------------------------------+
| | Linux/Fedora: 37+ |
| | Linux/Fedora: 38+ |
| +------------------------------------------------------------+
| | Linux/Ubuntu: 20.04+ (focal) |
+------------+------------------------------------------------------------+

View File

@@ -3,7 +3,7 @@
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/assets/"
DESTINATION "${SUNSHINE_ASSETS_DIR}")
if(${SUNSHINE_BUILD_APPIMAGE} OR ${SUNSHINE_BUILD_FLATPAK})
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/85-sunshine.rules"
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/60-sunshine.rules"
DESTINATION "${SUNSHINE_ASSETS_DIR}/udev/rules.d")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service"
DESTINATION "${SUNSHINE_ASSETS_DIR}/systemd/user")
@@ -11,7 +11,7 @@ else()
find_package(Systemd)
find_package(Udev)
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/85-sunshine.rules"
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/60-sunshine.rules"
DESTINATION "${UDEV_RULES_INSTALL_DIR}")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service"
DESTINATION "${SYSTEMD_USER_UNIT_INSTALL_DIR}")

View File

@@ -1,8 +1,6 @@
# unix specific packaging
# put anything here that applies to both linux and macos
include(GNUInstallDirs)
# return here if building a macos package
if(SUNSHINE_PACKAGE_MACOS)
return()

View File

@@ -12,7 +12,15 @@ option(CUDA_INHERIT_COMPILE_OPTIONS
"When building CUDA code, inherit compile options from the the main project. You may want to disable this if
your IDE throws errors about unknown flags after running cmake." ON)
if(UNIX)
# technically, the homebrew build could be on linux as well... no idea if it would actually work
option(SUNSHINE_BUILD_HOMEBREW
"Enable a Homebrew build." OFF)
endif ()
if(APPLE)
option(SUNSHINE_CONFIGURE_HOMEBREW
"Configure macOS Homebrew formula. Recommended to use with SUNSHINE_CONFIGURE_ONLY" OFF)
option(SUNSHINE_CONFIGURE_PORTFILE
"Configure macOS Portfile. Recommended to use with SUNSHINE_CONFIGURE_ONLY" OFF)
option(SUNSHINE_PACKAGE_MACOS

View File

@@ -2,7 +2,12 @@ if (APPLE)
if(${SUNSHINE_CONFIGURE_PORTFILE})
configure_file(packaging/macos/Portfile Portfile @ONLY)
endif()
if(${SUNSHINE_CONFIGURE_HOMEBREW})
configure_file(packaging/macos/sunshine.rb sunshine.rb @ONLY)
endif()
elseif (UNIX)
include(GNUInstallDirs) # this needs to be included prior to configuring the desktop files
# configure the .desktop file
if(${SUNSHINE_BUILD_APPIMAGE})
configure_file(packaging/linux/AppImage/sunshine.desktop sunshine.desktop @ONLY)
@@ -24,6 +29,7 @@ elseif (UNIX)
# configure the arch linux pkgbuild
if(${SUNSHINE_CONFIGURE_PKGBUILD})
configure_file(packaging/linux/Arch/PKGBUILD PKGBUILD @ONLY)
configure_file(packaging/linux/Arch/sunshine.install sunshine.install @ONLY)
endif()
# configure the flatpak manifest

View File

@@ -37,8 +37,19 @@ endif()
target_compile_options(sunshine PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${SUNSHINE_COMPILE_OPTIONS}>;$<$<COMPILE_LANGUAGE:CUDA>:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>) # cmake-lint: disable=C0301
# Homebrew build fails the vite build if we set these environment variables
if(${SUNSHINE_BUILD_HOMEBREW})
set(NPM_SOURCE_ASSETS_DIR "")
set(NPM_ASSETS_DIR "")
set(NPM_BUILD_HOMEBREW "true")
else()
set(NPM_SOURCE_ASSETS_DIR ${SUNSHINE_SOURCE_ASSETS_DIR})
set(NPM_ASSETS_DIR ${CMAKE_BINARY_DIR})
set(NPM_BUILD_HOMEBREW "")
endif()
#WebUI build
add_custom_target(web-ui ALL
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Installing NPM Dependencies and Building the Web UI"
COMMAND bash -c \"npm install && SUNSHINE_SOURCE_ASSETS_DIR=${SUNSHINE_SOURCE_ASSETS_DIR} SUNSHINE_ASSETS_DIR=${CMAKE_BINARY_DIR} npm run build\") # cmake-lint: disable=C0301
COMMAND bash -c \"npm install && SUNSHINE_BUILD_HOMEBREW=${NPM_BUILD_HOMEBREW} SUNSHINE_SOURCE_ASSETS_DIR=${NPM_SOURCE_ASSETS_DIR} SUNSHINE_ASSETS_DIR=${NPM_ASSETS_DIR} npm run build\") # cmake-lint: disable=C0301

View File

@@ -34,7 +34,7 @@ ENV COMMIT=${COMMIT}
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# install dependencies
# cuda, libcap, and libdrm are optional dependencies for PKGBUILD
# cuda is an optional build-time dependency for PKGBUILD
RUN <<_DEPS
#!/bin/bash
set -e
@@ -43,8 +43,6 @@ pacman -Syu --disable-download-timeout --needed --noconfirm \
cmake \
cuda \
git \
libcap \
libdrm \
namcap
_DEPS
@@ -80,6 +78,7 @@ _MAKE
WORKDIR /build/sunshine/pkg
RUN mv /build/sunshine/build/PKGBUILD .
RUN mv /build/sunshine/build/sunshine.install .
# namcap and build PKGBUILD file
RUN <<_PKGBUILD
@@ -87,12 +86,12 @@ RUN <<_PKGBUILD
set -e
namcap -i PKGBUILD
makepkg -si --noconfirm
rm -f /build/sunshine/pkg/sunshine-debug*.pkg.tar.zst
ls -a
_PKGBUILD
FROM scratch as artifacts
COPY --link --from=sunshine-build /build/sunshine/pkg/PKGBUILD /PKGBUILD
COPY --link --from=sunshine-build /build/sunshine/pkg/sunshine*.pkg.tar.zst /sunshine.pkg.tar.zst
FROM sunshine-base as sunshine

View File

@@ -68,28 +68,27 @@ dnf clean all
rm -rf /var/cache/yum
_DEPS
# todo - enable cuda once it's supported for gcc 13 and fedora 38
## install cuda
#WORKDIR /build/cuda
WORKDIR /build/cuda
## versions: https://developer.nvidia.com/cuda-toolkit-archive
#ENV CUDA_VERSION="12.0.0"
#ENV CUDA_BUILD="525.60.13"
ENV CUDA_VERSION="12.4.0"
ENV CUDA_BUILD="550.54.14"
## hadolint ignore=SC3010
#RUN <<_INSTALL_CUDA
##!/bin/bash
#set -e
#cuda_prefix="https://developer.download.nvidia.com/compute/cuda/"
#cuda_suffix=""
#if [[ "${TARGETPLATFORM}" == 'linux/arm64' ]]; then
# cuda_suffix="_sbsa"
#fi
#url="${cuda_prefix}${CUDA_VERSION}/local_installers/cuda_${CUDA_VERSION}_${CUDA_BUILD}_linux${cuda_suffix}.run"
#echo "cuda url: ${url}"
#wget "$url" --progress=bar:force:noscroll -q --show-progress -O ./cuda.run
#chmod a+x ./cuda.run
#./cuda.run --silent --toolkit --toolkitpath=/build/cuda --no-opengl-libs --no-man-page --no-drm
#rm ./cuda.run
#_INSTALL_CUDA
RUN <<_INSTALL_CUDA
#!/bin/bash
set -e
cuda_prefix="https://developer.download.nvidia.com/compute/cuda/"
cuda_suffix=""
if [[ "${TARGETPLATFORM}" == 'linux/arm64' ]]; then
cuda_suffix="_sbsa"
fi
url="${cuda_prefix}${CUDA_VERSION}/local_installers/cuda_${CUDA_VERSION}_${CUDA_BUILD}_linux${cuda_suffix}.run"
echo "cuda url: ${url}"
wget "$url" --progress=bar:force:noscroll -q --show-progress -O ./cuda.run
chmod a+x ./cuda.run
./cuda.run --silent --toolkit --toolkitpath=/build/cuda --no-opengl-libs --no-man-page --no-drm
rm ./cuda.run
_INSTALL_CUDA
# copy repository
WORKDIR /build/sunshine/
@@ -99,12 +98,11 @@ COPY --link .. .
WORKDIR /build/sunshine/build
# cmake and cpack
# todo - add cmake argument back in for cuda support "-DCMAKE_CUDA_COMPILER:PATH=/build/cuda/bin/nvcc \"
# todo - re-enable "DSUNSHINE_ENABLE_CUDA"
RUN <<_MAKE
#!/bin/bash
set -e
cmake \
-DCMAKE_CUDA_COMPILER:PATH=/build/cuda/bin/nvcc \
-DBUILD_WERROR=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
@@ -113,7 +111,7 @@ cmake \
-DSUNSHINE_ENABLE_WAYLAND=ON \
-DSUNSHINE_ENABLE_X11=ON \
-DSUNSHINE_ENABLE_DRM=ON \
-DSUNSHINE_ENABLE_CUDA=OFF \
-DSUNSHINE_ENABLE_CUDA=ON \
/build/sunshine
make -j "$(nproc)"
cpack -G RPM

View File

@@ -68,28 +68,34 @@ dnf clean all
rm -rf /var/cache/yum
_DEPS
# todo - enable cuda once it's supported for gcc 13 and fedora 39
## install cuda
#WORKDIR /build/cuda
## versions: https://developer.nvidia.com/cuda-toolkit-archive
#ENV CUDA_VERSION="12.0.0"
#ENV CUDA_BUILD="525.60.13"
## hadolint ignore=SC3010
#RUN <<_INSTALL_CUDA
##!/bin/bash
#set -e
#cuda_prefix="https://developer.download.nvidia.com/compute/cuda/"
#cuda_suffix=""
#if [[ "${TARGETPLATFORM}" == 'linux/arm64' ]]; then
# cuda_suffix="_sbsa"
#fi
#url="${cuda_prefix}${CUDA_VERSION}/local_installers/cuda_${CUDA_VERSION}_${CUDA_BUILD}_linux${cuda_suffix}.run"
#echo "cuda url: ${url}"
#wget "$url" --progress=bar:force:noscroll -q --show-progress -O ./cuda.run
#chmod a+x ./cuda.run
#./cuda.run --silent --toolkit --toolkitpath=/build/cuda --no-opengl-libs --no-man-page --no-drm
#rm ./cuda.run
#_INSTALL_CUDA
# install cuda
WORKDIR /build/cuda
# versions: https://developer.nvidia.com/cuda-toolkit-archive
ENV CUDA_VERSION="12.4.0"
ENV CUDA_BUILD="550.54.14"
# hadolint ignore=SC3010
RUN <<_INSTALL_CUDA
#!/bin/bash
set -e
cuda_prefix="https://developer.download.nvidia.com/compute/cuda/"
cuda_suffix=""
if [[ "${TARGETPLATFORM}" == 'linux/arm64' ]]; then
cuda_suffix="_sbsa"
# patch headers https://bugs.launchpad.net/ubuntu/+source/mumax3/+bug/2032624
sed -i 's/__Float32x4_t/int/g' /usr/include/bits/math-vector.h
sed -i 's/__Float64x2_t/int/g' /usr/include/bits/math-vector.h
sed -i 's/__SVFloat32_t/float/g' /usr/include/bits/math-vector.h
sed -i 's/__SVFloat64_t/float/g' /usr/include/bits/math-vector.h
sed -i 's/__SVBool_t/int/g' /usr/include/bits/math-vector.h
fi
url="${cuda_prefix}${CUDA_VERSION}/local_installers/cuda_${CUDA_VERSION}_${CUDA_BUILD}_linux${cuda_suffix}.run"
echo "cuda url: ${url}"
wget "$url" --progress=bar:force:noscroll -q --show-progress -O ./cuda.run
chmod a+x ./cuda.run
./cuda.run --silent --toolkit --toolkitpath=/build/cuda --no-opengl-libs --no-man-page --no-drm
rm ./cuda.run
_INSTALL_CUDA
# copy repository
WORKDIR /build/sunshine/
@@ -99,12 +105,11 @@ COPY --link .. .
WORKDIR /build/sunshine/build
# cmake and cpack
# todo - add cmake argument back in for cuda support "-DCMAKE_CUDA_COMPILER:PATH=/build/cuda/bin/nvcc \"
# todo - re-enable "DSUNSHINE_ENABLE_CUDA"
RUN <<_MAKE
#!/bin/bash
set -e
cmake \
-DCMAKE_CUDA_COMPILER:PATH=/build/cuda/bin/nvcc \
-DBUILD_WERROR=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
@@ -113,7 +118,7 @@ cmake \
-DSUNSHINE_ENABLE_WAYLAND=ON \
-DSUNSHINE_ENABLE_X11=ON \
-DSUNSHINE_ENABLE_DRM=ON \
-DSUNSHINE_ENABLE_CUDA=OFF \
-DSUNSHINE_ENABLE_CUDA=ON \
/build/sunshine
make -j "$(nproc)"
cpack -G RPM

View File

@@ -6,6 +6,8 @@ and applications to Sunshine.
.. attention:: Throughout these examples, any fields not shown are left blank. You can enhance your experience by
adding an image or a log file (via the ``Output`` field).
.. note:: When a working directory is not specified, it defaults to the folder where the target application resides.
Common Examples
---------------
@@ -24,7 +26,7 @@ Steam Big Picture
^^^^^^^^^^^^^^^^^
.. note:: Steam is launched as a detached command because Steam starts with a process that self updates itself and the original
process is killed. Since the original process ends it will not work as a regular command.
process is killed.
.. tab:: Linux
@@ -51,7 +53,7 @@ Steam Big Picture
+----------------------+-----------------------------+
| Application Name | ``Steam Big Picture`` |
+----------------------+-----------------------------+
| Detached Commands | ``steam://open/bigpicture`` |
| Command | ``steam://open/bigpicture`` |
+----------------------+-----------------------------+
| Image | ``steam.png`` |
+----------------------+-----------------------------+
@@ -59,8 +61,7 @@ Steam Big Picture
Epic Game Store game
^^^^^^^^^^^^^^^^^^^^
.. note:: Using URI method will be the most consistent between various games, but does not allow a game to be launched
using the "Command" and therefore the stream will not end when the game ends.
.. note:: Using URI method will be the most consistent between various games.
URI (Epic)
""""""""""
@@ -70,7 +71,7 @@ URI (Epic)
+----------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| Application Name | ``Surviving Mars`` |
+----------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| Detached Commands | ``com.epicgames.launcher://apps/d759128018124dcabb1fbee9bb28e178%3A20729b9176c241f0b617c5723e70ec2d%3AOvenbird?action=launch&silent=true`` |
| Command | ``com.epicgames.launcher://apps/d759128018124dcabb1fbee9bb28e178%3A20729b9176c241f0b617c5723e70ec2d%3AOvenbird?action=launch&silent=true`` |
+----------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
Binary (Epic w/ working directory)
@@ -81,7 +82,7 @@ Binary (Epic w/ working directory)
+----------------------+-----------------------------------------------+
| Application Name | ``Surviving Mars`` |
+----------------------+-----------------------------------------------+
| Command | ``cmd /c "MarsEpic.exe"`` |
| Command | ``MarsEpic.exe`` |
+----------------------+-----------------------------------------------+
| Working Directory | ``C:\Program Files\Epic Games\SurvivingMars`` |
+----------------------+-----------------------------------------------+
@@ -100,8 +101,7 @@ Binary (Epic w/o working directory)
Steam game
^^^^^^^^^^
.. note:: Using URI method will be the most consistent between various games, but does not allow a game to be launched
using the "Command" and therefore the stream will not end when the game ends.
.. note:: Using URI method will be the most consistent between various games.
URI (Steam)
"""""""""""
@@ -127,7 +127,7 @@ URI (Steam)
+----------------------+------------------------------+
| Application Name | ``Surviving Mars`` |
+----------------------+------------------------------+
| Detached Commands | ``steam://rungameid/464920`` |
| Command | ``steam://rungameid/464920`` |
+----------------------+------------------------------+
Binary (Steam w/ working directory)

View File

@@ -38,20 +38,21 @@ Install
=========================================== ============== ============== ================================
Package CUDA Version Min Driver CUDA Compute Capabilities
=========================================== ============== ============== ================================
PKGBUILD User dependent User dependent User dependent
sunshine.AppImage 11.8.0 450.80.02 35;50;52;60;61;62;70;75;80;86;90
sunshine.pkg.tar.zst 11.8.0 450.80.02 35;50;52;60;61;62;70;75;80;86;90
sunshine_{arch}.flatpak 12.0.0 525.60.13 50;52;60;61;62;70;75;80;86;90
sunshine-debian-bookworm-{arch}.deb 12.0.0 525.60.13 50;52;60;61;62;70;75;80;86;90
sunshine-debian-bullseye-{arch}.deb 11.8.0 450.80.02 35;50;52;60;61;62;70;75;80;86;90
sunshine-fedora-38-{arch}.rpm unavailable unavailable none
sunshine-fedora-39-{arch}.rpm unavailable unavailable none
sunshine-fedora-38-{arch}.rpm 12.4.0 525.60.13 50;52;60;61;62;70;75;80;86;90
sunshine-fedora-39-{arch}.rpm 12.4.0 525.60.13 50;52;60;61;62;70;75;80;86;90
sunshine-ubuntu-20.04-{arch}.deb 11.8.0 450.80.02 35;50;52;60;61;62;70;75;80;86;90
sunshine-ubuntu-22.04-{arch}.deb 11.8.0 450.80.02 35;50;52;60;61;62;70;75;80;86;90
=========================================== ============== ============== ================================
.. tab:: AppImage
.. caution:: Use distro-specific packages instead of the AppImage if they are available.
According to AppImageLint the supported distro matrix of the AppImage is below.
- ✔ Debian bullseye
@@ -90,21 +91,7 @@ Install
./sunshine.AppImage --remove
.. tab:: Archlinux PKGBUILD
#. Open terminal and run the following code.
.. code-block:: bash
wget https://github.com/LizardByte/Sunshine/releases/latest/download/PKGBUILD
makepkg -fi
Uninstall:
.. code-block:: bash
pacman -R sunshine
.. tab:: Archlinux pkg
.. tab:: Arch Linux Package
#. Open terminal and run the following code.
@@ -118,7 +105,7 @@ Install
pacman -R sunshine
.. tab:: Debian Package
.. tab:: Debian/Ubuntu Package
#. Download ``sunshine-{distro}-{distro-version}-{arch}.deb`` and run the following code.
@@ -138,6 +125,8 @@ Install
.. tab:: Flatpak Package
.. caution:: Use distro-specific packages instead of the Flatpak if they are available.
.. important:: The instructions provided here are for the version supplied in the `latest release`_, which does
not necessarily match the version in the Flathub repository!
@@ -205,16 +194,35 @@ Install
sudo dnf remove sunshine
The `deb`, `rpm`, `Flatpak` and `AppImage` packages should handle these steps automatically.
The `deb`, `rpm`, `zst`, `Flatpak` and `AppImage` packages should handle these steps automatically.
Third party packages may not.
Sunshine needs access to `uinput` to create mouse and gamepad events.
#. Create `udev` rules.
#. Create and reload `udev` rules for uinput.
.. code-block:: bash
echo 'KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"' | \
sudo tee /etc/udev/rules.d/85-sunshine.rules
sudo tee /etc/udev/rules.d/60-sunshine.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
sudo modprobe uinput
#. Enable permissions for KMS capture.
.. warning:: Capture of most Wayland-based desktop environments will fail unless this step is performed.
.. note:: ``cap_sys_admin`` may as well be root, except you don't need to be root to run it. It is necessary to
allow Sunshine to use KMS capture.
**Enable**
.. code-block:: bash
sudo setcap cap_sys_admin+p $(readlink -f $(which sunshine))
**Disable (for Xorg/X11 only)**
.. code-block:: bash
sudo setcap -r $(readlink -f $(which sunshine))
#. Optionally, configure autostart service
@@ -260,20 +268,6 @@ Install
systemctl --user enable sunshine
#. Additional Setup for KMS
.. note:: ``cap_sys_admin`` may as well be root, except you don't need to be root to run it. It is necessary to
allow Sunshine to use KMS.
**Enable**
.. code-block:: bash
sudo setcap cap_sys_admin+p $(readlink -f $(which sunshine))
**Disable (for Xorg/X11)**
.. code-block:: bash
sudo setcap -r $(readlink -f $(which sunshine))
#. Reboot
.. code-block:: bash
@@ -281,20 +275,17 @@ Install
.. tab:: macOS
.. important:: Sunshine on macOS is experimental. Gamepads do not work. Other features may not work as expected.
.. important:: Sunshine on macOS is experimental. Gamepads do not work.
.. tab:: dmg
.. tab:: Homebrew
.. warning:: The `dmg` does not include runtime dependencies. This package is not recommended for most users.
No support will be provided!
#. Install `Homebrew <https://docs.brew.sh/Installation>`__
#. Update the Homebrew sources and install Sunshine.
#. Download the ``sunshine.dmg`` file and install it.
Uninstall:
.. code-block:: bash
cd /etc/sunshine/assets
uninstall_pkg.sh
brew tap LizardByte/homebrew
brew install sunshine
.. tab:: Portfile

View File

@@ -20,9 +20,23 @@ Install Requirements
.. code-block:: bash
brew install boost cmake miniupnpc node opus pkg-config
# if there are issues with an SSL header that is not found:
cd /usr/local/include
ln -s ../opt/openssl/include/openssl .
If there are issues with an SSL header that is not found:
.. tab:: Intel
.. code-block:: bash
pushd /usr/local/include
ln -s ../opt/openssl/include/openssl .
popd
.. tab:: Apple Silicon
.. code-block:: bash
pushd /opt/homebrew/include
ln -s ../opt/openssl/include/openssl .
popd
Build
-----

View File

@@ -46,7 +46,9 @@ echo "
function install() {
# user input rules
# shellcheck disable=SC2002
cat "$SUNSHINE_SHARE_HERE/udev/rules.d/85-sunshine.rules" | sudo tee /etc/udev/rules.d/85-sunshine.rules
cat "$SUNSHINE_SHARE_HERE/udev/rules.d/60-sunshine.rules" | sudo tee /etc/udev/rules.d/60-sunshine.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --property-match=DEVNAME=/dev/uinput
# sunshine service
mkdir -p ~/.config/systemd/user
@@ -56,30 +58,11 @@ function install() {
# setcap
sudo setcap cap_sys_admin+p "$(readlink -f "$SUNSHINE_BIN_HERE")"
while true
do
read -r -p "This installation requires a reboot. Do you want to reboot NOW? [y/n] " input
case $input in
[yY][eE][sS]|[yY])
echo "Yes"
sudo reboot now
;;
[nN][oO]|[nN])
echo "No"
break
;;
*)
echo "Invalid input..."
;;
esac
done
}
function remove() {
# remove input rules
sudo rm -f /etc/udev/rules.d/85-sunshine.rules
sudo rm -f /etc/udev/rules.d/60-sunshine.rules
# remove service
sudo rm -f ~/.config/systemd/user/sunshine.service

View File

@@ -8,11 +8,14 @@ pkgdesc="@PROJECT_DESCRIPTION@"
arch=('x86_64' 'aarch64')
url=@PROJECT_HOMEPAGE_URL@
license=('GPL3')
install=sunshine.install
depends=('avahi'
'boost-libs'
'curl'
'libayatana-appindicator'
'libcap'
'libdrm'
'libevdev'
'libmfx'
'libnotify'
@@ -35,9 +38,9 @@ makedepends=('boost'
'make'
'nodejs'
'npm')
optdepends=('cuda: NvFBC capture support'
'libcap'
'libdrm')
optdepends=('cuda: Nvidia GPU encoding support'
'libva-mesa-driver: AMD GPU encoding support'
'intel-media-driver: Intel GPU encoding support')
provides=('sunshine')

View File

@@ -0,0 +1,20 @@
do_setcap() {
setcap cap_sys_admin+p $(readlink -f $(which sunshine))
}
do_udev_reload() {
udevadm control --reload-rules
udevadm trigger --property-match=DEVNAME=/dev/uinput
modprobe uinput || true
}
post_install() {
do_setcap
do_udev_reload
}
post_upgrade() {
do_setcap
do_udev_reload
}

View File

@@ -11,6 +11,7 @@ separate-locales: false
finish-args:
- --device=all # access all devices
- --env=PULSE_PROP_media.category=Manager # allow sunshine to manage audio sinks
- --env=SUNSHINE_MIGRATE_CONFIG=1 # migrate config files to the new location
- --filesystem=home # need to save files in user's home directory
- --share=ipc # required for X11 shared memory extension
- --share=network # access network

View File

@@ -7,7 +7,7 @@ echo Sunshine User Service has been installed.
echo Use [systemctl --user enable sunshine] once to autostart Sunshine on login.
# Udev rule
UDEV=$(cat /app/share/sunshine/udev/rules.d/85-sunshine.rules)
UDEV=$(cat /app/share/sunshine/udev/rules.d/60-sunshine.rules)
echo Configuring mouse permission.
flatpak-spawn --host pkexec sh -c "echo '$UDEV' > /etc/udev/rules.d/85-sunshine.rules"
flatpak-spawn --host pkexec sh -c "echo '$UDEV' > /etc/udev/rules.d/60-sunshine.rules"
echo Restart computer for mouse permission to take effect.

View File

@@ -7,5 +7,5 @@ systemctl --user daemon-reload
echo Sunshine User Service has been removed.
# Udev rule
flatpak-spawn --host pkexec sh -c "rm /etc/udev/rules.d/85-sunshine.rules"
flatpak-spawn --host pkexec sh -c "rm /etc/udev/rules.d/60-sunshine.rules"
echo Mouse permission removed. Restart computer to take effect.

View File

@@ -12,9 +12,9 @@ Actions=RunInTerminal;KMS;
[Desktop Action RunInTerminal]
Name=Run in Terminal
Icon=application-x-executable
Exec=gio launch @CMAKE_INSTALL_DATAROOTDIR@/applications/sunshine_terminal.desktop
Exec=gio launch @CMAKE_INSTALL_FULL_DATAROOTDIR@/applications/sunshine_terminal.desktop
[Desktop Action KMS]
Name=Run in Terminal (KMS)
Icon=application-x-executable
Exec=gio launch @CMAKE_INSTALL_DATAROOTDIR@/applications/sunshine_kms.desktop
Exec=gio launch @CMAKE_INSTALL_FULL_DATAROOTDIR@/applications/sunshine_kms.desktop

View File

@@ -12,4 +12,4 @@ Actions=RunInTerminal;
[Desktop Action RunInTerminal]
Name=Run in Terminal
Icon=application-x-executable
Exec=gio launch @CMAKE_INSTALL_DATAROOTDIR@/applications/sunshine_terminal.desktop
Exec=gio launch @CMAKE_INSTALL_FULL_DATAROOTDIR@/applications/sunshine_terminal.desktop

View File

@@ -0,0 +1,62 @@
require "language/node"
class @PROJECT_NAME@ < Formula
desc "@PROJECT_DESCRIPTION@"
homepage "@PROJECT_HOMEPAGE_URL@"
url "@GITHUB_CLONE_URL@",
tag: "@GITHUB_BRANCH@"
version "@PROJECT_VERSION@"
license all_of: ["GPL-3.0-only"]
head "@GITHUB_CLONE_URL@", branch: "nightly"
depends_on "boost" => :build
depends_on "cmake" => :build
depends_on "pkg-config" => :build
depends_on "curl"
depends_on "miniupnpc"
depends_on "node"
depends_on "openssl"
depends_on "opus"
def install
args = %W[
-DBUIld_WERROR=ON
-DCMAKE_INSTALL_PREFIX=#{prefix}
-DOPENSSL_ROOT_DIR=#{Formula["openssl"].opt_prefix}
-DSUNSHINE_ASSETS_DIR=sunshine/assets
-DSUNSHINE_BUILD_HOMEBREW=ON
]
system "cmake", "-S", ".", "-B", "build", *std_cmake_args, *args
cd "build" do
system "make", "-j"
system "make", "install"
end
end
service do
run [opt_bin/"sunshine", "~/.config/sunshine/sunshine.conf"]
end
def caveats
<<~EOS
Thanks for installing @PROJECT_NAME@!
To get started, review the documentation at:
https://docs.lizardbyte.dev/projects/sunshine/en/latest/
Sunshine can only access microphones on macOS due to system limitations.
To stream system audio use "Soundflower" or "BlackHole".
Gamepads are not currently supported on macOS.
EOS
end
test do
# test that the binary runs at all
output = shell_output("#{bin}/sunshine --version").strip
puts output
# TODO: add unit tests
end
end

View File

@@ -849,6 +849,11 @@ namespace config {
std::vector<std::string> list;
list_string_f(vars, name, list);
// check if list is empty, i.e. when the value doesn't exist in the config file
if (list.empty()) {
return;
}
// The framerate list must be cleared before adding values from the file configuration.
// If the list is not cleared, then the specified parameters do not affect the behavior of the sunshine server.
// That is, if you set only 30 fps in the configuration file, it will not work because by default, during initialization the list includes 10, 30, 60, 90 and 120 fps.

View File

@@ -106,8 +106,11 @@ main(int argc, char *argv[]) {
setlocale(LC_ALL, ".UTF-8");
#endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// Use UTF-8 conversion for the default C++ locale (used by boost::log)
std::locale::global(std::locale(std::locale(), new std::codecvt_utf8<wchar_t>));
#pragma GCC diagnostic pop
mail::man = std::make_shared<safe::mail_raw_t>();

View File

@@ -247,29 +247,38 @@ namespace cuda {
// There's no way to directly go from CUDA to a DRM device, so we'll
// use sysfs to look up the DRM device name from the PCI ID.
char pci_bus_id[13];
CU_CHECK(cdf->cuDeviceGetPCIBusId(pci_bus_id, sizeof(pci_bus_id), device), "Couldn't get CUDA device PCI bus ID");
BOOST_LOG(debug) << "Found CUDA device with PCI bus ID: "sv << pci_bus_id;
std::array<char, 13> pci_bus_id;
CU_CHECK(cdf->cuDeviceGetPCIBusId(pci_bus_id.data(), pci_bus_id.size(), device), "Couldn't get CUDA device PCI bus ID");
BOOST_LOG(debug) << "Found CUDA device with PCI bus ID: "sv << pci_bus_id.data();
// Linux uses lowercase hexadecimal while CUDA uses uppercase
std::transform(pci_bus_id.begin(), pci_bus_id.end(), pci_bus_id.begin(),
[](char c) { return std::tolower(c); });
// Look for the name of the primary node in sysfs
char sysfs_path[PATH_MAX];
std::snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/pci/devices/%s/drm", pci_bus_id);
fs::path sysfs_dir { sysfs_path };
for (auto &entry : fs::directory_iterator { sysfs_dir }) {
auto file = entry.path().filename();
auto filestring = file.generic_u8string();
if (std::string_view { filestring }.substr(0, 4) != "card"sv) {
continue;
try {
char sysfs_path[PATH_MAX];
std::snprintf(sysfs_path, sizeof(sysfs_path), "/sys/bus/pci/devices/%s/drm", pci_bus_id.data());
fs::path sysfs_dir { sysfs_path };
for (auto &entry : fs::directory_iterator { sysfs_dir }) {
auto file = entry.path().filename();
auto filestring = file.generic_u8string();
if (std::string_view { filestring }.substr(0, 4) != "card"sv) {
continue;
}
BOOST_LOG(debug) << "Found DRM primary node: "sv << filestring;
fs::path dri_path { "/dev/dri"sv };
auto device_path = dri_path / file;
return open(device_path.c_str(), O_RDWR);
}
BOOST_LOG(debug) << "Found DRM primary node: "sv << filestring;
fs::path dri_path { "/dev/dri"sv };
auto device_path = dri_path / file;
return open(device_path.c_str(), O_RDWR);
}
catch (const std::filesystem::filesystem_error &err) {
BOOST_LOG(error) << "Failed to read sysfs: "sv << err.what();
}
BOOST_LOG(error) << "Unable to find DRM device with PCI bus ID: "sv << pci_bus_id;
BOOST_LOG(error) << "Unable to find DRM device with PCI bus ID: "sv << pci_bus_id.data();
return -1;
}

View File

@@ -15,6 +15,7 @@
#include <filesystem>
#include <thread>
#include "src/config.h"
#include "src/logging.h"
#include "src/platform/common.h"
#include "src/round_robin.h"
@@ -108,6 +109,7 @@ namespace platf {
using obj_prop_t = util::safe_ptr<drmModeObjectProperties, drmModeFreeObjectProperties>;
using prop_t = util::safe_ptr<drmModePropertyRes, drmModeFreeProperty>;
using prop_blob_t = util::safe_ptr<drmModePropertyBlobRes, drmModeFreePropertyBlob>;
using version_t = util::safe_ptr<drmVersion, drmFreeVersion>;
using conn_type_count_t = std::map<std::uint32_t, std::uint32_t>;
@@ -297,6 +299,9 @@ namespace platf {
return -1;
}
version_t ver { drmGetVersion(fd.el) };
BOOST_LOG(info) << path << " -> "sv << ((ver && ver->name) ? ver->name : "UNKNOWN");
// Open the render node for this card to share with libva.
// If it fails, we'll just share the primary node instead.
char *rendernode_path = drmGetRenderDeviceNameFromFd(fd.el);
@@ -315,12 +320,21 @@ namespace platf {
}
if (drmSetClientCap(fd.el, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
BOOST_LOG(error) << "Couldn't expose some/all drm planes for card: "sv << path;
BOOST_LOG(error) << "GPU driver doesn't support universal planes: "sv << path;
return -1;
}
if (drmSetClientCap(fd.el, DRM_CLIENT_CAP_ATOMIC, 1)) {
BOOST_LOG(warning) << "Couldn't expose some properties for card: "sv << path;
BOOST_LOG(warning) << "GPU driver doesn't support atomic mode-setting: "sv << path;
#if defined(SUNSHINE_BUILD_X11)
// We won't be able to capture the mouse cursor with KMS on non-atomic drivers,
// so fall back to X11 if it's available and the user didn't explicitly force KMS.
if (window_system == window_system_e::X11 && config::video.capture != "kms") {
BOOST_LOG(info) << "Avoiding KMS capture under X11 due to lack of atomic mode-setting"sv;
return -1;
}
#endif
BOOST_LOG(warning) << "Cursor capture may fail without atomic mode-setting support!"sv;
}
plane_res.reset(drmModeGetPlaneResources(fd.el));
@@ -364,6 +378,12 @@ namespace platf {
return drmModeGetResources(fd.el);
}
bool
is_nvidia() {
version_t ver { drmGetVersion(fd.el) };
return ver && ver->name && strncmp(ver->name, "nvidia-drm", 10) == 0;
}
bool
is_cursor(std::uint32_t plane_id) {
auto props = plane_props(plane_id);
@@ -604,6 +624,15 @@ namespace platf {
continue;
}
// Skip non-Nvidia cards if we're looking for CUDA devices
// unless NVENC is selected manually by the user
if (mem_type == mem_type_e::cuda && !card.is_nvidia()) {
BOOST_LOG(debug) << file << " is not a CUDA device"sv;
if (config::video.encoder != "nvenc") {
continue;
}
}
auto end = std::end(card);
for (auto plane = std::begin(card); plane != end; ++plane) {
// Skip unused planes
@@ -627,8 +656,7 @@ namespace platf {
}
if (!fb->handles[0]) {
BOOST_LOG(error)
<< "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Possibly not permitted: do [sudo setcap cap_sys_admin+p sunshine]"sv;
BOOST_LOG(error) << "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Probably not permitted"sv;
return -1;
}
@@ -896,12 +924,14 @@ namespace platf {
if (!prop_crtc_w || !prop_crtc_h || !prop_crtc_x || !prop_crtc_y) {
BOOST_LOG(error) << "Cursor plane is missing required plane CRTC properties!"sv;
BOOST_LOG(error) << "Atomic mode-setting must be enabled to capture the cursor!"sv;
cursor_plane_id = -1;
captured_cursor.visible = false;
return;
}
if (!prop_src_x || !prop_src_y || !prop_src_w || !prop_src_h) {
BOOST_LOG(error) << "Cursor plane is missing required plane SRC properties!"sv;
BOOST_LOG(error) << "Atomic mode-setting must be enabled to capture the cursor!"sv;
cursor_plane_id = -1;
captured_cursor.visible = false;
return;
@@ -1059,8 +1089,7 @@ namespace platf {
}
if (!fb->handles[0]) {
BOOST_LOG(error)
<< "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Possibly not permitted: do [sudo setcap cap_sys_admin+p sunshine]"sv;
BOOST_LOG(error) << "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Probably not permitted"sv;
return capture_e::error;
}
@@ -1240,8 +1269,13 @@ namespace platf {
auto delta_width = std::min<uint32_t>(captured_cursor.src_w, std::max<int32_t>(0, screen_width - cursor_x)) - cursor_delta_x;
for (auto y = 0; y < delta_height; ++y) {
// Offset into the cursor image to skip drawing the parts of the cursor image that are off screen
auto cursor_begin = (uint32_t *) &captured_cursor.pixels[((y + cursor_delta_y) * captured_cursor.src_w + cursor_delta_x) * 4];
auto cursor_end = (uint32_t *) &captured_cursor.pixels[((y + cursor_delta_y) * captured_cursor.src_w + delta_width + cursor_delta_x) * 4];
//
// NB: We must access the elements via the data() function because cursor_end may point to the
// the first element beyond the valid range of the vector. Using vector's [] operator in that
// manner is undefined behavior (and triggers errors when using debug libc++), while doing the
// same with an array is fine.
auto cursor_begin = (uint32_t *) &captured_cursor.pixels.data()[((y + cursor_delta_y) * captured_cursor.src_w + cursor_delta_x) * 4];
auto cursor_end = (uint32_t *) &captured_cursor.pixels.data()[((y + cursor_delta_y) * captured_cursor.src_w + delta_width + cursor_delta_x) * 4];
auto pixels_begin = &pixels[(y + cursor_y) * (img.row_pitch / img.pixel_pitch) + cursor_x];
@@ -1571,7 +1605,7 @@ namespace platf {
// A list of names of displays accepted as display_name
std::vector<std::string>
kms_display_names() {
kms_display_names(mem_type_e hwdevice_type) {
int count = 0;
if (!fs::exists("/dev/dri")) {
@@ -1603,6 +1637,18 @@ namespace platf {
continue;
}
// Skip non-Nvidia cards if we're looking for CUDA devices
// unless NVENC is selected manually by the user
if (hwdevice_type == mem_type_e::cuda && !card.is_nvidia()) {
BOOST_LOG(debug) << file << " is not a CUDA device"sv;
if (config::video.encoder == "nvenc") {
BOOST_LOG(warning) << "Using NVENC with your display connected to a different GPU may not work properly!"sv;
}
else {
continue;
}
}
auto crtc_to_monitor = kms::map_crtc_to_monitor(card.monitors(conn_type_count));
auto end = std::end(card);
@@ -1623,8 +1669,9 @@ namespace platf {
}
if (!fb->handles[0]) {
BOOST_LOG(error)
<< "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Possibly not permitted: do [sudo setcap cap_sys_admin+p sunshine]"sv;
BOOST_LOG(error) << "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Probably not permitted"sv;
BOOST_LOG((window_system != window_system_e::X11 || config::video.capture == "kms") ? fatal : error)
<< "You must run [sudo setcap cap_sys_admin+p $(readlink -f sunshine)] for KMS display capture to work!"sv;
break;
}

View File

@@ -100,22 +100,54 @@ namespace platf {
fs::path
appdata() {
bool found = false;
bool migrate_config = true;
const char *dir;
const char *homedir;
fs::path config_path;
// Get the home directory
if ((homedir = getenv("HOME")) == nullptr || strlen(homedir) == 0) {
// If HOME is empty or not set, use the current user's home directory
homedir = getpwuid(geteuid())->pw_dir;
}
// May be set if running under a systemd service with the ConfigurationDirectory= option set.
if ((dir = getenv("CONFIGURATION_DIRECTORY")) != nullptr) {
return fs::path { dir } / "sunshine"sv;
if ((dir = getenv("CONFIGURATION_DIRECTORY")) != nullptr && strlen(dir) > 0) {
found = true;
config_path = fs::path(dir) / "sunshine"sv;
}
// Otherwise, follow the XDG base directory specification:
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
if ((dir = getenv("XDG_CONFIG_HOME")) != nullptr) {
return fs::path { dir } / "sunshine"sv;
if (!found && (dir = getenv("XDG_CONFIG_HOME")) != nullptr && strlen(dir) > 0) {
found = true;
config_path = fs::path(dir) / "sunshine"sv;
}
if ((dir = getenv("HOME")) == nullptr) {
dir = getpwuid(geteuid())->pw_dir;
// As a last resort, use the home directory
if (!found) {
migrate_config = false;
config_path = fs::path(homedir) / ".config/sunshine"sv;
}
return fs::path { dir } / ".config/sunshine"sv;
// migrate from the old config location if necessary
if (migrate_config && found && getenv("SUNSHINE_MIGRATE_CONFIG") == "1"sv) {
fs::path old_config_path = fs::path(homedir) / ".config/sunshine"sv;
if (old_config_path != config_path && fs::exists(old_config_path)) {
if (!fs::exists(config_path)) {
BOOST_LOG(info) << "Migrating config from "sv << old_config_path << " to "sv << config_path;
std::error_code ec;
fs::rename(old_config_path, config_path, ec);
if (ec) {
return old_config_path;
}
}
else {
BOOST_LOG(warning) << "Config exists in both "sv << old_config_path << " and "sv << config_path << ", using "sv << config_path << "... it is recommended to remove "sv << old_config_path;
}
}
}
return config_path;
}
std::string
@@ -734,13 +766,13 @@ namespace platf {
#ifdef SUNSHINE_BUILD_DRM
std::vector<std::string>
kms_display_names();
kms_display_names(mem_type_e hwdevice_type);
std::shared_ptr<display_t>
kms_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);
bool
verify_kms() {
return !kms_display_names().empty();
return !kms_display_names(mem_type_e::unknown).empty();
}
#endif
@@ -766,7 +798,7 @@ namespace platf {
if (sources[source::WAYLAND]) return wl_display_names();
#endif
#ifdef SUNSHINE_BUILD_DRM
if (sources[source::KMS]) return kms_display_names();
if (sources[source::KMS]) return kms_display_names(hwdevice_type);
#endif
#ifdef SUNSHINE_BUILD_X11
if (sources[source::X11]) return x11_display_names();

View File

@@ -234,7 +234,7 @@ namespace platf::dxgi {
auto xor_mask = std::begin(img_data) + bytes;
for (auto x = 0; x < bytes; ++x) {
for (auto c = 7; c >= 0; --c) {
for (auto c = 7; c >= 0 && ((std::uint8_t *) pixel_data) != std::end(cursor_img); --c) {
auto bit = 1 << c;
auto color_type = ((*and_mask & bit) ? 1 : 0) + ((*xor_mask & bit) ? 2 : 0);
@@ -307,7 +307,7 @@ namespace platf::dxgi {
auto xor_mask = std::begin(img_data) + bytes;
for (auto x = 0; x < bytes; ++x) {
for (auto c = 7; c >= 0; --c) {
for (auto c = 7; c >= 0 && ((std::uint8_t *) pixel_data) != std::end(cursor_img); --c) {
auto bit = 1 << c;
auto color_type = ((*and_mask & bit) ? 1 : 0) + ((*xor_mask & bit) ? 2 : 0);

View File

@@ -681,10 +681,11 @@ namespace platf {
* @param raw_cmd The raw command provided by the user.
* @param working_dir The working directory for the new process.
* @param token The user token currently being impersonated or `NULL` if running as ourselves.
* @param creation_flags The creation flags for CreateProcess(), which may be modified by this function.
* @return A command string suitable for use by CreateProcess().
*/
std::wstring
resolve_command_string(const std::string &raw_cmd, const std::wstring &working_dir, HANDLE token) {
resolve_command_string(const std::string &raw_cmd, const std::wstring &working_dir, HANDLE token, DWORD &creation_flags) {
std::wstring raw_cmd_w = from_utf8(raw_cmd);
// First, convert the given command into parts so we can get the executable/file/URL without parameters
@@ -757,8 +758,13 @@ namespace platf {
// FIXME: Maybe we can improve this in the future.
if (res == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION)) {
BOOST_LOG(warning) << "Using trampoline to handle target: "sv << raw_cmd;
std::wcscpy(shell_command_string.data(), L"cmd.exe /c start \"\" \"%1\" %*");
std::wcscpy(shell_command_string.data(), L"cmd.exe /c start \"\" /wait \"%1\" %*");
needs_cmd_escaping = true;
// We must suppress the console window that would otherwise appear when starting cmd.exe.
creation_flags &= ~CREATE_NEW_CONSOLE;
creation_flags |= CREATE_NO_WINDOW;
res = S_OK;
}
@@ -927,6 +933,31 @@ namespace platf {
// Create a new console for interactive processes and use no console for non-interactive processes
creation_flags |= interactive ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW;
// Find the PATH variable in our environment block using a case-insensitive search
auto sunshine_wenv = boost::this_process::wenvironment();
std::wstring path_var_name { L"PATH" };
std::wstring old_path_val;
auto itr = std::find_if(sunshine_wenv.cbegin(), sunshine_wenv.cend(), [&](const auto &e) { return boost::iequals(e.get_name(), path_var_name); });
if (itr != sunshine_wenv.cend()) {
// Use the existing variable if it exists, since Boost treats these as case-sensitive.
path_var_name = itr->get_name();
old_path_val = sunshine_wenv[path_var_name].to_string();
}
// Temporarily prepend the specified working directory to PATH to ensure CreateProcess()
// will (preferentially) find binaries that reside in the working directory.
sunshine_wenv[path_var_name].assign(start_dir + L";" + old_path_val);
// Restore the old PATH value for our process when we're done here
auto restore_path = util::fail_guard([&]() {
if (old_path_val.empty()) {
sunshine_wenv[path_var_name].clear();
}
else {
sunshine_wenv[path_var_name].assign(old_path_val);
}
});
BOOL ret;
if (is_running_as_system()) {
// Duplicate the current user's token
@@ -951,7 +982,7 @@ namespace platf {
// Open the process as the current user account, elevation is handled in the token itself.
ec = impersonate_current_user(user_token, [&]() {
std::wstring env_block = create_environment_block(cloned_env);
std::wstring wcmd = resolve_command_string(cmd, start_dir, user_token);
std::wstring wcmd = resolve_command_string(cmd, start_dir, user_token, creation_flags);
ret = CreateProcessAsUserW(user_token,
NULL,
(LPWSTR) wcmd.c_str(),
@@ -985,7 +1016,7 @@ namespace platf {
}
std::wstring env_block = create_environment_block(cloned_env);
std::wstring wcmd = resolve_command_string(cmd, start_dir, NULL);
std::wstring wcmd = resolve_command_string(cmd, start_dir, NULL, creation_flags);
ret = CreateProcessW(NULL,
(LPWSTR) wcmd.c_str(),
NULL,

View File

@@ -664,6 +664,12 @@ namespace proc {
if (working_dir) {
ctx.working_dir = parse_env_val(this_env, *working_dir);
#ifdef _WIN32
// The working directory, unlike the command itself, should not be quoted
// when it contains spaces. Unlike POSIX, Windows forbids quotes in paths,
// so we can safely strip them all out here to avoid confusing the user.
boost::erase_all(ctx.working_dir, "\"");
#endif
}
if (image_path) {

View File

@@ -47,6 +47,8 @@ using namespace std::literals;
// system_tray namespace
namespace system_tray {
static std::atomic<bool> tray_initialized = false;
/**
* @brief Callback for opening the UI from the system tray.
* @param item The tray menu item.
@@ -145,6 +147,8 @@ namespace system_tray {
{ .text = "Restart", .cb = tray_restart_cb },
{ .text = "Quit", .cb = tray_quit_cb },
{ .text = nullptr } },
.iconPathCount = 4,
.allIconPaths = { TRAY_ICON, TRAY_ICON_LOCKED, TRAY_ICON_PLAYING, TRAY_ICON_PAUSING },
};
/**
@@ -237,6 +241,7 @@ namespace system_tray {
BOOST_LOG(info) << "System tray created"sv;
}
tray_initialized = true;
while (tray_loop(1) == 0) {
BOOST_LOG(debug) << "System tray loop"sv;
}
@@ -273,6 +278,7 @@ namespace system_tray {
*/
int
end_tray() {
tray_initialized = false;
tray_exit();
return 0;
}
@@ -283,6 +289,10 @@ namespace system_tray {
*/
void
update_tray_playing(std::string app_name) {
if (!tray_initialized) {
return;
}
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;
@@ -305,6 +315,10 @@ namespace system_tray {
*/
void
update_tray_pausing(std::string app_name) {
if (!tray_initialized) {
return;
}
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;
@@ -327,6 +341,10 @@ namespace system_tray {
*/
void
update_tray_stopped(std::string app_name) {
if (!tray_initialized) {
return;
}
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;
@@ -348,6 +366,10 @@ namespace system_tray {
*/
void
update_tray_require_pin() {
if (!tray_initialized) {
return;
}
tray.notification_title = NULL;
tray.notification_text = NULL;
tray.notification_cb = NULL;

View File

@@ -1234,7 +1234,7 @@
"install_steam_audio_drivers": "enabled",
"adapter_name": "",
"output_name": "",
"resolutions": "[352x240,480x360,858x480,1280x720,1920x1080,2560x1080,3440x1440,1920x1200,3840x2160,3840x1600]",
"resolutions": "[352x240,480x360,858x480,1280x720,1920x1080,2560x1080,2560x1440,3440x1440,1920x1200,3840x2160,3840x1600]",
"fps": "[10,30,60,90,120]",
},
},

View File

@@ -6,3 +6,10 @@ if [ -x "$path_to_setcap" ] ; then
echo "$path_to_setcap cap_sys_admin+p /usr/bin/sunshine"
$path_to_setcap cap_sys_admin+p $(readlink -f /usr/bin/sunshine)
fi
# Trigger udev rule reload for /dev/uinput
path_to_udevadm=$(which udevadm)
if [ -x "$path_to_udevadm" ] ; then
$path_to_udevadm control --reload-rules
$path_to_udevadm trigger --property-match=DEVNAME=/dev/uinput
fi

View File

@@ -1,4 +1,7 @@
#!/bin/bash -e
# note: this file was used to remove files when using the pkg/dmg, it is no longer used, but left for reference
set -e
package_name=org.macports.Sunshine

View File

@@ -2,28 +2,17 @@
setlocal enabledelayedexpansion
rem Check if a compatible version of ViGEmBus is already installed (1.17 or later)
set Version=
for /f "usebackq delims=" %%a in (`wmic product where "name='ViGEm Bus Driver' or name='Nefarius Virtual Gamepad Emulation Bus Driver'" get Version /format:Textvaluelist`) do (
for /f "delims=" %%# in ("%%a") do set "%%#"
)
rem Extract Major and Minor versions
for /f "tokens=1,2 delims=." %%a in ("%Version%") do (
set "MajorVersion=%%a"
set "MinorVersion=%%b"
)
rem Compare the version to 1.17
if /i !MajorVersion! gtr 1 goto skip
if /i !MajorVersion! equ 1 (
if /i !MinorVersion! geq 17 (
goto skip
)
rem
rem Note: We use exit code 2 to indicate success because either 0 or 1 may be returned
rem based on the PowerShell version if an exception occurs.
powershell -c Exit $(if ((Get-Item "$env:SystemRoot\System32\drivers\ViGEmBus.sys").VersionInfo.FileVersion -ge [System.Version]"1.17") { 2 } Else { 1 })
if %ERRORLEVEL% EQU 2 (
goto skip
)
goto continue
:skip
echo "The installed version is %Version%, no update needed. Exiting."
echo "The installed version is 1.17 or later, no update needed. Exiting."
exit /b 0
:continue

View File

@@ -16,13 +16,18 @@ import process from 'process'
let assetsSrcPath = 'src_assets/common/assets/web';
let assetsDstPath = 'build/assets/web';
if (process.env.SUNSHINE_SOURCE_ASSETS_DIR) {
console.log("Using srcdir from Cmake: " + resolve(process.env.SUNSHINE_SOURCE_ASSETS_DIR,"common/assets/web"));
assetsSrcPath = resolve(process.env.SUNSHINE_SOURCE_ASSETS_DIR,"common/assets/web")
if (process.env.SUNSHINE_BUILD_HOMEBREW) {
console.log("Building for homebrew, using default paths")
}
if (process.env.SUNSHINE_ASSETS_DIR) {
console.log("Using destdir from Cmake: " + resolve(process.env.SUNSHINE_ASSETS_DIR,"assets/web"));
assetsDstPath = resolve(process.env.SUNSHINE_ASSETS_DIR,"assets/web")
else {
if (process.env.SUNSHINE_SOURCE_ASSETS_DIR) {
console.log("Using srcdir from Cmake: " + resolve(process.env.SUNSHINE_SOURCE_ASSETS_DIR,"common/assets/web"));
assetsSrcPath = resolve(process.env.SUNSHINE_SOURCE_ASSETS_DIR,"common/assets/web")
}
if (process.env.SUNSHINE_ASSETS_DIR) {
console.log("Using destdir from Cmake: " + resolve(process.env.SUNSHINE_ASSETS_DIR,"assets/web"));
assetsDstPath = resolve(process.env.SUNSHINE_ASSETS_DIR,"assets/web")
}
}
let header = fs.readFileSync(resolve(assetsSrcPath, "template_header.html"))