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
5 changes: 4 additions & 1 deletion cmake/compile_definitions/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ if(NOT DEFINED SUNSHINE_ICON_PATH)
set(SUNSHINE_ICON_PATH "${CMAKE_SOURCE_DIR}/sunshine.ico")
endif()

# For cross-compilation with llvm-rc, use relative path from build dir
file(RELATIVE_PATH SUNSHINE_ICON_RELATIVE "${CMAKE_BINARY_DIR}" "${SUNSHINE_ICON_PATH}")

# Create a separate object library for the RC file with minimal includes
add_library(sunshine_rc_object OBJECT "${CMAKE_SOURCE_DIR}/src/platform/windows/windows.rc")

# Set minimal properties for RC compilation - only what's needed for the resource file
# Otherwise compilation can fail due to "line too long" errors
set_target_properties(sunshine_rc_object PROPERTIES
COMPILE_DEFINITIONS "PROJECT_ICON_PATH=${SUNSHINE_ICON_PATH};PROJECT_NAME=${PROJECT_NAME};PROJECT_VENDOR=${SUNSHINE_PUBLISHER_NAME};PROJECT_VERSION=${PROJECT_VERSION};PROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR};PROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR};PROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH}" # cmake-lint: disable=C0301
COMPILE_DEFINITIONS "PROJECT_ICON_PATH=\"${SUNSHINE_ICON_RELATIVE}\";PROJECT_NAME=${PROJECT_NAME};PROJECT_VENDOR=\"${SUNSHINE_PUBLISHER_NAME}\";PROJECT_VERSION=${PROJECT_VERSION};PROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR};PROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR};PROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH}" # cmake-lint: disable=C0301
INCLUDE_DIRECTORIES ""
)

Expand Down
39 changes: 39 additions & 0 deletions cmake/toolchains/aarch64-w64-mingw32.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# CMake toolchain file for cross-compiling to Windows ARM64
# using llvm-mingw toolchain

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

# Toolchain paths - adjust TOOLCHAIN_ROOT as needed
if(NOT DEFINED TOOLCHAIN_ROOT)
set(TOOLCHAIN_ROOT "$ENV{HOME}/toolchains/llvm-mingw")
endif()

set(TARGET_TRIPLE "aarch64-w64-mingw32")

# Compilers
set(CMAKE_C_COMPILER "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-clang")
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-clang++")
set(CMAKE_RC_COMPILER "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-windres")
set(CMAKE_AR "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-ar")
set(CMAKE_RANLIB "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-ranlib")

# Sysroot
set(CMAKE_SYSROOT "${TOOLCHAIN_ROOT}/${TARGET_TRIPLE}")
set(CMAKE_FIND_ROOT_PATH "${TOOLCHAIN_ROOT}/${TARGET_TRIPLE}")

# Search paths
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# Compiler flags
set(CMAKE_C_FLAGS_INIT "-D_WIN32_WINNT=0x0A00")
set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++ -D_WIN32_WINNT=0x0A00")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-static -lc++ -lc++abi")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-static -lc++ -lc++abi")

# Windows-specific
set(WIN32 TRUE)
set(MINGW TRUE)
242 changes: 242 additions & 0 deletions docs/BUILD-ARM64.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
# Building Sunshine for Windows ARM64

This guide covers cross-compiling Sunshine for Windows ARM64 (Qualcomm Snapdragon) from a Linux host using the llvm-mingw toolchain.

## Prerequisites

- Ubuntu 22.04+ or WSL2
- ~10GB disk space
- Internet connection for downloading dependencies

## Quick Start

```bash
# Install build tools
sudo apt update
sudo apt install -y cmake ninja-build git curl wget pkg-config \
python3 nodejs npm nasm

# Download llvm-mingw toolchain
cd ~
wget https://github.com/mstorsjo/llvm-mingw/releases/download/20241119/llvm-mingw-20241119-ucrt-ubuntu-22.04-x86_64.tar.xz
tar xf llvm-mingw-20241119-ucrt-ubuntu-22.04-x86_64.tar.xz
mv llvm-mingw-20241119-ucrt-ubuntu-22.04-x86_64 toolchains/llvm-mingw

# Clone Sunshine
git clone --recursive https://github.com/LizardByte/Sunshine.git
cd Sunshine
```

## Building Dependencies

The following dependencies must be built for ARM64. Create a working directory:

