diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..1ccee08a107 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# ensure dockerfiles are checked out with LF line endings +Dockerfile text eol=lf +*.dockerfile text eol=lf diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 60f555c2166..80c309ca052 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -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 - - # 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 + brew install cmake - # 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 + - name: Configure formula + run: | + # variables for formula + branch=${GITHUB_HEAD_REF} - # 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 + # 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}" - - name: Install Boost - # installing boost from homebrew takes 30 minutes in a GitHub runner - run: | - export BOOST_ROOT=${HOME}/boost-${BOOST_VERSION} - - # 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} - - # 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) - - - name: Package MacOS - run: | - mkdir -p artifacts - cd build + cd .. - # package - cpack -G DragNDrop - mv ./cpack_artifacts/Sunshine.dmg ../artifacts/sunshine.dmg + # copy formula to artifacts + mkdir -p homebrew + cp -f ./build/sunshine.rb ./homebrew/sunshine.rb - # 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f8290545da..d1c67c68c3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index d672c9b8ae8..fce20cd2bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") diff --git a/README.rst b/README.rst index fbc78658668..11508d976e3 100644 --- a/README.rst +++ b/README.rst @@ -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) | +------------+------------------------------------------------------------+ diff --git a/cmake/packaging/linux.cmake b/cmake/packaging/linux.cmake index 8563414a40e..499f058c8bd 100644 --- a/cmake/packaging/linux.cmake +++ b/cmake/packaging/linux.cmake @@ -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}") diff --git a/cmake/packaging/unix.cmake b/cmake/packaging/unix.cmake index d6a4ae93575..bacbfc910de 100644 --- a/cmake/packaging/unix.cmake +++ b/cmake/packaging/unix.cmake @@ -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() diff --git a/cmake/prep/options.cmake b/cmake/prep/options.cmake index 9104320d31d..9a7fca8e5e5 100644 --- a/cmake/prep/options.cmake +++ b/cmake/prep/options.cmake @@ -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 diff --git a/cmake/prep/special_package_configuration.cmake b/cmake/prep/special_package_configuration.cmake index 3094c2399a5..d04066cdc8a 100644 --- a/cmake/prep/special_package_configuration.cmake +++ b/cmake/prep/special_package_configuration.cmake @@ -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 diff --git a/cmake/targets/common.cmake b/cmake/targets/common.cmake index 3dd629e0cab..9f2ce08240e 100644 --- a/cmake/targets/common.cmake +++ b/cmake/targets/common.cmake @@ -37,8 +37,19 @@ endif() target_compile_options(sunshine PRIVATE $<$:${SUNSHINE_COMPILE_OPTIONS}>;$<$:${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 diff --git a/docker/archlinux.dockerfile b/docker/archlinux.dockerfile index 15cb5d23685..e8cfd93998e 100644 --- a/docker/archlinux.dockerfile +++ b/docker/archlinux.dockerfile @@ -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 diff --git a/docker/fedora-38.dockerfile b/docker/fedora-38.dockerfile index 9ba496c5b97..55622ab7070 100644 --- a/docker/fedora-38.dockerfile +++ b/docker/fedora-38.dockerfile @@ -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 diff --git a/docker/fedora-39.dockerfile b/docker/fedora-39.dockerfile index e942a8aa916..20dae39a797 100644 --- a/docker/fedora-39.dockerfile +++ b/docker/fedora-39.dockerfile @@ -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 diff --git a/docs/source/about/guides/app_examples.rst b/docs/source/about/guides/app_examples.rst index ca834e4a4f2..8bca2bd89f0 100644 --- a/docs/source/about/guides/app_examples.rst +++ b/docs/source/about/guides/app_examples.rst @@ -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) diff --git a/docs/source/about/setup.rst b/docs/source/about/setup.rst index 8a280fcf644..2a2b015ce9c 100644 --- a/docs/source/about/setup.rst +++ b/docs/source/about/setup.rst @@ -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 `__ + #. 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 diff --git a/docs/source/building/macos.rst b/docs/source/building/macos.rst index c14751c28f8..bf96fb394f9 100644 --- a/docs/source/building/macos.rst +++ b/docs/source/building/macos.rst @@ -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 ----- diff --git a/packaging/linux/AppImage/AppRun b/packaging/linux/AppImage/AppRun index ddc5fd38455..404704c34d3 100644 --- a/packaging/linux/AppImage/AppRun +++ b/packaging/linux/AppImage/AppRun @@ -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 diff --git a/packaging/linux/Arch/PKGBUILD b/packaging/linux/Arch/PKGBUILD index 4422698263e..44a6beb2b2f 100644 --- a/packaging/linux/Arch/PKGBUILD +++ b/packaging/linux/Arch/PKGBUILD @@ -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') diff --git a/packaging/linux/Arch/sunshine.install b/packaging/linux/Arch/sunshine.install new file mode 100644 index 00000000000..a8a700f1f1c --- /dev/null +++ b/packaging/linux/Arch/sunshine.install @@ -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 +} + diff --git a/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml b/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml index a4176d4ea15..1da03310f7a 100644 --- a/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml +++ b/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml @@ -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 diff --git a/packaging/linux/flatpak/scripts/additional-install.sh b/packaging/linux/flatpak/scripts/additional-install.sh index 8a905b53810..a27db4e09ba 100644 --- a/packaging/linux/flatpak/scripts/additional-install.sh +++ b/packaging/linux/flatpak/scripts/additional-install.sh @@ -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. diff --git a/packaging/linux/flatpak/scripts/remove-additional-install.sh b/packaging/linux/flatpak/scripts/remove-additional-install.sh index 6148f62ea1e..0d13baeb62c 100644 --- a/packaging/linux/flatpak/scripts/remove-additional-install.sh +++ b/packaging/linux/flatpak/scripts/remove-additional-install.sh @@ -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. diff --git a/packaging/linux/flatpak/sunshine.desktop b/packaging/linux/flatpak/sunshine.desktop index be702701e08..1c5fe13a409 100644 --- a/packaging/linux/flatpak/sunshine.desktop +++ b/packaging/linux/flatpak/sunshine.desktop @@ -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 diff --git a/packaging/linux/sunshine.desktop b/packaging/linux/sunshine.desktop index b0f2ce327ec..719555301d5 100644 --- a/packaging/linux/sunshine.desktop +++ b/packaging/linux/sunshine.desktop @@ -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 diff --git a/packaging/macos/sunshine.rb b/packaging/macos/sunshine.rb new file mode 100644 index 00000000000..e312c99d4d6 --- /dev/null +++ b/packaging/macos/sunshine.rb @@ -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 diff --git a/src/config.cpp b/src/config.cpp index ba2718aca7f..21562f83487 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -849,6 +849,11 @@ namespace config { std::vector 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. diff --git a/src/main.cpp b/src/main.cpp index 5cc28f9f2a2..a3901448680 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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)); +#pragma GCC diagnostic pop mail::man = std::make_shared(); diff --git a/src/platform/linux/cuda.cpp b/src/platform/linux/cuda.cpp index 5b121c70691..33c939243f2 100644 --- a/src/platform/linux/cuda.cpp +++ b/src/platform/linux/cuda.cpp @@ -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 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; + 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); + 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; } diff --git a/src/platform/linux/kmsgrab.cpp b/src/platform/linux/kmsgrab.cpp index cd622fa775c..d4feb3557d8 100644 --- a/src/platform/linux/kmsgrab.cpp +++ b/src/platform/linux/kmsgrab.cpp @@ -15,6 +15,7 @@ #include #include +#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; using prop_t = util::safe_ptr; using prop_blob_t = util::safe_ptr; + using version_t = util::safe_ptr; using conn_type_count_t = std::map; @@ -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(captured_cursor.src_w, std::max(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 - 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; } diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index 0075d4502f8..884c0e9047a 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -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 ((dir = getenv("HOME")) == nullptr) { - dir = getpwuid(geteuid())->pw_dir; + if (!found && (dir = getenv("XDG_CONFIG_HOME")) != nullptr && strlen(dir) > 0) { + found = true; + config_path = fs::path(dir) / "sunshine"sv; + } + // As a last resort, use the home directory + if (!found) { + migrate_config = false; + config_path = fs::path(homedir) / ".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 fs::path { dir } / ".config/sunshine"sv; + return config_path; } std::string @@ -734,13 +766,13 @@ namespace platf { #ifdef SUNSHINE_BUILD_DRM std::vector - kms_display_names(); + kms_display_names(mem_type_e hwdevice_type); std::shared_ptr 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(); diff --git a/src/platform/windows/display_vram.cpp b/src/platform/windows/display_vram.cpp index a56869eab40..1baa1282bb9 100644 --- a/src/platform/windows/display_vram.cpp +++ b/src/platform/windows/display_vram.cpp @@ -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); diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 77de69f4cd3..e7bb64e52b8 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -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, diff --git a/src/process.cpp b/src/process.cpp index 804291577c2..89dc4dc5ae5 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -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) { diff --git a/src/system_tray.cpp b/src/system_tray.cpp index 39131ba30fe..c34c3d75a98 100644 --- a/src/system_tray.cpp +++ b/src/system_tray.cpp @@ -47,6 +47,8 @@ using namespace std::literals; // system_tray namespace namespace system_tray { + static std::atomic 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; diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index a072e101ba0..e7d47e4d852 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -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]", }, }, diff --git a/src_assets/linux/misc/85-sunshine.rules b/src_assets/linux/misc/60-sunshine.rules similarity index 100% rename from src_assets/linux/misc/85-sunshine.rules rename to src_assets/linux/misc/60-sunshine.rules diff --git a/src_assets/linux/misc/postinst b/src_assets/linux/misc/postinst index 63f0523d867..aab899f94ec 100644 --- a/src_assets/linux/misc/postinst +++ b/src_assets/linux/misc/postinst @@ -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 diff --git a/src_assets/macos/misc/uninstall_pkg.sh b/src_assets/macos/misc/uninstall_pkg.sh index 869f33d2fe6..89e7bbfb278 100644 --- a/src_assets/macos/misc/uninstall_pkg.sh +++ b/src_assets/macos/misc/uninstall_pkg.sh @@ -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 diff --git a/src_assets/windows/misc/gamepad/install-gamepad.bat b/src_assets/windows/misc/gamepad/install-gamepad.bat index cf164cb5109..a31babb93f6 100644 --- a/src_assets/windows/misc/gamepad/install-gamepad.bat +++ b/src_assets/windows/misc/gamepad/install-gamepad.bat @@ -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 diff --git a/third-party/tray b/third-party/tray index 2bf1c610300..a08c1025c3f 160000 --- a/third-party/tray +++ b/third-party/tray @@ -1 +1 @@ -Subproject commit 2bf1c610300b27f8d8ce87e2f13223fc83efeb42 +Subproject commit a08c1025c3f158d6b6c4b9bcf0ab770291d26896 diff --git a/vite.config.js b/vite.config.js index a41470e4bf5..8732f1a08c7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -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"))