Skip to content
Open
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
33 changes: 27 additions & 6 deletions .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,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@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
Expand Down Expand Up @@ -62,17 +67,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 @@ -158,7 +168,6 @@ jobs:
-B build \
-G Ninja \
-S . \
-DBUILD_WERROR=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DSUNSHINE_ASSETS_DIR=assets \
-DSUNSHINE_PUBLISHER_NAME="${GITHUB_REPOSITORY_OWNER}" \
Expand All @@ -168,18 +177,29 @@ jobs:
ninja -C build
echo "::remove-matcher owner=gcc::"

- 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 @@ -193,7 +213,8 @@ jobs:
# any except canceled or skipped
if: >-
always() &&
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
(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 @@ -89,7 +89,6 @@ list(PREPEND PLATFORM_LIBRARIES
libssp.a
libstdc++.a
libwinpthread.a
minhook::minhook
ntdll
setupapi
shlwapi
Expand All @@ -99,6 +98,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
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
Copy link
Member

Choose a reason for hiding this comment

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

Can you open an issue here? https://github.com/google/googletest/issues

It seems like there's really only one place where atomic is used, maybe they can easily work around it when it's not available. https://github.com/search?q=repo%3Agoogle%2Fgoogletest%20atomic&type=code

Or we should use the gtest provided by msys2? https://github.com/msys2/MINGW-packages/tree/ab284e9ffd0590397c948f56ac889208464fb0dd/mingw-w64-gtest

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know, I think you can open a issue for 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 @@ -126,33 +126,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"
)
fi
pacman -S "${dependencies[@]}"
```

Expand Down Expand Up @@ -199,7 +217,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 @@ -329,10 +329,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) |

> [!CAUTION]
> You should carefully select or unselect the options you want to install. Do not blindly install or
Expand All @@ -347,8 +354,13 @@ overflow menu. Different versions of Windows may provide slightly different step
> 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
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
"@vitejs/plugin-vue": "6.0.1",
"serve": "14.2.5",
"vite": "6.3.6",
"vite-plugin-ejs": "1.7.0"
"vite-plugin-ejs": "1.7.0",
"@rollup/wasm-node": "^4.57.1"
},
"overrides": {
"rollup": "npm:@rollup/wasm-node@^4.57.1"
}
}
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 @@ -39,7 +39,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

Copy link
Member

Choose a reason for hiding this comment

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

I agree this should be resolved before being merged otherwise it's just adding to the technical debt.

#endif

// local includes
#include "utf_utils.h"
Expand Down Expand Up @@ -420,6 +424,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 @@ -438,6 +443,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 @@ -457,12 +463,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
6 changes: 6 additions & 0 deletions src/platform/windows/display_vram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1907,6 +1907,12 @@ namespace platf::dxgi {
if (!boost::algorithm::ends_with(name, "_nvenc")) {
return false;
}
} else if (adapter_desc.VendorId == 0x4D4F4351 || // Qualcomm (QCOM as MOQC reversed)
adapter_desc.VendorId == 0x5143) { // Qualcomm alternate ID
// If it's not a MediaFoundation encoder, it's not compatible with a Qualcomm GPU
if (!boost::algorithm::ends_with(name, "_mf")) {
return false;
}
} else {
BOOST_LOG(warning) << "Unknown GPU vendor ID: " << util::hex(adapter_desc.VendorId).to_string_view();
}
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)
Loading