```bash
mkdir -p ~/deps-arm64/install
cd ~/deps-arm64
export TC=~/toolchains/llvm-mingw
export TARGET=aarch64-w64-mingw32
export PREFIX=~/deps-arm64/install
```

### OpenSSL 3.4.0

```bash
wget https://github.com/openssl/openssl/releases/download/openssl-3.4.0/openssl-3.4.0.tar.gz
tar xf openssl-3.4.0.tar.gz
cd openssl-3.4.0

./Configure mingw64 --cross-compile-prefix=$TC/bin/$TARGET- \
--prefix=$PREFIX --libdir=lib no-shared no-tests
make -j$(nproc)
make install_sw
cd ..
```

### libcurl 8.11.1

```bash
wget https://curl.se/download/curl-8.11.1.tar.xz
tar xf curl-8.11.1.tar.xz
cd curl-8.11.1
mkdir build && cd build

cmake .. -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=~/Sunshine/cmake/toolchains/aarch64-w64-mingw32.cmake \
-DCMAKE_PREFIX_PATH=$PREFIX \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DBUILD_SHARED_LIBS=OFF \
-DCURL_USE_OPENSSL=ON \
-DCURL_DISABLE_LDAP=ON \
-DBUILD_CURL_EXE=OFF \
-DBUILD_TESTING=OFF

ninja && ninja install
cd ../..
```

### miniupnpc 2.2.8

```bash
wget https://github.com/miniupnp/miniupnp/archive/refs/tags/miniupnpc_2_2_8.tar.gz
tar xf miniupnpc_2_2_8.tar.gz
cd miniupnp-miniupnpc_2_2_8/miniupnpc
mkdir build && cd build

cmake .. -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=~/Sunshine/cmake/toolchains/aarch64-w64-mingw32.cmake \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DUPNPC_BUILD_STATIC=ON \
-DUPNPC_BUILD_SHARED=OFF \
-DUPNPC_BUILD_TESTS=OFF \
-DUPNPC_BUILD_SAMPLE=OFF

ninja && ninja install
cd ../../..
```

### Opus 1.5.2

```bash
wget https://github.com/xiph/opus/releases/download/v1.5.2/opus-1.5.2.tar.gz
tar xf opus-1.5.2.tar.gz
cd opus-1.5.2
mkdir build && cd build

cmake .. -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=~/Sunshine/cmake/toolchains/aarch64-w64-mingw32.cmake \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DBUILD_SHARED_LIBS=OFF \
-DOPUS_BUILD_TESTING=OFF \
-DOPUS_BUILD_PROGRAMS=OFF

ninja && ninja install
cd ../..
```

### Stub Libraries

Some libraries are not available on ARM64 and require stubs:

#### MinHook (not available on ARM64)

```bash
mkdir -p $PREFIX/lib
cat > /tmp/minhook_stub.c << 'EOF'
int MH_Initialize(void) { return 0; }
int MH_Uninitialize(void) { return 0; }
int MH_CreateHook(void *a, void *b, void **c) { return 0; }
int MH_EnableHook(void *a) { return 0; }
int MH_DisableHook(void *a) { return 0; }
EOF
$TC/bin/$TARGET-clang -c /tmp/minhook_stub.c -o /tmp/minhook_stub.o
$TC/bin/$TARGET-ar rcs $PREFIX/lib/libMinHook.a /tmp/minhook_stub.o
```

#### VPL (Intel QuickSync - not available on ARM64)

```bash
cat > /tmp/vpl_stub.c << 'EOF'
int MFXInit(int a, void *b, void **c) { return -1; }
int MFXClose(void *a) { return 0; }
int MFXQueryVersion(void *a, void *b) { return -1; }
int MFXInitEx(void *a, void **b) { return -1; }
EOF
$TC/bin/$TARGET-clang -c /tmp/vpl_stub.c -o /tmp/vpl_stub.o
$TC/bin/$TARGET-ar rcs $PREFIX/lib/libvpl.a /tmp/vpl_stub.o

mkdir -p $PREFIX/include/vpl
cat > $PREFIX/include/vpl/mfxvideo.h << 'EOF'
#pragma once
typedef int mfxStatus;
typedef void* mfxSession;
EOF
```

## CMake Toolchain File

Create `cmake/toolchains/aarch64-w64-mingw32.cmake`:

