diff --git a/.github/workflows/ci-bundle.yml b/.github/workflows/ci-bundle.yml index d9edfd7c791..3a7df39e6f0 100644 --- a/.github/workflows/ci-bundle.yml +++ b/.github/workflows/ci-bundle.yml @@ -23,6 +23,10 @@ jobs: - name: Install npm dependencies run: npm install --ignore-scripts + - name: Debug install + if: always() + run: cat "${HOME}/.npm/_logs/*-debug-0.log" || true + - name: Build env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index 2164df0c41f..be8392cca48 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -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 @@ -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" + ) + fi + # do not modify below this line ignore_packages=() @@ -129,6 +139,11 @@ jobs: # Clean up Remove-Item -Path doxygen-setup.exe + - name: Setup dotnet # needed for wix + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.x' + - name: Setup python id: setup-python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 @@ -169,19 +184,33 @@ jobs: echo "::remove-matcher owner=gcc::" - name: Package Windows + env: + # if MSYSTEM is used, it interferes with environment and cpack cannot be found + MATRIX_MSYSTEM: ${{ matrix.msystem }} shell: msys2 {0} run: | mkdir -p artifacts cd build - # package - cpack -G NSIS - cpack -G ZIP + # nsis installer + if [[ "${MATRIX_MSYSTEM}" == "ucrt64" ]]; then + cpack -G NSIS + mv ./cpack_artifacts/Sunshine.exe ../artifacts/Sunshine-${{ matrix.name }}-installer.exe + fi + + # wix installer + cpack -G WIX + mv ./cpack_artifacts/Sunshine.msi ../artifacts/Sunshine-${{ matrix.name }}-installer.msi - # move - mv ./cpack_artifacts/Sunshine.exe ../artifacts/Sunshine-${{ matrix.name }}-installer.exe + # portable version + cpack -G ZIP mv ./cpack_artifacts/Sunshine.zip ../artifacts/Sunshine-${{ matrix.name }}-portable.zip + - name: Debug wix + if: always() + shell: msys2 {0} + run: cat ./build/cpack_artifacts/_CPack_Packages/win64/WIX/wix.log || true + - name: Run tests id: test shell: msys2 {0} diff --git a/cmake/compile_definitions/windows.cmake b/cmake/compile_definitions/windows.cmake index c1a2c95fc45..57af5e2a435 100644 --- a/cmake/compile_definitions/windows.cmake +++ b/cmake/compile_definitions/windows.cmake @@ -9,6 +9,13 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") # gcc complains about misleading indentation in some mingw includes list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-misleading-indentation) +# Disable warnings for Windows ARM64 +if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64") + list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-dll-attribute-on-redeclaration) # Boost + list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-unknown-warning-option) # ViGEmClient + list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-unused-variable) # Boost +endif() + # see gcc bug 98723 add_definitions(-DUSE_BOOST_REGEX) diff --git a/cmake/dependencies/windows.cmake b/cmake/dependencies/windows.cmake index 3faad7dfd41..a9e5630d971 100644 --- a/cmake/dependencies/windows.cmake +++ b/cmake/dependencies/windows.cmake @@ -1,9 +1,35 @@ # 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) +# MinHook setup - use installed minhook for AMD64, otherwise download minhook-detours for ARM64 +if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64") + # Make sure MinHook is installed for x86/x64 + 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}) +else() + # Download pre-built minhook-detours for ARM64 + message(STATUS "Downloading minhook-detours pre-built binaries for ARM64") + include(FetchContent) + + FetchContent_Declare( + minhook-detours + URL https://github.com/m417z/minhook-detours/releases/download/v1.0.6/minhook-detours-1.0.6.zip + URL_HASH SHA256=E719959D824511E27395A82AEDA994CAAD53A67EE5894BA5FC2F4BF1FA41E38E + ) + FetchContent_MakeAvailable(minhook-detours) + + # Create imported library for the pre-built DLL + set(_MINHOOK_DLL + "${minhook-detours_SOURCE_DIR}/Release/minhook-detours.ARM64.Release.dll" + CACHE INTERNAL "Path to minhook-detours DLL") + add_library(minhook::minhook SHARED IMPORTED GLOBAL) + set_property(TARGET minhook::minhook PROPERTY IMPORTED_LOCATION "${_MINHOOK_DLL}") + set_property(TARGET minhook::minhook PROPERTY IMPORTED_IMPLIB + "${minhook-detours_SOURCE_DIR}/Release/minhook-detours.ARM64.Release.lib") + set_target_properties(minhook::minhook PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${minhook-detours_SOURCE_DIR}/src" + ) +endif() diff --git a/cmake/packaging/windows.cmake b/cmake/packaging/windows.cmake index 069fd85154b..0dbed2b6e7b 100644 --- a/cmake/packaging/windows.cmake +++ b/cmake/packaging/windows.cmake @@ -4,6 +4,11 @@ install(TARGETS sunshine RUNTIME DESTINATION "." COMPONENT application) # Hardening: include zlib1.dll (loaded via LoadLibrary() in openssl's libcrypto.a) install(FILES "${ZLIB}" DESTINATION "." COMPONENT application) +# ARM64: include minhook-detours DLL (shared library for ARM64) +if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64" AND DEFINED _MINHOOK_DLL) + install(FILES "${_MINHOOK_DLL}" DESTINATION "." COMPONENT application) +endif() + # ViGEmBus installer set(VIGEMBUS_INSTALLER "${CMAKE_BINARY_DIR}/scripts/vigembus_installer.exe") set(VIGEMBUS_DOWNLOAD_URL_1 "https://github.com/nefarius/ViGEmBus/releases/download") diff --git a/cmake/packaging/windows_wix.cmake b/cmake/packaging/windows_wix.cmake index bc956182f06..5f1393bd8a7 100644 --- a/cmake/packaging/windows_wix.cmake +++ b/cmake/packaging/windows_wix.cmake @@ -1,4 +1,92 @@ # WIX Packaging # see options at: https://cmake.org/cmake/help/latest/cpack_gen/wix.html -# TODO: Replace nsis with wix +set(CPACK_WIX_VERSION 4) +set(WIX_VERSION 4.0.4) +set(WIX_UI_VERSION 4.0.4) # extension versioning is independent of the WiX version +set(WIX_BUILD_PARENT_DIRECTORY "${CMAKE_BINARY_DIR}/wix_packaging") +set(WIX_BUILD_DIRECTORY "${CPACK_PACKAGE_DIRECTORY}/_CPack_Packages/win64/WIX") + +# Download and install WiX tools locally in the build directory +set(WIX_TOOL_PATH "${CMAKE_BINARY_DIR}/.wix") +file(MAKE_DIRECTORY ${WIX_TOOL_PATH}) + +# find dotnet +find_program(DOTNET_EXECUTABLE dotnet REQUIRED HINTS "C:/Program Files/dotnet") + +# Install WiX locally using dotnet +execute_process( + COMMAND ${DOTNET_EXECUTABLE} tool install --tool-path ${WIX_TOOL_PATH} wix --version ${WIX_VERSION} + ERROR_VARIABLE WIX_INSTALL_OUTPUT + RESULT_VARIABLE WIX_INSTALL_RESULT +) + +if(NOT WIX_INSTALL_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to install WiX tools locally. + WiX packaging may not work correctly, error: ${WIX_INSTALL_OUTPUT}") +endif() + +# Install WiX UI Extension +execute_process( + COMMAND "${WIX_TOOL_PATH}/wix" extension add WixToolset.UI.wixext/${WIX_UI_VERSION} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ERROR_VARIABLE WIX_UI_INSTALL_OUTPUT + RESULT_VARIABLE WIX_UI_INSTALL_RESULT +) + +if(NOT WIX_UI_INSTALL_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to install WiX UI extension, error: ${WIX_UI_INSTALL_OUTPUT}") +endif() + +# Install WiX Util Extension +execute_process( + COMMAND "${WIX_TOOL_PATH}/wix" extension add WixToolset.Util.wixext/${WIX_UI_VERSION} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ERROR_VARIABLE WIX_UTIL_INSTALL_OUTPUT + RESULT_VARIABLE WIX_UTIL_INSTALL_RESULT +) + +if(NOT WIX_UTIL_INSTALL_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to install WiX Util extension, error: ${WIX_UTIL_INSTALL_OUTPUT}") +endif() + +# Set WiX-specific variables +set(CPACK_WIX_ROOT "${WIX_TOOL_PATH}") +set(CPACK_WIX_UPGRADE_GUID "512A3D1B-BE16-401B-A0D1-59BBA3942FB8") + +# Installer metadata +set(CPACK_WIX_HELP_LINK "https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2getting__started.html") +set(CPACK_WIX_PRODUCT_ICON "${SUNSHINE_ICON_PATH}") +set(CPACK_WIX_PRODUCT_URL "${CMAKE_PROJECT_HOMEPAGE_URL}") +set(CPACK_WIX_PROGRAM_MENU_FOLDER "LizardByte") + +set(CPACK_WIX_EXTENSIONS + "WixToolset.UI.wixext" + "WixToolset.Util.wixext" +) + +message(STATUS "cpack package directory: ${CPACK_PACKAGE_DIRECTORY}") + +# copy custom wxs files to the build directory +file(COPY "${CMAKE_CURRENT_LIST_DIR}/wix_resources/" + DESTINATION "${WIX_BUILD_PARENT_DIRECTORY}/") + +set(CPACK_WIX_EXTRA_SOURCES + "${WIX_BUILD_PARENT_DIRECTORY}/sunshine-installer.wxs" +) +set(CPACK_WIX_PATCH_FILE + "${WIX_BUILD_PARENT_DIRECTORY}/patch.xml" +) + +# Copy root LICENSE and rename to have .txt extension +file(COPY "${CMAKE_SOURCE_DIR}/LICENSE" + DESTINATION "${CMAKE_BINARY_DIR}") +file(RENAME "${CMAKE_BINARY_DIR}/LICENSE" "${CMAKE_BINARY_DIR}/LICENSE.txt") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/LICENSE.txt") # cpack will covert this to an RTF if it is txt + +# https://cmake.org/cmake/help/latest/cpack_gen/wix.html#variable:CPACK_WIX_ARCHITECTURE +if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64") + set(CPACK_WIX_ARCHITECTURE "arm64") +else() + set(CPACK_WIX_ARCHITECTURE "x64") +endif() diff --git a/cmake/packaging/wix_resources/patch.xml b/cmake/packaging/wix_resources/patch.xml new file mode 100644 index 00000000000..e85c3581dee --- /dev/null +++ b/cmake/packaging/wix_resources/patch.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/cmake/packaging/wix_resources/sunshine-installer.wxs b/cmake/packaging/wix_resources/sunshine-installer.wxs new file mode 100644 index 00000000000..aaec41a9ac2 --- /dev/null +++ b/cmake/packaging/wix_resources/sunshine-installer.wxs @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmake/prep/build_version.cmake b/cmake/prep/build_version.cmake index 7c10dde2414..91209922066 100644 --- a/cmake/prep/build_version.cmake +++ b/cmake/prep/build_version.cmake @@ -56,11 +56,11 @@ else() if(NOT GIT_DESCRIBE_ERROR_CODE) MESSAGE("Sunshine Branch: ${GIT_DESCRIBE_BRANCH}") if(NOT GIT_DESCRIBE_BRANCH STREQUAL "master") - set(PROJECT_VERSION ${PROJECT_VERSION}.${GIT_DESCRIBE_VERSION}) + set(PROJECT_VERSION ${PROJECT_VERSION}-${GIT_DESCRIBE_VERSION}) MESSAGE("Sunshine Version: ${GIT_DESCRIBE_VERSION}") endif() if(GIT_IS_DIRTY) - set(PROJECT_VERSION ${PROJECT_VERSION}.dirty) + set(PROJECT_VERSION ${PROJECT_VERSION}-dirty) MESSAGE("Git tree is dirty!") endif() else() diff --git a/cmake/prep/options.cmake b/cmake/prep/options.cmake index 6b732a957e6..f8973ea4899 100644 --- a/cmake/prep/options.cmake +++ b/cmake/prep/options.cmake @@ -9,6 +9,7 @@ set(SUNSHINE_PUBLISHER_ISSUE_URL "https://app.lizardbyte.dev/support" option(BUILD_DOCS "Build documentation" ON) option(BUILD_TESTS "Build tests" ON) + option(NPM_OFFLINE "Use offline npm packages. You must ensure packages are in your npm cache." OFF) option(BUILD_WERROR "Enable -Werror flag." OFF) diff --git a/docs/building.md b/docs/building.md index 67b2066cd49..05870ab51b3 100644 --- a/docs/building.md +++ b/docs/building.md @@ -126,33 +126,52 @@ 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}-doxygen" # Optional, for docs + "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[@]}" ``` @@ -198,9 +217,12 @@ ninja -C build ```} }} @tab{Windows | @tabs{ - @tab{Installer | ```bash + @tab{NSIS Installer | ```bash cpack -G NSIS --config ./build/CPackConfig.cmake ```} + @tab{WiX Installer | ```bash + cpack -G WIX --config ./build/CPackConfig.cmake + ```} @tab{Portable | ```bash cpack -G ZIP --config ./build/CPackConfig.cmake ```} diff --git a/docs/getting_started.md b/docs/getting_started.md index d2afb2b9354..978a0b832d5 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -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 @@ -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 diff --git a/package.json b/package.json index 065fc6d3340..56df3046fff 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index 2b1d705ee7b..312c74fdec5 100755 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -695,7 +695,7 @@ elif grep -q "Debian GNU/Linux 12 (bookworm)" /etc/os-release; then cuda_version="12.9.1" cuda_build="575.57.08" gcc_version="13" - nvm_node=0 + nvm_node=1 elif grep -q "Debian GNU/Linux 13 (trixie)" /etc/os-release; then distro="debian" version="13" @@ -704,7 +704,7 @@ elif grep -q "Debian GNU/Linux 13 (trixie)" /etc/os-release; then cuda_version="12.9.1" cuda_build="575.57.08" gcc_version="14" - nvm_node=0 + nvm_node=1 elif grep -q "PLATFORM_ID=\"platform:f41\"" /etc/os-release; then distro="fedora" version="41" diff --git a/src/config.cpp b/src/config.cpp index e5d58f3eccc..c320ed6dccf 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -187,7 +187,7 @@ namespace config { }; template - std::optional quality_from_view(const std::string_view &quality_type, const std::optional(&original)) { + ::std::optional quality_from_view(const ::std::string_view &quality_type, const ::std::optional(&original)) { #define _CONVERT_(x) \ if (quality_type == #x##sv) \ return (int) T::x @@ -199,7 +199,7 @@ namespace config { } template - std::optional rc_from_view(const std::string_view &rc, const std::optional(&original)) { + ::std::optional rc_from_view(const ::std::string_view &rc, const ::std::optional(&original)) { #define _CONVERT_(x) \ if (rc == #x##sv) \ return (int) T::x @@ -212,7 +212,7 @@ namespace config { } template - std::optional usage_from_view(const std::string_view &usage, const std::optional(&original)) { + ::std::optional usage_from_view(const ::std::string_view &usage, const ::std::optional(&original)) { #define _CONVERT_(x) \ if (usage == #x##sv) \ return (int) T::x @@ -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; } diff --git a/src/nvenc/nvenc_d3d11_on_cuda.h b/src/nvenc/nvenc_d3d11_on_cuda.h index 102e18097d1..80aeb9ed8f9 100644 --- a/src/nvenc/nvenc_d3d11_on_cuda.h +++ b/src/nvenc/nvenc_d3d11_on_cuda.h @@ -56,7 +56,6 @@ namespace nvenc { autopop_context push_context(); - HMODULE dll = nullptr; const ID3D11DevicePtr d3d_device; ID3D11Texture2DPtr d3d_input_texture; diff --git a/src/platform/windows/audio.cpp b/src/platform/windows/audio.cpp index d7d4680edfd..b26f91a811b 100644 --- a/src/platform/windows/audio.cpp +++ b/src/platform/windows/audio.cpp @@ -32,14 +32,14 @@ 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" -#else - #warning No known Steam audio driver for this architecture #endif 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; diff --git a/src/platform/windows/display_vram.cpp b/src/platform/windows/display_vram.cpp index c6b694f0a35..52a87c7817d 100644 --- a/src/platform/windows/display_vram.cpp +++ b/src/platform/windows/display_vram.cpp @@ -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(); } diff --git a/src/platform/windows/input.cpp b/src/platform/windows/input.cpp index 85273609ec5..533e3790013 100644 --- a/src/platform/windows/input.cpp +++ b/src/platform/windows/input.cpp @@ -10,6 +10,7 @@ // standard includes #include #include +#include // lib includes #include @@ -1134,9 +1135,9 @@ namespace platf { void unicode(input_t &input, char *utf8, int size) { // We can do no worse than one UTF-16 character per byte of UTF-8 - WCHAR wide[size]; + std::vector wide(size); - int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, size, wide, size); + int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8, size, wide.data(), size); if (chars <= 0) { return; } diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 5a4ea26e709..4736a4c731c 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -9,6 +9,7 @@ #include #include #include +#include // lib includes #include @@ -1383,7 +1384,7 @@ namespace platf { auto const max_bufs_per_msg = send_info.payload_buffers.size() + (send_info.headers ? 1 : 0); - WSABUF bufs[(send_info.headers ? send_info.block_count : 1) * max_bufs_per_msg]; + std::vector bufs((send_info.headers ? send_info.block_count : 1) * max_bufs_per_msg); DWORD bufcount = 0; if (send_info.headers) { // Interleave buffers for headers and payloads @@ -1409,7 +1410,7 @@ namespace platf { } } - msg.lpBuffers = bufs; + msg.lpBuffers = bufs.data(); msg.dwBufferCount = bufcount; msg.dwFlags = 0; diff --git a/src/platform/windows/windows.rc b/src/platform/windows/windows.rc index 8f1c2bf767a..417fcf0d047 100644 --- a/src/platform/windows/windows.rc +++ b/src/platform/windows/windows.rc @@ -41,4 +41,4 @@ BEGIN END END -SuperDuperAmazing ICON DISCARDABLE PROJECT_ICON_PATH +SuperDuperAmazing ICON DISCARDABLE TOSTRING(PROJECT_ICON_PATH) diff --git a/src/video.cpp b/src/video.cpp index 0290fd95002..7487e1278e6 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -300,6 +300,7 @@ namespace video { ALWAYS_REPROBE = 1 << 9, ///< This is an encoder of last resort and we want to aggressively probe for a better one YUV444_SUPPORT = 1 << 10, ///< Encoder may support 4:4:4 chroma sampling depending on hardware ASYNC_TEARDOWN = 1 << 11, ///< Encoder supports async teardown on a different thread + FIXED_GOP_SIZE = 1 << 12, ///< Use fixed small GOP size (encoder doesn't support on-demand IDR frames) }; class avcodec_encode_session_t: public encode_session_t { @@ -825,6 +826,63 @@ namespace video { }, PARALLEL_ENCODING }; + + encoder_t mediafoundation { + "mediafoundation"sv, + std::make_unique( + AV_HWDEVICE_TYPE_D3D11VA, + AV_HWDEVICE_TYPE_NONE, + AV_PIX_FMT_D3D11, + AV_PIX_FMT_NV12, // SDR 4:2:0 8-bit (only format Qualcomm supports) + AV_PIX_FMT_NONE, // No HDR - Qualcomm MF only supports 8-bit + AV_PIX_FMT_NONE, // No YUV444 SDR + AV_PIX_FMT_NONE, // No YUV444 HDR + dxgi_init_avcodec_hardware_input_buffer + ), + { + // Common options for AV1 - Qualcomm MF encoder + { + {"hw_encoding"s, 1}, + {"rate_control"s, "cbr"s}, + {"scenario"s, "display_remoting"s}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "av1_mf"s, + }, + { + // Common options for HEVC - Qualcomm MF encoder + { + {"hw_encoding"s, 1}, + {"rate_control"s, "cbr"s}, + {"scenario"s, "display_remoting"s}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "hevc_mf"s, + }, + { + // Common options for H.264 - Qualcomm MF encoder + { + {"hw_encoding"s, 1}, + {"rate_control"s, "cbr"s}, + {"scenario"s, "display_remoting"s}, + }, + {}, // SDR-specific options + {}, // HDR-specific options + {}, // YUV444 SDR-specific options + {}, // YUV444 HDR-specific options + {}, // Fallback options + "h264_mf"s, + }, + PARALLEL_ENCODING | FIXED_GOP_SIZE // MF encoder doesn't support on-demand IDR frames + }; #endif encoder_t software { @@ -1031,6 +1089,7 @@ namespace video { #ifdef _WIN32 &quicksync, &amdvce, + &mediafoundation, #endif #if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__) &vaapi, @@ -1566,11 +1625,17 @@ namespace video { ctx->max_b_frames = 0; // Use an infinite GOP length since I-frames are generated on demand - ctx->gop_size = encoder.flags & LIMITED_GOP_SIZE ? - std::numeric_limits::max() : - std::numeric_limits::max(); - - ctx->keyint_min = std::numeric_limits::max(); + // Exception: encoders with FIXED_GOP_SIZE flag don't support on-demand IDR + if (encoder.flags & FIXED_GOP_SIZE) { + // Fixed GOP for encoders that don't support on-demand IDR (e.g. Media Foundation) + ctx->gop_size = 120; // ~2 seconds at 60 FPS - larger to reduce oversized IDR frame frequency + ctx->keyint_min = 120; + } else { + ctx->gop_size = encoder.flags & LIMITED_GOP_SIZE ? + std::numeric_limits::max() : + std::numeric_limits::max(); + ctx->keyint_min = std::numeric_limits::max(); + } // Some client decoders have limits on the number of reference frames if (config.numRefFrames) { diff --git a/src/video.h b/src/video.h index 8dbf76e27bd..eb8bb46f0dd 100644 --- a/src/video.h +++ b/src/video.h @@ -220,6 +220,7 @@ namespace video { #ifdef _WIN32 extern encoder_t amdvce; extern encoder_t quicksync; + extern encoder_t mediafoundation; #endif #if defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9a570fd3e7f..1d9bdad4424 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -163,4 +163,15 @@ if (WIN32) # prefer static libraries since we're linking statically # this fixes libcurl linking errors when using non MSYS2 version of CMake set_target_properties(${PROJECT_NAME} PROPERTIES LINK_SEARCH_START_STATIC 1) + + # Copy minhook-detours DLL to test binary directory for ARM64 + if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64" AND DEFINED _MINHOOK_DLL) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${_MINHOOK_DLL}" + "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Copying minhook-detours DLL to test binary directory" + VERBATIM + ) + endif() endif ()