Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ jobs:
arch: x86_64
msystem: ucrt64
toolchain: ucrt-x86_64
- name: Windows-ARM64
os: windows-11-arm
arch: aarch64
msystem: clangarm64
toolchain: clang-aarch64
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -169,17 +174,22 @@ jobs:
"mingw-w64-${TOOLCHAIN}-curl-winssl"
"mingw-w64-${TOOLCHAIN}-gcc"
"mingw-w64-${TOOLCHAIN}-graphviz"
"mingw-w64-${TOOLCHAIN}-MinHook"
"mingw-w64-${TOOLCHAIN}-miniupnpc"
"mingw-w64-${TOOLCHAIN}-nlohmann-json"
"mingw-w64-${TOOLCHAIN}-nodejs"
"mingw-w64-${TOOLCHAIN}-nsis"
"mingw-w64-${TOOLCHAIN}-onevpl"
"mingw-w64-${TOOLCHAIN}-openssl"
"mingw-w64-${TOOLCHAIN}-opus"
"mingw-w64-${TOOLCHAIN}-toolchain"
)

if [[ ${MSYSTEM} == "ucrt64" ]]; then
dependencies+=(
"mingw-w64-${TOOLCHAIN}-MinHook"
"mingw-w64-${TOOLCHAIN}-nsis" # TODO: how to create an arm64 installer?
)
fi

# do not modify below this line

ignore_packages=()
Expand Down Expand Up @@ -266,26 +276,36 @@ jobs:
-B build \
-G Ninja \
-S . \
-DBUILD_WERROR=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DSUNSHINE_ASSETS_DIR=assets \
-DSUNSHINE_PUBLISHER_NAME='${{ github.repository_owner }}' \
-DSUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' \
-DSUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support'
ninja -C build

- name: Package Windows
- name: Package Windows Installer
if: runner.arch == 'X86' || runner.arch == 'X64'
shell: msys2 {0}
run: |
mkdir -p artifacts
cd build

# package
cpack -G NSIS
cpack -G ZIP

# move
mv ./cpack_artifacts/Sunshine.exe ../artifacts/Sunshine-${{ matrix.name }}-installer.exe

- name: Package Windows Portable
shell: msys2 {0}
run: |
mkdir -p artifacts
cd build

# package
cpack -G ZIP

# move
mv ./cpack_artifacts/Sunshine.zip ../artifacts/Sunshine-${{ matrix.name }}-portable.zip