```cmake
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

set(TOOLCHAIN_ROOT "$ENV{HOME}/toolchains/llvm-mingw")
set(TARGET_TRIPLE "aarch64-w64-mingw32")

set(CMAKE_C_COMPILER "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-clang")
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-clang++")
set(CMAKE_RC_COMPILER "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-windres")
set(CMAKE_AR "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-ar")
set(CMAKE_RANLIB "${TOOLCHAIN_ROOT}/bin/${TARGET_TRIPLE}-ranlib")

set(CMAKE_FIND_ROOT_PATH "${TOOLCHAIN_ROOT}/${TARGET_TRIPLE}")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++ -D_WIN32_WINNT=0x0A00")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-static -lc++ -lc++abi")
```

## Building Sunshine

```bash
cd ~/Sunshine
mkdir build-arm64 && cd build-arm64

cmake .. -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/aarch64-w64-mingw32.cmake \
-DCMAKE_PREFIX_PATH="$PREFIX;$HOME/Sunshine/third-party/build-deps/dist/Windows-ARM64" \
-DCMAKE_BUILD_TYPE=Release \
-DSUNSHINE_ENABLE_TRAY=OFF \
-DSUNSHINE_ENABLE_DRM=OFF \
-DSUNSHINE_ENABLE_WAYLAND=OFF \
-DSUNSHINE_ENABLE_X11=OFF \
-DSUNSHINE_ENABLE_CUDA=OFF \
-DSUNSHINE_BUILD_APPIMAGE=OFF \
-DSUNSHINE_PUBLISHER_NAME="LizardByte"

ninja sunshine.exe
```

## Running on Windows ARM64

1. Copy the built files to your Windows ARM64 device:
- `sunshine.exe`
- `assets/` folder (from `src_assets/windows/assets/`)

2. Install ViGEmBus driver for controller support

3. Run `sunshine.exe` from an elevated command prompt

## Hardware Encoding

Sunshine will automatically detect and use the Qualcomm Adreno GPU for hardware encoding via Windows Media Foundation:

- **h264_mf**: H.264 hardware encoding
- **hevc_mf**: HEVC hardware encoding
- **av1_mf**: AV1 hardware encoding (if supported)

### Known Limitations

- Only SDR 4:2:0 8-bit encoding supported (Qualcomm MF limitation)
- No HDR or YUV444 support
- ~8ms encoder latency overhead compared to direct GPU APIs
- Software encoding (libx264) may perform better in some cases

To use software encoding, set `encoder = software` in `sunshine.conf`.

## Troubleshooting

### "Encoder did not produce IDR frame"
This is normal for the first frame with Media Foundation encoders. The encoder uses a fixed GOP size of 120 frames.

### Large encoded frames / FEC warnings
The Media Foundation encoder may produce larger keyframes. This is handled automatically but may cause occasional FEC skip warnings.

### Shader compilation errors
Ensure the `assets/shaders/` directory is present alongside `sunshine.exe`.

### No GPU detected
Verify the Qualcomm Adreno driver is installed. Check Device Manager for the GPU.
10 changes: 5 additions & 5 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 Expand Up @@ -295,7 +295,7 @@ namespace config {
cavlc ///< CAVLC
};

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
17 changes: 10 additions & 7 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ namespace boost {
class path;
}

namespace process::inline v1 {
class child;
class group;
template<typename Char>
class basic_environment;
typedef basic_environment<char> environment;
} // namespace process::inline v1
namespace process {
namespace v1 {
class child;
class group;
template<typename Char>
class basic_environment;
typedef basic_environment<char> environment;
} // namespace v1
using namespace v1;
} // namespace process
} // namespace boost
#endif
namespace video {
Expand Down
3 changes: 3 additions & 0 deletions src/platform/windows/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b

#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64)
#define STEAM_DRIVER_SUBDIR L"x64"
#elif defined(__aarch64__) || defined(_M_ARM64)
#define STEAM_DRIVER_SUBDIR L"arm64"
#else
#warning No known Steam audio driver for this architecture
#define STEAM_DRIVER_SUBDIR L"unknown"
#endif

namespace {
Expand Down
3 changes: 3 additions & 0 deletions src/platform/windows/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include <dxgi.h>
#include <dxgi1_6.h>
#include <Unknwn.h>
#ifdef __clang__
#include "include/wgc_interop_guids.h"
#endif
#include <winrt/windows.graphics.capture.h>

// local includes
Expand Down
Loading