- name: Run tests
Expand All @@ -298,7 +318,7 @@ jobs:
- name: Generate gcov report
id: test_report
# any except canceled or skipped
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure') && runner.arch == 'X86' || runner.arch == 'X64'
shell: msys2 {0}
working-directory: build
run: |
Expand Down
7 changes: 6 additions & 1 deletion cmake/compile_definitions/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ list(PREPEND PLATFORM_LIBRARIES
libssp.a
libstdc++.a
libwinpthread.a
minhook::minhook
ntdll
setupapi
shlwapi
Expand All @@ -92,6 +91,12 @@ list(PREPEND PLATFORM_LIBRARIES
wsock32
)

if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64")
list(APPEND PLATFORM_LIBRARIES
minhook::minhook
)
endif()

if(SUNSHINE_ENABLE_TRAY)
list(APPEND PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/third-party/tray/src/tray_windows.c")
Expand Down
15 changes: 13 additions & 2 deletions cmake/dependencies/Boost_Sunshine.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,19 @@ if(NOT Boost_FOUND)

# Limit boost to the required libraries only
set(BOOST_INCLUDE_LIBRARIES ${BOOST_COMPONENTS})
set(BOOST_URL "https://github.com/boostorg/boost/releases/download/boost-${BOOST_VERSION}/boost-${BOOST_VERSION}-cmake.tar.xz") # cmake-lint: disable=C0301
set(BOOST_HASH "SHA256=7da75f171837577a52bbf217e17f8ea576c7c246e4594d617bfde7fafd408be5")
# set(BOOST_URL "https://github.com/boostorg/boost/releases/download/boost-${BOOST_VERSION}/boost-${BOOST_VERSION}-cmake.tar.xz") # cmake-lint: disable=C0301
# set(BOOST_HASH "SHA256=7da75f171837577a52bbf217e17f8ea576c7c246e4594d617bfde7fafd408be5")

# Build Windows Arm64 must backport following:
#
# context: Support building assembly files for mingw-w64 on arm64 with CMake
# Link: https://github.com/boostorg/context/commit/f82483d343c6452c62ec89a48d22a3a7e565373d
#
# uuid: Do not link to libatomic under any Clang/Windows
# Link: https://github.com/boostorg/uuid/commit/434329f8dc7fcfb69cd7565ab0318d86772cea39
#
set(BOOST_URL "https://github.com/rbqvq/Sunshine/releases/download/boost-${BOOST_VERSION}/boost-${BOOST_VERSION}-cmake.tar.xz") # cmake-lint: disable=C0301
set(BOOST_HASH "SHA256=7238ae092c7e8aa97fe47321bee4cf6ef059c8001fbde30e3611a856543d605f")

if(CMAKE_VERSION VERSION_LESS "3.24.0")
FetchContent_Declare(
Expand Down
14 changes: 8 additions & 6 deletions cmake/dependencies/windows.cmake
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# windows specific dependencies

# Make sure MinHook is installed
find_library(MINHOOK_LIBRARY libMinHook.a REQUIRED)
find_path(MINHOOK_INCLUDE_DIR MinHook.h PATH_SUFFIXES include REQUIRED)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64")
# Make sure MinHook is installed
find_library(MINHOOK_LIBRARY libMinHook.a REQUIRED)
find_path(MINHOOK_INCLUDE_DIR MinHook.h PATH_SUFFIXES include REQUIRED)

add_library(minhook::minhook STATIC IMPORTED)
set_property(TARGET minhook::minhook PROPERTY IMPORTED_LOCATION ${MINHOOK_LIBRARY})
target_include_directories(minhook::minhook INTERFACE ${MINHOOK_INCLUDE_DIR})
add_library(minhook::minhook STATIC IMPORTED)
set_property(TARGET minhook::minhook PROPERTY IMPORTED_LOCATION ${MINHOOK_LIBRARY})
target_include_directories(minhook::minhook INTERFACE ${MINHOOK_INCLUDE_DIR})
endif()
6 changes: 6 additions & 0 deletions cmake/prep/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ set(SUNSHINE_PUBLISHER_ISSUE_URL "https://app.lizardbyte.dev/support"

option(BUILD_DOCS "Build documentation" ON)
option(BUILD_TESTS "Build tests" ON)

# CLANGARM64 does not have libatomic which used by googletest, disable it
if(MINGW AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
set(BUILD_TESTS ON CACHE BOOL "Build tests" FORCE)
endif()

option(NPM_OFFLINE "Use offline npm packages. You must ensure packages are in your npm cache." OFF)

option(BUILD_WERROR "Enable -Werror flag." OFF)
Expand Down
52 changes: 35 additions & 17 deletions docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,33 +72,51 @@ sudo port install "${dependencies[@]}"
```

#### Windows
First you need to install [MSYS2](https://www.msys2.org), then startup "MSYS2 UCRT64" and execute the following
commands.

@warning{Cross-compilation is not supported on Windows. You must build on the target architecture.}

First you need to install [MSYS2](https://www.msys2.org).

For AMD64 startup "MSYS2 UCRT64", or for ARM64 startup "MSYS2 CLANGARM64", then execute the following commands.

##### Update all packages
```bash
pacman -Syu
```

##### Set toolchain variable
For UCRT64:
```bash
export TOOLCHAIN="ucrt-x86_64"
```

For CLANGARM64:
```bash
export TOOLCHAIN="clang-aarch64"
```

##### Install dependencies
```bash
dependencies=(
"git"
"mingw-w64-ucrt-x86_64-boost" # Optional
"mingw-w64-ucrt-x86_64-cmake"
"mingw-w64-ucrt-x86_64-cppwinrt"
"mingw-w64-ucrt-x86_64-curl-winssl"
"mingw-w64-ucrt-x86_64-doxygen" # Optional, for docs... better to install official Doxygen
"mingw-w64-ucrt-x86_64-graphviz" # Optional, for docs
"mingw-w64-ucrt-x86_64-MinHook"
"mingw-w64-ucrt-x86_64-miniupnpc"
"mingw-w64-ucrt-x86_64-nodejs"
"mingw-w64-ucrt-x86_64-nsis"
"mingw-w64-ucrt-x86_64-onevpl"
"mingw-w64-ucrt-x86_64-openssl"
"mingw-w64-ucrt-x86_64-opus"
"mingw-w64-ucrt-x86_64-toolchain"
"mingw-w64-${TOOLCHAIN}-boost" # Optional
"mingw-w64-${TOOLCHAIN}-cmake"
"mingw-w64-${TOOLCHAIN}-cppwinrt"
"mingw-w64-${TOOLCHAIN}-curl-winssl"
"mingw-w64-${TOOLCHAIN}-graphviz" # Optional, for docs
"mingw-w64-${TOOLCHAIN}-miniupnpc"
"mingw-w64-${TOOLCHAIN}-nodejs"
"mingw-w64-${TOOLCHAIN}-onevpl"
"mingw-w64-${TOOLCHAIN}-openssl"
"mingw-w64-${TOOLCHAIN}-opus"
"mingw-w64-${TOOLCHAIN}-toolchain"
)
if [[ ${MSYSTEM} == "ucrt64" ]]; then
dependencies+=(
"mingw-w64-${TOOLCHAIN}-MinHook"
"mingw-w64-${TOOLCHAIN}-nsis" # TODO: how to create an arm64 installer?
)
fi
pacman -S "${dependencies[@]}"
```

Expand Down Expand Up @@ -139,7 +157,7 @@ ninja -C build
}}
@tab{Windows | @tabs{
@tab{Installer | ```bash
cpack -G NSIS --config ./build/CPackConfig.cmake
cpack -G NSIS --config ./build/CPackConfig.cmake # Not working on CLANGARM64
```}
@tab{Portable | ```bash
cpack -G ZIP --config ./build/CPackConfig.cmake
Expand Down
20 changes: 16 additions & 4 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,17 @@ brew uninstall sunshine

### Windows

Sunshine now supports ARM64 on Windows; however this should be considered experimental. This version does not properly
support GPU scheduling and any hardware acceleration.

#### Installer (recommended)

1. Download and install
[Sunshine-Windows-AMD64-installer.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-installer.exe)
1. Download and install based on your architecture:

| Architecture | Installer |
|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
| AMD64/x64 (Intel/AMD) | [Sunshine-Windows-AMD64-installer.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-installer.exe) |
| ARM64 | [Sunshine-Windows-ARM64-installer.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-ARM64-installer.exe) |

@attention{You should carefully select or unselect the options you want to install. Do not blindly install or
enable features.}
Expand All @@ -297,8 +304,13 @@ overflow menu. Different versions of Windows may provide slightly different step
@warning{By using this package instead of the installer, performance will be reduced. This package is not
recommended for most users. No support will be provided!}

1. Download and extract
[Sunshine-Windows-AMD64-portable.zip](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-portable.zip)
1. Download and extract based on your architecture:

| Architecture | Installer |
|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
| AMD64/x64 (Intel/AMD) | [Sunshine-Windows-AMD64-portable.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-portable.zip) |
| ARM64 | [Sunshine-Windows-ARM64-portable.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-ARM64-portable.zip) |

2. Open command prompt as administrator
3. Firewall rules

Expand Down
8 changes: 4 additions & 4 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ namespace config {
};

template<class T>
std::optional<int> quality_from_view(const std::string_view &quality_type, const std::optional<int>(&original)) {
::std::optional<int> quality_from_view(const ::std::string_view &quality_type, const ::std::optional<int>(&original)) {
#define _CONVERT_(x) \
if (quality_type == #x##sv) \
return (int) T::x
Expand All @@ -199,7 +199,7 @@ namespace config {
}

template<class T>
std::optional<int> rc_from_view(const std::string_view &rc, const std::optional<int>(&original)) {
::std::optional<int> rc_from_view(const ::std::string_view &rc, const ::std::optional<int>(&original)) {
#define _CONVERT_(x) \
if (rc == #x##sv) \
return (int) T::x
Expand All @@ -212,7 +212,7 @@ namespace config {
}

template<class T>
std::optional<int> usage_from_view(const std::string_view &usage, const std::optional<int>(&original)) {
::std::optional<int> usage_from_view(const ::std::string_view &usage, const ::std::optional<int>(&original)) {
#define _CONVERT_(x) \
if (usage == #x##sv) \
return (int) T::x
Expand All @@ -225,7 +225,7 @@ namespace config {
return original;
}

int coder_from_view(const std::string_view &coder) {
int coder_from_view(const ::std::string_view &coder) {
if (coder == "auto"sv) {
return _auto;
}
Expand Down
2 changes: 2 additions & 0 deletions src/platform/windows/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b
namespace {

constexpr auto SAMPLE_RATE = 48000;
#ifdef STEAM_DRIVER_SUBDIR
constexpr auto STEAM_AUDIO_DRIVER_PATH = L"%CommonProgramFiles(x86)%\\Steam\\drivers\\Windows10\\" STEAM_DRIVER_SUBDIR L"\\SteamStreamingSpeakers.inf";
#endif

constexpr auto waveformat_mask_stereo = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;

Expand Down
10 changes: 9 additions & 1 deletion src/platform/windows/display_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
// lib includes
#include <boost/algorithm/string/join.hpp>
#include <boost/process/v1.hpp>
#include <MinHook.h>

// conditional includes
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64)
#include <MinHook.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can/should do this. It might work now by luck because none of the Windows ARM64 machines out in the wild have a discrete GPU, but it is definitely not guaranteed to continue working. We should look into hooking libraries that support ARM64, like Detours.

Copy link
Contributor Author

@rbqvq rbqvq Jul 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MediaTek + NVIDIA SoCs in 2026
I'm not sure if this is integrated or discrete graphics.
At least until then, we don't have to do this.
We don't have any discrete GPU drivers for windows on arm

Step by step, complete the initial support first

#endif

// We have to include boost/process/v1.hpp before display.h due to WinSock.h,
// but that prevents the definition of NTSTATUS so we must define it ourself.
Expand Down Expand Up @@ -407,6 +411,7 @@ namespace platf::dxgi {
return false;
}

#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64)
/**
* @brief Hook for NtGdiDdDDIGetCachedHybridQueryValue() from win32u.dll.
* @param gpuPreference A pointer to the location where the preference will be written.
Expand All @@ -425,6 +430,7 @@ namespace platf::dxgi {
return STATUS_INVALID_PARAMETER;
}
}
#endif

int display_base_t::init(const ::video::config_t &config, const std::string &display_name) {
std::once_flag windows_cpp_once_flag;
Expand All @@ -444,12 +450,14 @@ namespace platf::dxgi {
FreeLibrary(user32);
}

#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64)
{
// We aren't calling MH_Uninitialize(), but that's okay because this hook lasts for the life of the process
MH_Initialize();
MH_CreateHookApi(L"win32u.dll", "NtGdiDdDDIGetCachedHybridQueryValue", (void *) NtGdiDdDDIGetCachedHybridQueryValueHook, nullptr);
MH_EnableHook(MH_ALL_HOOKS);
}
#endif
});

// Get rectangle of full desktop for absolute mouse coordinates
Expand Down
2 changes: 1 addition & 1 deletion src/platform/windows/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "src/logging.h"
#include "src/platform/common.h"

#ifdef __MINGW32__
#if defined(__MINGW32__) && (defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64))
DECLARE_HANDLE(HSYNTHETICPOINTERDEVICE);
WINUSERAPI HSYNTHETICPOINTERDEVICE WINAPI CreateSyntheticPointerDevice(POINTER_INPUT_TYPE pointerType, ULONG maxCount, POINTER_FEEDBACK_MODE mode);
WINUSERAPI BOOL WINAPI InjectSyntheticPointerInput(HSYNTHETICPOINTERDEVICE device, CONST POINTER_TYPE_INFO *pointerInfo, UINT32 count);
Expand Down
2 changes: 1 addition & 1 deletion src/platform/windows/windows.rc
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ BEGIN

END
END
SuperDuperAmazing ICON DISCARDABLE PROJECT_ICON_PATH
SuperDuperAmazing ICON DISCARDABLE TOSTRING(PROJECT_ICON_PATH)