mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-08-07 10:20:46 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0784774fec | |||
| 3893c5bcda | |||
| c19904b577 | |||
| 089f15d4b6 | |||
| e2074c6d62 | |||
| 965c91a428 | |||
| 6f58be350e | |||
| 25c3f0b624 | |||
| cea0b89568 | |||
| fb3d85cff4 | |||
| 7cb92071ac | |||
| 4b74548578 | |||
| c19ad3db01 |
@@ -63,7 +63,7 @@ jobs:
|
||||
run: ls -l artifacts
|
||||
|
||||
- name: Update GitHub Release
|
||||
uses: LizardByte/actions/actions/release_create@a46850981292c4bbc0c41715f286ad95adaaaf4a # v2026.625.20301
|
||||
uses: LizardByte/actions/actions/release_create@d0ae7f82215a479fe2b74f4088c53ee6460513dd # v2026.728.214955
|
||||
with:
|
||||
allowUpdates: true
|
||||
body: ${{ github.event.release.body }}
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
steps:
|
||||
- name: More space
|
||||
if: matrix.arch == 'x86_64'
|
||||
uses: LizardByte/actions/actions/more_space@a46850981292c4bbc0c41715f286ad95adaaaf4a # v2026.625.20301
|
||||
uses: LizardByte/actions/actions/more_space@d0ae7f82215a479fe2b74f4088c53ee6460513dd # v2026.728.214955
|
||||
with:
|
||||
analyze-space-savings: true
|
||||
clean-all: true
|
||||
|
||||
@@ -107,7 +107,6 @@ jobs:
|
||||
devel/evdev-proto \
|
||||
devel/git \
|
||||
devel/libevdev \
|
||||
devel/libnotify \
|
||||
devel/llvm${{ env.FREEBSD_CLANG_VERSION }} \
|
||||
devel/ninja \
|
||||
devel/pkgconf \
|
||||
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
steps:
|
||||
- name: More space
|
||||
if: runner.os == 'Linux'
|
||||
uses: LizardByte/actions/actions/more_space@a46850981292c4bbc0c41715f286ad95adaaaf4a # v2026.625.20301
|
||||
uses: LizardByte/actions/actions/more_space@d0ae7f82215a479fe2b74f4088c53ee6460513dd # v2026.728.214955
|
||||
with:
|
||||
analyze-space-savings: true
|
||||
clean-all: true
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
dist: 22.04
|
||||
steps:
|
||||
- name: More space
|
||||
uses: LizardByte/actions/actions/more_space@a46850981292c4bbc0c41715f286ad95adaaaf4a # v2026.625.20301
|
||||
uses: LizardByte/actions/actions/more_space@d0ae7f82215a479fe2b74f4088c53ee6460513dd # v2026.728.214955
|
||||
with:
|
||||
analyze-space-savings: true
|
||||
clean-all: true
|
||||
@@ -151,17 +151,20 @@ jobs:
|
||||
|
||||
./appimagelint-x86_64.AppImage ./artifacts/sunshine.AppImage
|
||||
|
||||
- name: Install test deps
|
||||
- name: Install screenshot dependency
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y \
|
||||
x11-xserver-utils \
|
||||
xvfb
|
||||
sudo apt-get install -y imagemagick
|
||||
|
||||
# clean apt cache
|
||||
sudo apt-get clean
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
- name: Setup virtual desktop
|
||||
uses: LizardByte/actions/actions/virtual_desktop@d0ae7f82215a479fe2b74f4088c53ee6460513dd # v2026.728.214955
|
||||
with:
|
||||
environment: mate
|
||||
|
||||
- name: Setup python
|
||||
id: python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
@@ -182,12 +185,17 @@ jobs:
|
||||
- name: Run tests
|
||||
id: test
|
||||
working-directory: build/tests
|
||||
run: |
|
||||
export DISPLAY=:1
|
||||
Xvfb ${DISPLAY} -screen 0 1024x768x24 &
|
||||
sleep 5 # give Xvfb time to start
|
||||
run: ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml
|
||||
|
||||
./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml
|
||||
- name: Upload system tray screenshots
|
||||
if: >-
|
||||
always() &&
|
||||
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: sunshine-screenshots-${{ matrix.name }}
|
||||
path: build/tests/screenshots
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Generate gcov report
|
||||
id: test_report
|
||||
|
||||
@@ -90,7 +90,12 @@ jobs:
|
||||
icu4c@78 \
|
||||
miniupnpc \
|
||||
openssl@3 \
|
||||
opus
|
||||
opus \
|
||||
qtbase \
|
||||
qtsvg
|
||||
|
||||
- name: Configure macOS screen recording
|
||||
uses: LizardByte/tray/.github/actions/configure-macos-screen-recording@master
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
@@ -180,6 +185,16 @@ jobs:
|
||||
working-directory: build/tests
|
||||
run: ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml
|
||||
|
||||
- name: Upload system tray screenshots
|
||||
if: >-
|
||||
always() &&
|
||||
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: sunshine-screenshots-${{ matrix.name }}
|
||||
path: build/tests/screenshots
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Generate gcov report
|
||||
id: test_report
|
||||
# any except canceled or skipped
|
||||
|
||||
@@ -108,6 +108,7 @@ jobs:
|
||||
"mingw-w64-${TOOLCHAIN}-openssl"
|
||||
"mingw-w64-${TOOLCHAIN}-opus"
|
||||
"mingw-w64-${TOOLCHAIN}-toolchain"
|
||||
"mingw-w64-${TOOLCHAIN}-qt6-static"
|
||||
)
|
||||
|
||||
if [[ "${MATRIX_MSYSTEM}" == "ucrt64" ]]; then
|
||||
@@ -239,10 +240,12 @@ jobs:
|
||||
-S . \
|
||||
-DBUILD_WERROR=ON \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_PREFIX_PATH="${MINGW_PREFIX}/qt6-static" \
|
||||
-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"
|
||||
-DSUNSHINE_PUBLISHER_ISSUE_URL="https://app.lizardbyte.dev/support" \
|
||||
-DSUNSHINE_USE_STATIC_QT=ON
|
||||
echo "::add-matcher::.github/matchers/gcc.json"
|
||||
ninja -C build
|
||||
echo "::remove-matcher owner=gcc::"
|
||||
@@ -345,12 +348,34 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
run: cat ./build/cpack_artifacts/_CPack_Packages/win64/WIX/wix.log || true
|
||||
|
||||
- name: Initialize tray icon
|
||||
working-directory: build/tests
|
||||
env:
|
||||
SUNSHINE_CONFIGURE_TRAY_ICONS: '1'
|
||||
run: >-
|
||||
./test_sunshine.exe
|
||||
--gtest_color=yes
|
||||
--gtest_filter=SystemTrayTest.InitializesTrayForWorkflowConfiguration
|
||||
|
||||
- name: Configure Windows tray screenshots
|
||||
uses: LizardByte/tray/.github/actions/configure-windows-tray-screenshots@master
|
||||
|
||||
- name: Run tests
|
||||
id: test
|
||||
shell: msys2 {0}
|
||||
working-directory: build/tests
|
||||
run: ./test_sunshine.exe --gtest_color=yes --gtest_output=xml:test_results.xml
|
||||
|
||||
- name: Upload system tray screenshots
|
||||
if: >-
|
||||
always() &&
|
||||
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: sunshine-screenshots-${{ matrix.name }}
|
||||
path: build/tests/screenshots
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Generate gcov report
|
||||
id: test_report
|
||||
# any except canceled or skipped
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- name: Release Setup
|
||||
id: release-setup
|
||||
uses: LizardByte/actions/actions/release_setup@a46850981292c4bbc0c41715f286ad95adaaaf4a # v2026.625.20301
|
||||
uses: LizardByte/actions/actions/release_setup@d0ae7f82215a479fe2b74f4088c53ee6460513dd # v2026.728.214955
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -316,7 +316,7 @@ jobs:
|
||||
run: ls -l artifacts
|
||||
|
||||
- name: Create/Update GitHub Release
|
||||
uses: LizardByte/actions/actions/release_create@a46850981292c4bbc0c41715f286ad95adaaaf4a # v2026.625.20301
|
||||
uses: LizardByte/actions/actions/release_create@d0ae7f82215a479fe2b74f4088c53ee6460513dd # v2026.728.214955
|
||||
with:
|
||||
allowUpdates: false
|
||||
body: ${{ needs.release-setup.outputs.release_body }}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Publish Screenshots
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["CI"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
if: github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure'
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
pull-requests: write
|
||||
statuses: write
|
||||
uses: LizardByte/tray/.github/workflows/_publish-screenshots.yml@master
|
||||
with:
|
||||
artifact-name-prefix: sunshine-screenshots-
|
||||
source-run-id: ${{ github.event.workflow_run.id }}
|
||||
@@ -29,10 +29,6 @@
|
||||
path = third-party/moonlight-common-c
|
||||
url = https://github.com/moonlight-stream/moonlight-common-c.git
|
||||
branch = master
|
||||
[submodule "third-party/nv-codec-headers"]
|
||||
path = third-party/nv-codec-headers
|
||||
url = https://github.com/FFmpeg/nv-codec-headers.git
|
||||
branch = master
|
||||
[submodule "third-party/nvapi"]
|
||||
path = third-party/nvapi
|
||||
url = https://github.com/NVIDIA/nvapi.git
|
||||
|
||||
@@ -38,6 +38,10 @@ endif()
|
||||
# set the module path, used for includes
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
# CPM
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpm/CPM.cmake)
|
||||
CPMUsePackageLock(package-lock.cmake)
|
||||
|
||||
# export compile_commands.json
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
|
||||
@@ -59,8 +59,53 @@ elseif(UNIX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include_directories(BEFORE SYSTEM "${CMAKE_SOURCE_DIR}/third-party/nv-codec-headers/include")
|
||||
file(GLOB NVENC_SOURCES CONFIGURE_DEPENDS "src/nvenc/*.cpp" "src/nvenc/*.h")
|
||||
set(NVENC_PUBLIC_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_config.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_d3d11_interface.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_dynamic_factory.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_dynamic_factory.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_dynamic_factory_versions.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_encoded_frame.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_encoder.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_shared_dll.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_version.h"
|
||||
)
|
||||
set(NVENC_SOURCES ${NVENC_PUBLIC_SOURCES})
|
||||
|
||||
if(WIN32)
|
||||
set(NVENC_IMPLEMENTATION_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_base.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_d3d11.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_d3d11_native.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_d3d11_on_cuda.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_dynamic_factory_impl.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/nvenc/nvenc_utils.cpp"
|
||||
)
|
||||
|
||||
# Add a version-isolated NVENC implementation object library.
|
||||
# add_nvenc_sdk_implementation: args = `target_name`, `sdk_version`, `sdk_include_dir`
|
||||
function(add_nvenc_sdk_implementation target_name sdk_version sdk_include_dir)
|
||||
add_library(${target_name} OBJECT ${NVENC_IMPLEMENTATION_SOURCES})
|
||||
target_include_directories(${target_name} BEFORE PRIVATE "${sdk_include_dir}")
|
||||
target_compile_definitions(${target_name} PRIVATE
|
||||
NVENC_FACTORY_SUFFIX=${sdk_version}
|
||||
NVENC_NAMESPACE=nvenc_${sdk_version}
|
||||
NVENC_SDK_VERSION=${sdk_version}
|
||||
)
|
||||
target_compile_options(${target_name} PRIVATE ${SUNSHINE_COMPILE_OPTIONS})
|
||||
endfunction()
|
||||
|
||||
add_nvenc_sdk_implementation(nvenc_sdk_1100 1100 "${NV_CODEC_HEADERS_11_INCLUDE_DIR}")
|
||||
add_nvenc_sdk_implementation(nvenc_sdk_1200 1200 "${NV_CODEC_HEADERS_12_INCLUDE_DIR}")
|
||||
add_nvenc_sdk_implementation(nvenc_sdk_1300 1300 "${NV_CODEC_HEADERS_13_INCLUDE_DIR}")
|
||||
|
||||
list(APPEND NVENC_SOURCES
|
||||
$<TARGET_OBJECTS:nvenc_sdk_1100>
|
||||
$<TARGET_OBJECTS:nvenc_sdk_1200>
|
||||
$<TARGET_OBJECTS:nvenc_sdk_1300>
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND PLATFORM_TARGET_FILES ${NVENC_SOURCES})
|
||||
|
||||
set(SUNSHINE_TARGET_FILES
|
||||
@@ -152,6 +197,10 @@ include_directories(
|
||||
${Boost_INCLUDE_DIRS} # has to be the last, or we get runtime error on macOS ffmpeg encoder
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
include_directories(BEFORE SYSTEM "${NV_CODEC_HEADERS_13_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
|
||||
${MINIUPNP_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
|
||||
@@ -14,6 +14,13 @@ 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
|
||||
|
||||
# Qt's static qwindows plugin and MinGW's Windowsapp import library both provide the
|
||||
# UiaRaiseNotificationEvent import thunk on ARM64. Keep both required libraries while
|
||||
# permitting lld to coalesce their identical definitions.
|
||||
if(SUNSHINE_USE_STATIC_QT AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND SUNSHINE_LINK_OPTIONS -Wl,--allow-multiple-definition)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# see gcc bug 98723
|
||||
|
||||
+1379
File diff suppressed because it is too large
Load Diff
@@ -25,10 +25,53 @@ add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/lizardbyte-common")
|
||||
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/libdisplaydevice")
|
||||
|
||||
if(SUNSHINE_ENABLE_TRAY)
|
||||
if(SUNSHINE_USE_STATIC_QT)
|
||||
set(_sunshine_find_library_suffixes "${CMAKE_FIND_LIBRARY_SUFFIXES}")
|
||||
set(_sunshine_import_library_suffix "${CMAKE_IMPORT_LIBRARY_SUFFIX}")
|
||||
set(_sunshine_pkg_config_argn "${PKG_CONFIG_ARGN}")
|
||||
set(_sunshine_disable_find_package_harfbuzz "${CMAKE_DISABLE_FIND_PACKAGE_harfbuzz}")
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
set(CMAKE_IMPORT_LIBRARY_SUFFIX ".a")
|
||||
set(PKG_CONFIG_ARGN --static)
|
||||
|
||||
# HarfBuzz's config-file target omits dependencies needed by its static archive.
|
||||
# Use Qt's pkg-config fallback so --static supplies the complete link interface.
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_harfbuzz TRUE)
|
||||
|
||||
# CMake's FindTIFF module does not propagate dependencies of the static archive.
|
||||
# Provide its standard target from pkg-config before Qt imports the TIFF plugin.
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SUNSHINE_STATIC_TIFF REQUIRED IMPORTED_TARGET libtiff-4)
|
||||
add_library(TIFF::TIFF INTERFACE IMPORTED)
|
||||
target_link_libraries(TIFF::TIFF INTERFACE PkgConfig::SUNSHINE_STATIC_TIFF)
|
||||
|
||||
set(_sunshine_module_path "${CMAKE_MODULE_PATH}")
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Svg)
|
||||
get_target_property(_sunshine_qt_core_type Qt6::Core TYPE)
|
||||
if(NOT _sunshine_qt_core_type STREQUAL "STATIC_LIBRARY")
|
||||
message(FATAL_ERROR "SUNSHINE_USE_STATIC_QT requires a static Qt 6 installation.")
|
||||
endif()
|
||||
set(CMAKE_MODULE_PATH "${_sunshine_module_path}")
|
||||
endif()
|
||||
|
||||
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/tray")
|
||||
|
||||
if(SUNSHINE_USE_STATIC_QT)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES "${_sunshine_find_library_suffixes}")
|
||||
set(CMAKE_IMPORT_LIBRARY_SUFFIX "${_sunshine_import_library_suffix}")
|
||||
set(PKG_CONFIG_ARGN "${_sunshine_pkg_config_argn}")
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_harfbuzz "${_sunshine_disable_find_package_harfbuzz}")
|
||||
unset(_sunshine_disable_find_package_harfbuzz)
|
||||
unset(_sunshine_find_library_suffixes)
|
||||
unset(_sunshine_import_library_suffix)
|
||||
unset(_sunshine_module_path)
|
||||
unset(_sunshine_pkg_config_argn)
|
||||
unset(_sunshine_qt_core_type)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# common dependencies
|
||||
include("${CMAKE_MODULE_PATH}/dependencies/nv_codec_headers.cmake")
|
||||
include("${CMAKE_MODULE_PATH}/dependencies/nlohmann_json.cmake")
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
if(WIN32)
|
||||
CPMGetPackage(nv_codec_headers_13)
|
||||
CPMGetPackage(nv_codec_headers_11)
|
||||
CPMGetPackage(nv_codec_headers_12)
|
||||
|
||||
set(NV_CODEC_HEADERS_11_INCLUDE_DIR "${nv_codec_headers_11_SOURCE_DIR}/include")
|
||||
set(NV_CODEC_HEADERS_12_INCLUDE_DIR "${nv_codec_headers_12_SOURCE_DIR}/include")
|
||||
set(NV_CODEC_HEADERS_13_INCLUDE_DIR "${nv_codec_headers_13_SOURCE_DIR}/include")
|
||||
endif()
|
||||
@@ -29,6 +29,13 @@ foreach(asset ${ALL_ASSETS}) # Copy assets to build directory, excluding the we
|
||||
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/assets")
|
||||
endforeach()
|
||||
|
||||
# Copy the primary application icon into the built web assets for the system tray.
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/assets/web/images")
|
||||
configure_file(
|
||||
"${CMAKE_SOURCE_DIR}/sunshine.svg"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/assets/web/images/logo-sunshine.svg"
|
||||
COPYONLY)
|
||||
|
||||
# install built vite assets
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/assets/web"
|
||||
DESTINATION "${SUNSHINE_ASSETS_DIR}")
|
||||
|
||||
@@ -145,26 +145,12 @@ set(CPACK_RPM_PACKAGE_AUTOREQ ON)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/sunshine.svg"
|
||||
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps"
|
||||
RENAME "${PROJECT_FQDN}.svg")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/sunshine.svg"
|
||||
DESTINATION "${SUNSHINE_ASSETS_DIR}/web/images"
|
||||
RENAME "logo-sunshine.svg")
|
||||
|
||||
# tray icon
|
||||
if(${SUNSHINE_TRAY} STREQUAL 1)
|
||||
# Icons used by the Qt tray backend are no longer installed to the hicolor icon theme,
|
||||
# because Qt6 will not allow icons not part of the theme... so we will use icons from our web directory instead
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "\
|
||||
${CPACK_DEBIAN_PACKAGE_DEPENDS}, \
|
||||
libnotify4"
|
||||
)
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "\
|
||||
${CPACK_RPM_PACKAGE_REQUIRES}, \
|
||||
libnotify >= 0.8.0"
|
||||
)
|
||||
list(APPEND CPACK_FREEBSD_PACKAGE_DEPS
|
||||
devel/libnotify
|
||||
)
|
||||
if(TRAY_QT_VERSION EQUAL 6)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "\
|
||||
${CPACK_DEBIAN_PACKAGE_DEPENDS}, \
|
||||
@@ -177,7 +163,7 @@ if(${SUNSHINE_TRAY} STREQUAL 1)
|
||||
qt6-qtsvg"
|
||||
)
|
||||
list(APPEND CPACK_FREEBSD_PACKAGE_DEPS
|
||||
x11-toolkits/qt6-widgets
|
||||
devel/qt6-base
|
||||
graphics/qt6-svg
|
||||
)
|
||||
else()
|
||||
|
||||
@@ -22,6 +22,26 @@ else()
|
||||
BUNDLE DESTINATION .
|
||||
COMPONENT Runtime)
|
||||
|
||||
if(SUNSHINE_ENABLE_TRAY)
|
||||
# Import Qt in this directory so its deployment commands and targets are visible here.
|
||||
set(_sunshine_module_path "${CMAKE_MODULE_PATH}")
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
set(CMAKE_MODULE_PATH "${_sunshine_module_path}")
|
||||
unset(_sunshine_module_path)
|
||||
|
||||
qt6_generate_deploy_script(
|
||||
TARGET sunshine
|
||||
OUTPUT_SCRIPT SUNSHINE_QT_DEPLOY_SCRIPT
|
||||
CONTENT "
|
||||
qt6_deploy_runtime_dependencies(
|
||||
EXECUTABLE \"$<TARGET_FILE_NAME:sunshine>.app\"
|
||||
NO_APP_STORE_COMPLIANCE
|
||||
NO_TRANSLATIONS
|
||||
DEPLOY_TOOL_OPTIONS -no-codesign
|
||||
)")
|
||||
install(SCRIPT "${SUNSHINE_QT_DEPLOY_SCRIPT}" COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
install(FILES "${APPLE_PLIST_FILE}"
|
||||
DESTINATION "${MAC_BUNDLE_CONTENTS}"
|
||||
COMPONENT Runtime)
|
||||
@@ -44,6 +64,18 @@ else()
|
||||
message(STATUS \"Running fixup_bundle for: \${_app}\")
|
||||
include(BundleUtilities)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS TRUE)
|
||||
|
||||
# Resolve @rpath items that Qt already deployed into the app bundle.
|
||||
function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var)
|
||||
if(\"\${item}\" MATCHES \"^@rpath/(.+)$\")
|
||||
set(_embedded_item \"\${_app}/Contents/Frameworks/\${CMAKE_MATCH_1}\")
|
||||
if(EXISTS \"\${_embedded_item}\")
|
||||
set(\${resolved_item_var} \"\${_embedded_item}\" PARENT_SCOPE)
|
||||
set(\${resolved_var} TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
fixup_bundle(\"\${_app}\" \"\" \"\")
|
||||
|
||||
# Remove Finder/resource-fork metadata that breaks codesign.
|
||||
@@ -61,12 +93,13 @@ else()
|
||||
|
||||
# SHOULD_SIGN is set only when publish_release is true or when manually building
|
||||
if(\"\$ENV{SHOULD_SIGN}\" STREQUAL \"true\")
|
||||
# Sign anything inside Contents/Frameworks
|
||||
# Sign bundled frameworks and plugins before signing the app itself.
|
||||
set(_fw_dir \"\${_app}/Contents/Frameworks\")
|
||||
if(EXISTS \"\${_fw_dir}\")
|
||||
file(GLOB_RECURSE _sign_items
|
||||
\"\${_fw_dir}/*.framework\"
|
||||
\"\${_fw_dir}/*.dylib\"
|
||||
\"\${_app}/Contents/PlugIns/*.dylib\"
|
||||
)
|
||||
|
||||
foreach(item IN LISTS _sign_items)
|
||||
|
||||
@@ -18,6 +18,11 @@ option(SUNSHINE_CONFIGURE_ONLY "Configure special files only, then exit." OFF)
|
||||
|
||||
option(SUNSHINE_ENABLE_TRAY "Enable system tray icon." ON)
|
||||
|
||||
if(WIN32)
|
||||
option(SUNSHINE_USE_STATIC_QT
|
||||
"Require static Qt libraries and their static third-party dependencies." OFF)
|
||||
endif()
|
||||
|
||||
option(SUNSHINE_SYSTEM_VULKAN_HEADERS "Use system installation of vulkan-headers rather than the submodule." OFF)
|
||||
option(SUNSHINE_SYSTEM_WAYLAND_PROTOCOLS "Use system installation of wayland-protocols rather than the submodule." OFF)
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ apt-get install -y --no-install-recommends \
|
||||
libevdev-dev \
|
||||
libgbm-dev \
|
||||
libminiupnpc-dev \
|
||||
libnotify-dev \
|
||||
libnuma-dev \
|
||||
libopus-dev \
|
||||
libpulse-dev \
|
||||
|
||||
+13
-1
@@ -27,7 +27,6 @@ pkg install -y \
|
||||
devel/evdev-proto \
|
||||
devel/git \
|
||||
devel/libevdev \
|
||||
devel/libnotify \
|
||||
devel/llvm19 \
|
||||
devel/ninja \
|
||||
devel/pkgconf \
|
||||
@@ -102,6 +101,8 @@ dependencies=(
|
||||
"openssl@3"
|
||||
"opus"
|
||||
"pkg-config"
|
||||
"qtbase"
|
||||
"qtsvg"
|
||||
)
|
||||
brew install "${dependencies[@]}"
|
||||
```
|
||||
@@ -130,6 +131,8 @@ dependencies=(
|
||||
"ninja"
|
||||
"npm9"
|
||||
"pkgconfig"
|
||||
"qt6-qtbase"
|
||||
"qt6-qtsvg"
|
||||
)
|
||||
sudo port install "${dependencies[@]}"
|
||||
```
|
||||
@@ -174,6 +177,7 @@ dependencies=(
|
||||
"mingw-w64-${TOOLCHAIN}-openssl"
|
||||
"mingw-w64-${TOOLCHAIN}-opus"
|
||||
"mingw-w64-${TOOLCHAIN}-toolchain"
|
||||
"mingw-w64-${TOOLCHAIN}-qt6-static"
|
||||
)
|
||||
if [[ "${MSYSTEM}" == "UCRT64" ]]; then
|
||||
dependencies+=(
|
||||
@@ -185,6 +189,14 @@ fi
|
||||
pacman -S "${dependencies[@]}"
|
||||
```
|
||||
|
||||
The static Qt package is installed under a separate prefix. Add the following options when configuring a Windows
|
||||
build so Sunshine and Qt's third-party dependencies are linked statically:
|
||||
|
||||
```bash
|
||||
-DCMAKE_PREFIX_PATH="${MINGW_PREFIX}/qt6-static" \
|
||||
-DSUNSHINE_USE_STATIC_QT=ON
|
||||
```
|
||||
|
||||
To create a WiX installer, you also need to install [.NET](https://dotnet.microsoft.com/download).
|
||||
|
||||
For ARM64: To build frontend, you also need to install [Node.JS](https://nodejs.org/en/download)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# CPM Package Lock
|
||||
# This file should be committed to version control
|
||||
|
||||
# The first argument of CPMDeclarePackage can be freely chosen and is used as argument in CPMGetPackage.
|
||||
# The NAME argument should be package name that would also be used in a find_package call.
|
||||
# Ideally, both are the same, which might not always be possible: https://github.com/cpm-cmake/CPM.cmake/issues/603
|
||||
# This is needed to support CPM_USE_LOCAL_PACKAGES
|
||||
|
||||
# Renovate-bot will update the versions and hashes in this file when a new version of a dependency is released.
|
||||
# The comments above each dependency are used by renovate to identify the dependencies and extract the version numbers.
|
||||
# See https://github.com/LizardByte/.github/blob/master/renovate-config.json5 for the configuration of renovate.
|
||||
#
|
||||
# Expected dependency structure for new entries:
|
||||
# - Start each block with a human-readable comment, for example `# Example dependency`.
|
||||
# - Follow it with consecutive renovate metadata comments.
|
||||
# - The first metadata line must start with `# renovate:` and include `datasource=` and `depName=`.
|
||||
# - Optional metadata keys are `packageName=`, `versioning=`, `extractVersion=`, and `registryUrl=`.
|
||||
# - Optional metadata may stay on the `# renovate:` line or continue on the next consecutive `#` lines.
|
||||
# - Keep metadata keys in this order: `datasource`, `depName`, `packageName`, `versioning`,
|
||||
# `extractVersion`, `registryUrl`.
|
||||
# - After metadata, declare the tracked value with `set(NAME_VERSION ...)` or `set(NAME_TAG ...)`.
|
||||
# - If the dependency also tracks a SHA256, keep `set(NAME_SHA256 ...)` immediately after the
|
||||
# matching `NAME_VERSION` or `NAME_TAG` line with no unrelated lines between them.
|
||||
# - Keep `CPMDeclarePackage(...)` below the tracked values.
|
||||
#
|
||||
# Example layout:
|
||||
# - `# Example dependency`
|
||||
# - `# renovate: datasource=github-tags depName=owner/repo`
|
||||
# - `# versioning=regex:^v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$`
|
||||
# - `set(EXAMPLE_TAG v1.2.3)`
|
||||
# - `set(EXAMPLE_SHA256 <sha256>)`
|
||||
# - `CPMDeclarePackage(...)`
|
||||
|
||||
set(PATCH_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/patches")
|
||||
|
||||
# NVENC SDK 11.0 headers
|
||||
# renovate: datasource=github-tags depName=FFmpeg/nv-codec-headers
|
||||
# versioning=regex:^n(?<major>11)\.(?<minor>0)\.(?<patch>\d+)\.(?<build>\d+)$
|
||||
set(NV_CODEC_HEADERS_11_TAG n11.0.10.3)
|
||||
CPMDeclarePackage(nv_codec_headers_11
|
||||
NAME nv_codec_headers_11
|
||||
GIT_REPOSITORY https://github.com/FFmpeg/nv-codec-headers.git
|
||||
GIT_TAG ${NV_CODEC_HEADERS_11_TAG}
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
# NVENC SDK 12.0 headers
|
||||
# renovate: datasource=github-tags depName=FFmpeg/nv-codec-headers
|
||||
# versioning=regex:^n(?<major>12)\.(?<minor>0)\.(?<patch>\d+)\.(?<build>\d+)$
|
||||
set(NV_CODEC_HEADERS_12_TAG n12.0.16.2)
|
||||
CPMDeclarePackage(nv_codec_headers_12
|
||||
NAME nv_codec_headers_12
|
||||
GIT_REPOSITORY https://github.com/FFmpeg/nv-codec-headers.git
|
||||
GIT_TAG ${NV_CODEC_HEADERS_12_TAG}
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
# NVENC SDK 13.0 headers
|
||||
# renovate: datasource=github-tags depName=FFmpeg/nv-codec-headers
|
||||
# versioning=regex:^n(?<major>13)\.(?<minor>0)\.(?<patch>\d+)\.(?<build>\d+)$
|
||||
set(NV_CODEC_HEADERS_13_TAG n13.0.19.1)
|
||||
CPMDeclarePackage(nv_codec_headers_13
|
||||
NAME nv_codec_headers_13
|
||||
GIT_REPOSITORY https://github.com/FFmpeg/nv-codec-headers.git
|
||||
GIT_TAG ${NV_CODEC_HEADERS_13_TAG}
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
Generated
+141
-141
@@ -8,12 +8,12 @@
|
||||
"name": "sunshine",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@lucide/vue": "1.26.0",
|
||||
"@lucide/vue": "1.27.0",
|
||||
"bootstrap": "5.3.8",
|
||||
"date-fns": "4.4.0",
|
||||
"marked": "18.0.7",
|
||||
"vue": "3.5.40",
|
||||
"vue-i18n": "11.4.7",
|
||||
"vue-i18n": "11.4.8",
|
||||
"vue3-simple-icons": "16.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -614,14 +614,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/core-base": {
|
||||
"version": "11.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.4.7.tgz",
|
||||
"integrity": "sha512-MSB/sBKwEWJTILvQIhg2rnIcwPpLayo3wGwvVA+dJTNeUBD9GoqQgAaSOLdI9iOPDHCm9YoVnLqpfzza98MpkQ==",
|
||||
"version": "11.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.4.8.tgz",
|
||||
"integrity": "sha512-A+Q7SKm5oEcy1E/cghqd7n/St4XjTqLhiiyDuieNcMrJcrHlkY5n0jp7Q9dD3txvVHzvsmBVV5M9wD5/s1zfzw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@intlify/devtools-types": "11.4.7",
|
||||
"@intlify/message-compiler": "11.4.7",
|
||||
"@intlify/shared": "11.4.7"
|
||||
"@intlify/devtools-types": "11.4.8",
|
||||
"@intlify/message-compiler": "11.4.8",
|
||||
"@intlify/shared": "11.4.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 22"
|
||||
@@ -631,13 +631,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/devtools-types": {
|
||||
"version": "11.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.4.7.tgz",
|
||||
"integrity": "sha512-GSz+J+hqH+AEpAHIYya6fSufS30OaMnG39HiZX7DmGKi3+aaLvassCfsXENEc4Wr4m68q2YP0QdMdB3D9UeAXg==",
|
||||
"version": "11.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.4.8.tgz",
|
||||
"integrity": "sha512-MGpID+rlfzGUbNcnC20bm5NMSBHPrvx0atLTfv9dftn3kjXw1hGKDcIcwrO99tSrZEc2i+hczRL7ks8qXsHPkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@intlify/core-base": "11.4.7",
|
||||
"@intlify/shared": "11.4.7"
|
||||
"@intlify/core-base": "11.4.8",
|
||||
"@intlify/shared": "11.4.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 22"
|
||||
@@ -647,12 +647,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/message-compiler": {
|
||||
"version": "11.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.4.7.tgz",
|
||||
"integrity": "sha512-bHxmh7n94N4N1evADeb7XTkc3jTw6Ki5biMFZVSX6Jmk+iehy8/maeH2XUsBI27rtKIK+Hzc6QnVAKggUwylKw==",
|
||||
"version": "11.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.4.8.tgz",
|
||||
"integrity": "sha512-vbzk17dYwduYiv52EK61+FDCyhfVg1uPUtPmiD/d45W99uJIcXywrweOBcHv7n9/iEqmXiMGT52bgJbZDQqK3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@intlify/shared": "11.4.7",
|
||||
"@intlify/shared": "11.4.8",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -663,9 +663,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/shared": {
|
||||
"version": "11.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.4.7.tgz",
|
||||
"integrity": "sha512-OtjPZan3No2OZZFnMUiCVsXC6+j+XRwEywaFDk0AoayAbLuPesyDloXhJZLl9JUl5vHZeQUkYSbEA8VX+CWMjg==",
|
||||
"version": "11.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.4.8.tgz",
|
||||
"integrity": "sha512-XbRgrv+XEuvDr7UCY55oibVrh+o4u+A0VB6nSL0F5Z8LcZxE/8j573LYG6bCrOigIcHdGpSNI7Rh5UpC5/B/eg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 22"
|
||||
@@ -681,9 +681,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@lucide/vue": {
|
||||
"version": "1.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@lucide/vue/-/vue-1.26.0.tgz",
|
||||
"integrity": "sha512-jz00zLm8+i7VzBuQTbmjChIvIKehaIK5YbOVC+bab7qTh4JTkCd0XJQ4l5TY57gT08fMPVlvUITROB/vm/xImA==",
|
||||
"version": "1.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@lucide/vue/-/vue-1.27.0.tgz",
|
||||
"integrity": "sha512-LKDEZJ0Uo9UaT4vxBMYVwXeK/0dGcWCTdav1AK/aGD/jYsDPtiVvOgfM7jPlx9BVeyGZ1Uf0aQhHA++rmbe7rw==",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"vue": ">=3.0.1"
|
||||
@@ -846,9 +846,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
|
||||
"integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.3.tgz",
|
||||
"integrity": "sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -860,9 +860,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz",
|
||||
"integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.3.tgz",
|
||||
"integrity": "sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -874,9 +874,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz",
|
||||
"integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.3.tgz",
|
||||
"integrity": "sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -888,9 +888,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz",
|
||||
"integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.3.tgz",
|
||||
"integrity": "sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -902,9 +902,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz",
|
||||
"integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.3.tgz",
|
||||
"integrity": "sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -916,9 +916,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz",
|
||||
"integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.3.tgz",
|
||||
"integrity": "sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -930,9 +930,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz",
|
||||
"integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.3.tgz",
|
||||
"integrity": "sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -947,9 +947,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz",
|
||||
"integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.3.tgz",
|
||||
"integrity": "sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -964,9 +964,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz",
|
||||
"integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.3.tgz",
|
||||
"integrity": "sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -981,9 +981,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz",
|
||||
"integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.3.tgz",
|
||||
"integrity": "sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -998,9 +998,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz",
|
||||
"integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.3.tgz",
|
||||
"integrity": "sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1015,9 +1015,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz",
|
||||
"integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.3.tgz",
|
||||
"integrity": "sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1032,9 +1032,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz",
|
||||
"integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.3.tgz",
|
||||
"integrity": "sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1049,9 +1049,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz",
|
||||
"integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.3.tgz",
|
||||
"integrity": "sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1066,9 +1066,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz",
|
||||
"integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.3.tgz",
|
||||
"integrity": "sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1083,9 +1083,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz",
|
||||
"integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.3.tgz",
|
||||
"integrity": "sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1100,9 +1100,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz",
|
||||
"integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.3.tgz",
|
||||
"integrity": "sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1117,9 +1117,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz",
|
||||
"integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.3.tgz",
|
||||
"integrity": "sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1134,9 +1134,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz",
|
||||
"integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.3.tgz",
|
||||
"integrity": "sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1151,9 +1151,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz",
|
||||
"integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.3.tgz",
|
||||
"integrity": "sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1165,9 +1165,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz",
|
||||
"integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.3.tgz",
|
||||
"integrity": "sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1179,9 +1179,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz",
|
||||
"integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.3.tgz",
|
||||
"integrity": "sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1193,9 +1193,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz",
|
||||
"integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.3.tgz",
|
||||
"integrity": "sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1207,9 +1207,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz",
|
||||
"integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.3.tgz",
|
||||
"integrity": "sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1221,9 +1221,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz",
|
||||
"integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.3.tgz",
|
||||
"integrity": "sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1370,9 +1370,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.17.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
|
||||
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
|
||||
"integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -2319,9 +2319,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.20",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.20.tgz",
|
||||
"integrity": "sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==",
|
||||
"version": "8.5.24",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.24.tgz",
|
||||
"integrity": "sha512-8RyVklq0owXUTa4xlpzu4l9AaVKIdQvAcOHZWaMh98HgySsUtxRVf/chRe3dsSLqb6i40BzGRzEUddRaI+9TSw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -2407,9 +2407,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.62.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz",
|
||||
"integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==",
|
||||
"version": "4.62.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.3.tgz",
|
||||
"integrity": "sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2423,31 +2423,31 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.62.2",
|
||||
"@rollup/rollup-android-arm64": "4.62.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.62.2",
|
||||
"@rollup/rollup-darwin-x64": "4.62.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.62.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.62.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.62.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.62.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.62.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.62.2",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.62.2",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.62.2",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.62.2",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.62.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.62.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.62.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.62.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.62.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.62.2",
|
||||
"@rollup/rollup-openbsd-x64": "4.62.2",
|
||||
"@rollup/rollup-openharmony-arm64": "4.62.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.62.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.62.2",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.62.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.62.2",
|
||||
"@rollup/rollup-android-arm-eabi": "4.62.3",
|
||||
"@rollup/rollup-android-arm64": "4.62.3",
|
||||
"@rollup/rollup-darwin-arm64": "4.62.3",
|
||||
"@rollup/rollup-darwin-x64": "4.62.3",
|
||||
"@rollup/rollup-freebsd-arm64": "4.62.3",
|
||||
"@rollup/rollup-freebsd-x64": "4.62.3",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.62.3",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.62.3",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.62.3",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.62.3",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.62.3",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.62.3",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.62.3",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.62.3",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.62.3",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.62.3",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.62.3",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.62.3",
|
||||
"@rollup/rollup-linux-x64-musl": "4.62.3",
|
||||
"@rollup/rollup-openbsd-x64": "4.62.3",
|
||||
"@rollup/rollup-openharmony-arm64": "4.62.3",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.62.3",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.62.3",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.62.3",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.62.3",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -2697,9 +2697,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.27.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz",
|
||||
"integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==",
|
||||
"version": "6.28.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
|
||||
"integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2856,14 +2856,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-i18n": {
|
||||
"version": "11.4.7",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.4.7.tgz",
|
||||
"integrity": "sha512-j6RyshdPPzqLiMAUpnpvZGFPM+rRoWi14Sl5yTsquvoW0/56DWyvhAj2o9TO2YXGvb6teg8T0xrYO9jR3urvdw==",
|
||||
"version": "11.4.8",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.4.8.tgz",
|
||||
"integrity": "sha512-0ULeHP6Z9CGvAm67S77ZEp41cfGXIREGL8qfhos2BMgcQQewtQcDKuojt6jjasAD/S8GwfTp2ySPmDSpwvrCMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@intlify/core-base": "11.4.7",
|
||||
"@intlify/devtools-types": "11.4.7",
|
||||
"@intlify/shared": "11.4.7",
|
||||
"@intlify/core-base": "11.4.8",
|
||||
"@intlify/devtools-types": "11.4.8",
|
||||
"@intlify/shared": "11.4.8",
|
||||
"@vue/devtools-api": "^6.5.0"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
+2
-2
@@ -9,12 +9,12 @@
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@lucide/vue": "1.26.0",
|
||||
"@lucide/vue": "1.27.0",
|
||||
"bootstrap": "5.3.8",
|
||||
"date-fns": "4.4.0",
|
||||
"marked": "18.0.7",
|
||||
"vue": "3.5.40",
|
||||
"vue-i18n": "11.4.7",
|
||||
"vue-i18n": "11.4.8",
|
||||
"vue3-simple-icons": "16.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -39,7 +39,6 @@ depends=(
|
||||
'libdrm'
|
||||
'libevdev'
|
||||
'libmfx'
|
||||
'libnotify'
|
||||
'libpipewire'
|
||||
'libpulse'
|
||||
'libva'
|
||||
@@ -75,6 +74,7 @@ makedepends=(
|
||||
|
||||
checkdepends=(
|
||||
'gcovr'
|
||||
'imagemagick'
|
||||
)
|
||||
|
||||
optdepends=(
|
||||
|
||||
@@ -31,7 +31,6 @@ BuildRequires: libcap-devel
|
||||
BuildRequires: libcurl-devel
|
||||
BuildRequires: libdrm-devel
|
||||
BuildRequires: libevdev-devel
|
||||
BuildRequires: libnotify-devel >= 0.8.0
|
||||
BuildRequires: libva-devel
|
||||
BuildRequires: libX11-devel
|
||||
BuildRequires: libxcb-devel
|
||||
@@ -75,6 +74,7 @@ BuildRequires: systemd-udev
|
||||
BuildRequires: uv
|
||||
%{?sysusers_requires_compat}
|
||||
# for unit tests
|
||||
BuildRequires: ImageMagick
|
||||
BuildRequires: xorg-x11-server-Xvfb
|
||||
%endif
|
||||
|
||||
@@ -100,6 +100,7 @@ BuildRequires: udev
|
||||
BuildRequires: vulkan-devel
|
||||
%endif
|
||||
# for unit tests
|
||||
BuildRequires: ImageMagick
|
||||
BuildRequires: xvfb-run
|
||||
%endif
|
||||
|
||||
@@ -152,7 +153,6 @@ BuildRequires: libqt6-qtsvg-devel
|
||||
%global cuda_dir %{_builddir}/cuda
|
||||
|
||||
# Common runtime requirements
|
||||
Requires: libnotify >= 0.8.0
|
||||
Requires: miniupnpc >= 2.2.4
|
||||
Requires: which >= 2.21
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ cleanup:
|
||||
|
||||
modules:
|
||||
# Test dependencies
|
||||
- "modules/imagemagick.json"
|
||||
- "modules/xvfb/xvfb.json"
|
||||
|
||||
# Build dependencies
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://github.com/LizardByte/build-deps/releases/download/v2026.713.132551/Linux-x86_64-ffmpeg.tar.gz",
|
||||
"sha256": "66512409857d7c11c18875193c098a5131baec060169c8f8e6397387e7a1af7d",
|
||||
"url": "https://github.com/LizardByte/build-deps/releases/download/v2026.724.203728/Linux-x86_64-ffmpeg.tar.gz",
|
||||
"sha256": "2c27d4694b4ed0e734f497d4bd62f1b3662cbbc4ded2a69f2dc4b703441eebb3",
|
||||
"dest-filename": "ffmpeg.tar.gz",
|
||||
"only-arches": [
|
||||
"x86_64"
|
||||
@@ -23,8 +23,8 @@
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"url": "https://github.com/LizardByte/build-deps/releases/download/v2026.713.132551/Linux-aarch64-ffmpeg.tar.gz",
|
||||
"sha256": "2bdcfa663bb7a1b241a47665c94aa288ef2ec40c6a212cc0a8ec63904b886c6d",
|
||||
"url": "https://github.com/LizardByte/build-deps/releases/download/v2026.724.203728/Linux-aarch64-ffmpeg.tar.gz",
|
||||
"sha256": "fd6492f55d79ae178db97e48d6395b4cac2a2e10b2f157b0d40355cfd7c160e8",
|
||||
"dest-filename": "ffmpeg.tar.gz",
|
||||
"only-arches": [
|
||||
"aarch64"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "imagemagick",
|
||||
"cleanup": [
|
||||
"*"
|
||||
],
|
||||
"config-opts": [
|
||||
"--disable-docs",
|
||||
"--disable-static",
|
||||
"--with-modules=no",
|
||||
"--with-perl=no",
|
||||
"--with-x"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://download.imagemagick.org/archive/releases/ImageMagick-7.1.2-29.tar.xz",
|
||||
"sha256": "bab096dc4b3089be4c0ebfdb90a232b85b7d982a99f722b30512fb243ea1e4ce"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -58,6 +58,8 @@ class Sunshine < Formula
|
||||
depends_on "miniupnpc"
|
||||
depends_on "openssl@3"
|
||||
depends_on "opus"
|
||||
depends_on "qtbase"
|
||||
depends_on "qtsvg"
|
||||
|
||||
on_sonoma do
|
||||
depends_on xcode: ["16.2", :build] # required for jthreads on macos-14
|
||||
@@ -68,6 +70,7 @@ class Sunshine < Formula
|
||||
depends_on "gcovr" => [:build, :test]
|
||||
depends_on "lizardbyte/homebrew/#{CUDA_FORMULA}" => :build
|
||||
depends_on "python3" => :build
|
||||
depends_on "imagemagick" => :test
|
||||
depends_on "at-spi2-core"
|
||||
depends_on "avahi"
|
||||
depends_on "cairo"
|
||||
@@ -78,7 +81,6 @@ class Sunshine < Formula
|
||||
depends_on "libcap"
|
||||
depends_on "libdrm"
|
||||
depends_on "libice"
|
||||
depends_on "libnotify"
|
||||
depends_on "libsm"
|
||||
depends_on "libva"
|
||||
depends_on "libx11"
|
||||
@@ -95,8 +97,6 @@ class Sunshine < Formula
|
||||
depends_on "pango"
|
||||
depends_on "pipewire"
|
||||
depends_on "pulseaudio"
|
||||
depends_on "qtbase"
|
||||
depends_on "qtsvg"
|
||||
depends_on "shaderc"
|
||||
depends_on "systemd"
|
||||
depends_on "vulkan-loader"
|
||||
|
||||
@@ -283,7 +283,6 @@ function add_arch_deps() {
|
||||
'libdrm'
|
||||
'libevdev'
|
||||
'libmfx'
|
||||
'libnotify'
|
||||
'libpulse'
|
||||
'libva'
|
||||
'libx11'
|
||||
@@ -337,13 +336,13 @@ function add_debian_based_deps() {
|
||||
"git"
|
||||
"glslang-tools" # Vulkan shader compiler
|
||||
"graphviz"
|
||||
"imagemagick" # necessary for system tray screenshots in unit tests
|
||||
"libcap-dev" # KMS
|
||||
"libcurl4-openssl-dev"
|
||||
"libdrm-dev" # KMS
|
||||
"libevdev-dev"
|
||||
"libgbm-dev"
|
||||
"libminiupnpc-dev"
|
||||
"libnotify-dev"
|
||||
"libnuma-dev"
|
||||
"libopus-dev"
|
||||
"libpipewire-0.3-dev"
|
||||
@@ -443,12 +442,12 @@ function add_fedora_deps() {
|
||||
"git"
|
||||
"glslc"
|
||||
"graphviz"
|
||||
"ImageMagick" # necessary for system tray screenshots in unit tests
|
||||
"libappstream-glib"
|
||||
"libcap-devel"
|
||||
"libcurl-devel"
|
||||
"libdrm-devel"
|
||||
"libevdev-devel"
|
||||
"libnotify-devel"
|
||||
"libX11-devel" # X11
|
||||
"libxcb-devel" # X11
|
||||
"libXcursor-devel" # X11
|
||||
|
||||
@@ -37,6 +37,8 @@ required_formulas=(
|
||||
"openssl@3"
|
||||
"opus"
|
||||
"llvm"
|
||||
"qtbase"
|
||||
"qtsvg"
|
||||
)
|
||||
|
||||
function _usage() {
|
||||
|
||||
@@ -535,13 +535,11 @@ namespace display_device {
|
||||
std::optional<parsed_remapping_entry_t> parse_remapping_entry(const config::video_t::dd_t::mode_remapping_entry_t &entry, const remapping_type_e type) {
|
||||
parsed_remapping_entry_t result {};
|
||||
|
||||
if (is_resolution_mapped(type) && (!parse_resolution_string(entry.requested_resolution, result.requested_resolution) ||
|
||||
!parse_resolution_string(entry.final_resolution, result.final_resolution))) {
|
||||
if (is_resolution_mapped(type) && (!parse_resolution_string(entry.requested_resolution, result.requested_resolution) || !parse_resolution_string(entry.final_resolution, result.final_resolution))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (is_fps_mapped(type) && (!parse_refresh_rate_string(entry.requested_fps, result.requested_fps, false) ||
|
||||
!parse_refresh_rate_string(entry.final_refresh_rate, result.final_refresh_rate))) {
|
||||
if (is_fps_mapped(type) && (!parse_refresh_rate_string(entry.requested_fps, result.requested_fps, false) || !parse_refresh_rate_string(entry.final_refresh_rate, result.final_refresh_rate))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -63,8 +63,7 @@ namespace http {
|
||||
config::nvhttp.pkey = (dir / ("pkey-"s + unique_id)).string();
|
||||
}
|
||||
|
||||
if ((!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) &&
|
||||
create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
|
||||
if ((!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) && create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
|
||||
return -1;
|
||||
}
|
||||
if (!user_creds_exist(config::sunshine.credentials_file)) {
|
||||
|
||||
+6
-12
@@ -935,8 +935,7 @@ namespace input {
|
||||
|
||||
// Right-alt maps to meta, so it must not also register as ALT
|
||||
int modifiers = packet->modifiers;
|
||||
if (config::input.key_rightalt_to_key_win &&
|
||||
input->right_alt_pressed && !input->left_alt_pressed) {
|
||||
if (config::input.key_rightalt_to_key_win && input->right_alt_pressed && !input->left_alt_pressed) {
|
||||
modifiers &= ~MODIFIER_ALT;
|
||||
}
|
||||
|
||||
@@ -1557,14 +1556,12 @@ namespace input {
|
||||
*/
|
||||
batch_result_e batch(PSS_TOUCH_PACKET dest, PSS_TOUCH_PACKET src) {
|
||||
// Only batch hover or move events
|
||||
if (dest->eventType != LI_TOUCH_EVENT_MOVE &&
|
||||
dest->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
if (dest->eventType != LI_TOUCH_EVENT_MOVE && dest->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
return batch_result_e::terminate_batch;
|
||||
}
|
||||
|
||||
// Don't batch beyond state changing events
|
||||
if (src->eventType != LI_TOUCH_EVENT_MOVE &&
|
||||
src->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
if (src->eventType != LI_TOUCH_EVENT_MOVE && src->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
return batch_result_e::terminate_batch;
|
||||
}
|
||||
|
||||
@@ -1591,8 +1588,7 @@ namespace input {
|
||||
*/
|
||||
batch_result_e batch(PSS_PEN_PACKET dest, PSS_PEN_PACKET src) {
|
||||
// Only batch hover or move events
|
||||
if (dest->eventType != LI_TOUCH_EVENT_MOVE &&
|
||||
dest->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
if (dest->eventType != LI_TOUCH_EVENT_MOVE && dest->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
return batch_result_e::terminate_batch;
|
||||
}
|
||||
|
||||
@@ -1624,8 +1620,7 @@ namespace input {
|
||||
*/
|
||||
batch_result_e batch(PSS_CONTROLLER_TOUCH_PACKET dest, PSS_CONTROLLER_TOUCH_PACKET src) {
|
||||
// Only batch hover or move events
|
||||
if (dest->eventType != LI_TOUCH_EVENT_MOVE &&
|
||||
dest->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
if (dest->eventType != LI_TOUCH_EVENT_MOVE && dest->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
return batch_result_e::terminate_batch;
|
||||
}
|
||||
|
||||
@@ -1636,8 +1631,7 @@ namespace input {
|
||||
}
|
||||
|
||||
// Don't batch beyond state changing events
|
||||
if (src->eventType != LI_TOUCH_EVENT_MOVE &&
|
||||
src->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
if (src->eventType != LI_TOUCH_EVENT_MOVE && src->eventType != LI_TOUCH_EVENT_HOVER) {
|
||||
return batch_result_e::terminate_batch;
|
||||
}
|
||||
|
||||
|
||||
+528
-395
File diff suppressed because it is too large
Load Diff
+202
-11
@@ -4,32 +4,33 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// lib includes
|
||||
#include <ffnvcodec/nvEncodeAPI.h>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_colorspace.h"
|
||||
#include "nvenc_config.h"
|
||||
#include "nvenc_encoded_frame.h"
|
||||
#include "nvenc_encoder.h"
|
||||
#include "nvenc_sdk.h"
|
||||
#include "src/logging.h"
|
||||
#include "src/video.h"
|
||||
#include "src/video_colorspace.h"
|
||||
|
||||
/**
|
||||
* @brief Standalone NVENC encoder
|
||||
*/
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
/**
|
||||
* @brief Abstract platform-agnostic base of standalone NVENC encoder.
|
||||
* Derived classes perform platform-specific operations.
|
||||
*/
|
||||
class nvenc_base {
|
||||
// Virtual inheritance is required because platform implementations also inherit their SDK-neutral interface.
|
||||
class nvenc_base: public virtual ::nvenc::nvenc_encoder { // NOSONAR(cpp:S1011)
|
||||
public:
|
||||
/**
|
||||
* @param device_type Underlying device type used by derived class.
|
||||
*/
|
||||
explicit nvenc_base(NV_ENC_DEVICE_TYPE device_type);
|
||||
virtual ~nvenc_base();
|
||||
~nvenc_base() override;
|
||||
|
||||
nvenc_base(const nvenc_base &) = delete;
|
||||
nvenc_base &operator=(const nvenc_base &) = delete;
|
||||
@@ -42,13 +43,18 @@ namespace nvenc {
|
||||
* @param buffer_format Platform-agnostic input surface format.
|
||||
* @return `true` on success, `false` on error
|
||||
*/
|
||||
bool create_encoder(const nvenc_config &config, const video::config_t &client_config, const nvenc_colorspace_t &colorspace, NV_ENC_BUFFER_FORMAT buffer_format);
|
||||
bool create_encoder(
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
const video::sunshine_colorspace_t &colorspace,
|
||||
platf::pix_fmt_e buffer_format
|
||||
) override;
|
||||
|
||||
/**
|
||||
* @brief Destroy the encoder.
|
||||
* Derived classes classes call it in the destructor.
|
||||
*/
|
||||
void destroy_encoder();
|
||||
void destroy_encoder() override;
|
||||
|
||||
/**
|
||||
* @brief Encode the next frame using platform-specific input surface.
|
||||
@@ -58,7 +64,7 @@ namespace nvenc {
|
||||
* @param force_idr Whether to encode frame as forced IDR.
|
||||
* @return Encoded frame.
|
||||
*/
|
||||
nvenc_encoded_frame encode_frame(uint64_t frame_index, bool force_idr);
|
||||
::nvenc::nvenc_encoded_frame encode_frame(uint64_t frame_index, bool force_idr) override;
|
||||
|
||||
/**
|
||||
* @brief Perform reference frame invalidation (RFI) procedure.
|
||||
@@ -67,7 +73,7 @@ namespace nvenc {
|
||||
* @return `true` on success, `false` on error.
|
||||
* After error next frame must be encoded with `force_idr = true`.
|
||||
*/
|
||||
bool invalidate_ref_frames(uint64_t first_frame, uint64_t last_frame);
|
||||
bool invalidate_ref_frames(uint64_t first_frame, uint64_t last_frame) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -137,6 +143,191 @@ namespace nvenc {
|
||||
///< Can be set in constructor or `init_library()`, must override `wait_for_async_event()`.
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Query one encoder capability.
|
||||
*
|
||||
* @param encode_guid Codec GUID to query.
|
||||
* @param cap Capability identifier.
|
||||
* @return Capability value, or zero when the query fails.
|
||||
*/
|
||||
int get_encoder_cap(const GUID &encode_guid, NV_ENC_CAPS cap) const;
|
||||
|
||||
/**
|
||||
* @brief Validate the requested input format and dimensions against encoder capabilities.
|
||||
*
|
||||
* @param encode_guid Selected codec GUID.
|
||||
* @param buffer_format Selected NVENC input format.
|
||||
* @return `true` when the request is supported, otherwise `false`.
|
||||
*/
|
||||
bool validate_encoder_capabilities(const GUID &encode_guid, NV_ENC_BUFFER_FORMAT buffer_format);
|
||||
|
||||
/**
|
||||
* @brief Configure split-frame encoding for the selected SDK.
|
||||
*
|
||||
* @param init_params Encoder initialization parameters to update.
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
*/
|
||||
void configure_split_frame(
|
||||
NV_ENC_INITIALIZE_PARAMS &init_params,
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Configure rate control and VBV options.
|
||||
*
|
||||
* @param enc_config Encoder configuration to update.
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param encode_guid Selected codec GUID.
|
||||
*/
|
||||
void configure_rate_control(
|
||||
NV_ENC_CONFIG &enc_config,
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
const GUID &encode_guid
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Configure the requested reference-frame count.
|
||||
*
|
||||
* @param ref_frames_option Codec-specific reference-frame option.
|
||||
* @param list0_option Codec-specific list-zero option.
|
||||
* @param default_count Default reference-frame count.
|
||||
* @param requested_count Client-requested reference-frame count.
|
||||
* @param encode_guid Selected codec GUID.
|
||||
*/
|
||||
void configure_reference_frames(
|
||||
std::uint32_t &ref_frames_option,
|
||||
NV_ENC_NUM_REF_FRAMES &list0_option,
|
||||
std::uint32_t default_count,
|
||||
int requested_count,
|
||||
const GUID &encode_guid
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Configure VUI metadata and intra-refresh options shared by H.264 and HEVC.
|
||||
*
|
||||
* @tparam FormatConfig Codec-specific NVENC configuration type.
|
||||
* @param format_config Codec-specific encoder configuration to update.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param colorspace NVENC colorspace metadata.
|
||||
* @param buffer_format Selected NVENC input format.
|
||||
* @param encode_guid Selected codec GUID.
|
||||
*/
|
||||
template<typename FormatConfig>
|
||||
void configure_h264_hevc_metadata(
|
||||
FormatConfig &format_config,
|
||||
const video::config_t &client_config,
|
||||
const nvenc_colorspace_t &colorspace,
|
||||
NV_ENC_BUFFER_FORMAT buffer_format,
|
||||
const GUID &encode_guid
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Configure H.264 codec options.
|
||||
*
|
||||
* @param enc_config Encoder configuration to update.
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param colorspace NVENC colorspace metadata.
|
||||
* @param buffer_format Selected NVENC input format.
|
||||
* @param encode_guid Selected codec GUID.
|
||||
*/
|
||||
void configure_h264(
|
||||
NV_ENC_CONFIG &enc_config,
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
const nvenc_colorspace_t &colorspace,
|
||||
NV_ENC_BUFFER_FORMAT buffer_format,
|
||||
const GUID &encode_guid
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Configure HEVC codec options.
|
||||
*
|
||||
* @param enc_config Encoder configuration to update.
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param colorspace NVENC colorspace metadata.
|
||||
* @param buffer_format Selected NVENC input format.
|
||||
* @param encode_guid Selected codec GUID.
|
||||
*/
|
||||
void configure_hevc(
|
||||
NV_ENC_CONFIG &enc_config,
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
const nvenc_colorspace_t &colorspace,
|
||||
NV_ENC_BUFFER_FORMAT buffer_format,
|
||||
const GUID &encode_guid
|
||||
);
|
||||
|
||||
#if NVENC_SDK_VERSION >= 1200
|
||||
/**
|
||||
* @brief Configure AV1 codec options.
|
||||
*
|
||||
* @param enc_config Encoder configuration to update.
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param colorspace NVENC colorspace metadata.
|
||||
* @param buffer_format Selected NVENC input format.
|
||||
* @param encode_guid Selected codec GUID.
|
||||
*/
|
||||
void configure_av1(
|
||||
NV_ENC_CONFIG &enc_config,
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
const nvenc_colorspace_t &colorspace,
|
||||
NV_ENC_BUFFER_FORMAT buffer_format,
|
||||
const GUID &encode_guid
|
||||
);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configure codec-specific encoder options.
|
||||
*
|
||||
* @param enc_config Encoder configuration to update.
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param colorspace NVENC colorspace metadata.
|
||||
* @param buffer_format Selected NVENC input format.
|
||||
* @param encode_guid Selected codec GUID.
|
||||
*/
|
||||
void configure_codec(
|
||||
NV_ENC_CONFIG &enc_config,
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
const nvenc_colorspace_t &colorspace,
|
||||
NV_ENC_BUFFER_FORMAT buffer_format,
|
||||
const GUID &encode_guid
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Initialize the encoder and its registered input and output resources.
|
||||
*
|
||||
* @param init_params Completed encoder initialization parameters.
|
||||
* @return `true` on success, otherwise `false`.
|
||||
*/
|
||||
bool initialize_encoder_resources(NV_ENC_INITIALIZE_PARAMS &init_params);
|
||||
|
||||
/**
|
||||
* @brief Log the selected encoder configuration.
|
||||
*
|
||||
* @param init_params Encoder initialization parameters.
|
||||
* @param enc_config Encoder configuration.
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param buffer_format Selected NVENC input format.
|
||||
*/
|
||||
void log_created_encoder(
|
||||
const NV_ENC_INITIALIZE_PARAMS &init_params,
|
||||
const NV_ENC_CONFIG &enc_config,
|
||||
const ::nvenc::nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
NV_ENC_BUFFER_FORMAT buffer_format
|
||||
) const;
|
||||
|
||||
NV_ENC_OUTPUT_PTR output_bitstream = nullptr;
|
||||
|
||||
struct {
|
||||
@@ -147,4 +338,4 @@ namespace nvenc {
|
||||
} encoder_state;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// lib includes
|
||||
#include <ffnvcodec/nvEncodeAPI.h>
|
||||
// local includes
|
||||
#include "nvenc_sdk.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
/**
|
||||
* @brief YUV colorspace and color range.
|
||||
@@ -19,4 +19,4 @@ namespace nvenc {
|
||||
bool full_range; ///< Whether the video range is full-range instead of limited.
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
|
||||
+19
-34
@@ -8,62 +8,47 @@
|
||||
#ifdef _WIN32
|
||||
#include "nvenc_d3d11.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
nvenc_d3d11::nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type):
|
||||
nvenc_base(device_type) {
|
||||
nvenc_d3d11::nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type, ::nvenc::shared_dll dll):
|
||||
nvenc_base(device_type),
|
||||
dll(std::move(dll)) {
|
||||
async_event_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
}
|
||||
|
||||
nvenc_d3d11::~nvenc_d3d11() {
|
||||
if (dll) {
|
||||
FreeLibrary(dll);
|
||||
dll = nullptr;
|
||||
}
|
||||
if (async_event_handle) {
|
||||
CloseHandle(async_event_handle);
|
||||
}
|
||||
}
|
||||
|
||||
bool nvenc_d3d11::init_library() {
|
||||
if (dll) {
|
||||
if (nvenc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
constexpr auto dll_name = "nvEncodeAPI64.dll";
|
||||
#else
|
||||
constexpr auto dll_name = "nvEncodeAPI.dll";
|
||||
#endif
|
||||
|
||||
if ((dll = LoadLibraryEx(dll_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))) {
|
||||
if (auto create_instance = (decltype(NvEncodeAPICreateInstance) *) GetProcAddress(dll, "NvEncodeAPICreateInstance")) {
|
||||
auto new_nvenc = std::make_unique<NV_ENCODE_API_FUNCTION_LIST>();
|
||||
new_nvenc->version = NV_ENCODE_API_FUNCTION_LIST_VER;
|
||||
if (nvenc_failed(create_instance(new_nvenc.get()))) {
|
||||
BOOST_LOG(error) << "NvEnc: NvEncodeAPICreateInstance() failed: " << last_nvenc_error_string;
|
||||
} else {
|
||||
nvenc = std::move(new_nvenc);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG(error) << "NvEnc: No NvEncodeAPICreateInstance() in " << dll_name;
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG(debug) << "NvEnc: Couldn't load NvEnc library " << dll_name;
|
||||
auto create_instance = reinterpret_cast<decltype(NvEncodeAPICreateInstance) *>(
|
||||
GetProcAddress(dll.get(), "NvEncodeAPICreateInstance")
|
||||
);
|
||||
if (!create_instance) {
|
||||
BOOST_LOG(error) << "NvEnc: No NvEncodeAPICreateInstance() in NVENC driver library";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dll) {
|
||||
FreeLibrary(dll);
|
||||
dll = nullptr;
|
||||
auto new_nvenc = std::make_unique<NV_ENCODE_API_FUNCTION_LIST>();
|
||||
new_nvenc->version = NV_ENCODE_API_FUNCTION_LIST_VER;
|
||||
if (nvenc_failed(create_instance(new_nvenc.get()))) {
|
||||
BOOST_LOG(error) << "NvEnc: NvEncodeAPICreateInstance() failed: " << last_nvenc_error_string;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
nvenc = std::move(new_nvenc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nvenc_d3d11::wait_for_async_event(uint32_t timeout_ms) {
|
||||
return WaitForSingleObject(async_event_handle, timeout_ms) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
#endif
|
||||
|
||||
+10
-7
@@ -11,8 +11,10 @@
|
||||
|
||||
// local includes
|
||||
#include "nvenc_base.h"
|
||||
#include "nvenc_d3d11_interface.h"
|
||||
#include "nvenc_shared_dll.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
@@ -42,29 +44,30 @@ namespace nvenc {
|
||||
* @brief Abstract Direct3D11 NVENC encoder.
|
||||
* Encapsulates common code used by native and interop implementations.
|
||||
*/
|
||||
class nvenc_d3d11: public nvenc_base {
|
||||
class nvenc_d3d11: public nvenc_base, public ::nvenc::nvenc_d3d11_interface {
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize an NVENC session wrapper for D3D11 input textures.
|
||||
*
|
||||
* @param device_type NVENC device type used by the encoder session.
|
||||
* @param dll Shared NVENC driver module.
|
||||
*/
|
||||
explicit nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type);
|
||||
~nvenc_d3d11();
|
||||
explicit nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type, ::nvenc::shared_dll dll);
|
||||
~nvenc_d3d11() override;
|
||||
|
||||
/**
|
||||
* @brief Get input surface texture.
|
||||
* @return Input surface texture.
|
||||
*/
|
||||
virtual ID3D11Texture2D *get_input_texture() = 0;
|
||||
ID3D11Texture2D *get_input_texture() override = 0;
|
||||
|
||||
protected:
|
||||
bool init_library() override;
|
||||
bool wait_for_async_event(uint32_t timeout_ms) override;
|
||||
|
||||
private:
|
||||
HMODULE dll = nullptr;
|
||||
::nvenc::shared_dll dll;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_d3d11_interface.h
|
||||
* @brief Declarations for the SDK-neutral Direct3D11 NVENC interface.
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
|
||||
// lib includes
|
||||
#include <d3d11.h>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_encoder.h"
|
||||
|
||||
namespace nvenc {
|
||||
|
||||
/**
|
||||
* @brief SDK-neutral Direct3D11 NVENC encoder interface.
|
||||
*/
|
||||
// Virtual inheritance is required because concrete encoders also inherit their SDK-specific implementation.
|
||||
class nvenc_d3d11_interface: public virtual nvenc_encoder { // NOSONAR(cpp:S1011)
|
||||
public:
|
||||
/**
|
||||
* @brief Destroy the SDK-neutral Direct3D11 encoder interface.
|
||||
*/
|
||||
~nvenc_d3d11_interface() override = default;
|
||||
|
||||
/**
|
||||
* @brief Get the input surface texture.
|
||||
*
|
||||
* @return Input surface texture.
|
||||
*/
|
||||
virtual ID3D11Texture2D *get_input_texture() = 0;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
#endif
|
||||
@@ -9,10 +9,10 @@
|
||||
// local includes
|
||||
#include "nvenc_utils.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
nvenc_d3d11_native::nvenc_d3d11_native(ID3D11Device *d3d_device):
|
||||
nvenc_d3d11(NV_ENC_DEVICE_TYPE_DIRECTX),
|
||||
nvenc_d3d11_native::nvenc_d3d11_native(ID3D11Device *d3d_device, ::nvenc::shared_dll dll):
|
||||
nvenc_d3d11(NV_ENC_DEVICE_TYPE_DIRECTX, std::move(dll)),
|
||||
d3d_device(d3d_device) {
|
||||
device = d3d_device;
|
||||
}
|
||||
@@ -70,5 +70,5 @@ namespace nvenc {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// local includes
|
||||
#include "nvenc_d3d11.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
/**
|
||||
* @brief Native Direct3D11 NVENC encoder.
|
||||
@@ -20,9 +20,10 @@ namespace nvenc {
|
||||
public:
|
||||
/**
|
||||
* @param d3d_device Direct3D11 device used for encoding.
|
||||
* @param dll Shared NVENC driver module.
|
||||
*/
|
||||
explicit nvenc_d3d11_native(ID3D11Device *d3d_device);
|
||||
~nvenc_d3d11_native();
|
||||
explicit nvenc_d3d11_native(ID3D11Device *d3d_device, ::nvenc::shared_dll dll);
|
||||
~nvenc_d3d11_native() override;
|
||||
|
||||
ID3D11Texture2D *get_input_texture() override;
|
||||
|
||||
@@ -33,5 +34,5 @@ namespace nvenc {
|
||||
ID3D11Texture2DPtr d3d_input_texture;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
#endif
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
// local includes
|
||||
#include "nvenc_utils.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
nvenc_d3d11_on_cuda::nvenc_d3d11_on_cuda(ID3D11Device *d3d_device):
|
||||
nvenc_d3d11(NV_ENC_DEVICE_TYPE_CUDA),
|
||||
nvenc_d3d11_on_cuda::nvenc_d3d11_on_cuda(ID3D11Device *d3d_device, ::nvenc::shared_dll dll):
|
||||
nvenc_d3d11(NV_ENC_DEVICE_TYPE_CUDA, std::move(dll)),
|
||||
d3d_device(d3d_device) {
|
||||
}
|
||||
|
||||
@@ -68,20 +68,7 @@ namespace nvenc {
|
||||
location = (T) GetProcAddress(cuda_functions.dll, symbol);
|
||||
return location != nullptr;
|
||||
};
|
||||
if (!load_function(cuda_functions.cuInit, "cuInit") ||
|
||||
!load_function(cuda_functions.cuD3D11GetDevice, "cuD3D11GetDevice") ||
|
||||
!load_function(cuda_functions.cuCtxCreate, "cuCtxCreate_v2") ||
|
||||
!load_function(cuda_functions.cuCtxDestroy, "cuCtxDestroy_v2") ||
|
||||
!load_function(cuda_functions.cuCtxPushCurrent, "cuCtxPushCurrent_v2") ||
|
||||
!load_function(cuda_functions.cuCtxPopCurrent, "cuCtxPopCurrent_v2") ||
|
||||
!load_function(cuda_functions.cuMemAllocPitch, "cuMemAllocPitch_v2") ||
|
||||
!load_function(cuda_functions.cuMemFree, "cuMemFree_v2") ||
|
||||
!load_function(cuda_functions.cuGraphicsD3D11RegisterResource, "cuGraphicsD3D11RegisterResource") ||
|
||||
!load_function(cuda_functions.cuGraphicsUnregisterResource, "cuGraphicsUnregisterResource") ||
|
||||
!load_function(cuda_functions.cuGraphicsMapResources, "cuGraphicsMapResources") ||
|
||||
!load_function(cuda_functions.cuGraphicsUnmapResources, "cuGraphicsUnmapResources") ||
|
||||
!load_function(cuda_functions.cuGraphicsSubResourceGetMappedArray, "cuGraphicsSubResourceGetMappedArray") ||
|
||||
!load_function(cuda_functions.cuMemcpy2D, "cuMemcpy2D_v2")) {
|
||||
if (!load_function(cuda_functions.cuInit, "cuInit") || !load_function(cuda_functions.cuD3D11GetDevice, "cuD3D11GetDevice") || !load_function(cuda_functions.cuCtxCreate, "cuCtxCreate_v2") || !load_function(cuda_functions.cuCtxDestroy, "cuCtxDestroy_v2") || !load_function(cuda_functions.cuCtxPushCurrent, "cuCtxPushCurrent_v2") || !load_function(cuda_functions.cuCtxPopCurrent, "cuCtxPopCurrent_v2") || !load_function(cuda_functions.cuMemAllocPitch, "cuMemAllocPitch_v2") || !load_function(cuda_functions.cuMemFree, "cuMemFree_v2") || !load_function(cuda_functions.cuGraphicsD3D11RegisterResource, "cuGraphicsD3D11RegisterResource") || !load_function(cuda_functions.cuGraphicsUnregisterResource, "cuGraphicsUnregisterResource") || !load_function(cuda_functions.cuGraphicsMapResources, "cuGraphicsMapResources") || !load_function(cuda_functions.cuGraphicsUnmapResources, "cuGraphicsUnmapResources") || !load_function(cuda_functions.cuGraphicsSubResourceGetMappedArray, "cuGraphicsSubResourceGetMappedArray") || !load_function(cuda_functions.cuMemcpy2D, "cuMemcpy2D_v2")) {
|
||||
BOOST_LOG(error) << "NvEnc: missing CUDA functions in " << dll_name;
|
||||
FreeLibrary(cuda_functions.dll);
|
||||
cuda_functions = {};
|
||||
@@ -93,14 +80,9 @@ namespace nvenc {
|
||||
if (cuda_functions.dll) {
|
||||
IDXGIDevicePtr dxgi_device;
|
||||
IDXGIAdapterPtr dxgi_adapter;
|
||||
if (d3d_device &&
|
||||
SUCCEEDED(d3d_device->QueryInterface(IID_PPV_ARGS(&dxgi_device))) &&
|
||||
SUCCEEDED(dxgi_device->GetAdapter(&dxgi_adapter))) {
|
||||
if (d3d_device && SUCCEEDED(d3d_device->QueryInterface(IID_PPV_ARGS(&dxgi_device))) && SUCCEEDED(dxgi_device->GetAdapter(&dxgi_adapter))) {
|
||||
CUdevice cuda_device;
|
||||
if (cuda_succeeded(cuda_functions.cuInit(0)) &&
|
||||
cuda_succeeded(cuda_functions.cuD3D11GetDevice(&cuda_device, dxgi_adapter)) &&
|
||||
cuda_succeeded(cuda_functions.cuCtxCreate(&cuda_context, CU_CTX_SCHED_BLOCKING_SYNC, cuda_device)) &&
|
||||
cuda_succeeded(cuda_functions.cuCtxPopCurrent(&cuda_context))) {
|
||||
if (cuda_succeeded(cuda_functions.cuInit(0)) && cuda_succeeded(cuda_functions.cuD3D11GetDevice(&cuda_device, dxgi_adapter)) && cuda_succeeded(cuda_functions.cuCtxCreate(&cuda_context, CU_CTX_SCHED_BLOCKING_SYNC, cuda_device)) && cuda_succeeded(cuda_functions.cuCtxPopCurrent(&cuda_context))) {
|
||||
device = cuda_context;
|
||||
} else {
|
||||
BOOST_LOG(error) << "NvEnc: couldn't create CUDA interop context: error " << last_cuda_error;
|
||||
@@ -143,25 +125,18 @@ namespace nvenc {
|
||||
}
|
||||
|
||||
if (!cuda_d3d_input_texture) {
|
||||
if (cuda_failed(cuda_functions.cuGraphicsD3D11RegisterResource(
|
||||
&cuda_d3d_input_texture,
|
||||
d3d_input_texture,
|
||||
CU_GRAPHICS_REGISTER_FLAGS_NONE
|
||||
))) {
|
||||
if (cuda_failed(cuda_functions.cuGraphicsD3D11RegisterResource(&cuda_d3d_input_texture, d3d_input_texture, CU_GRAPHICS_REGISTER_FLAGS_NONE))) {
|
||||
BOOST_LOG(error) << "NvEnc: cuGraphicsD3D11RegisterResource() failed: error " << last_cuda_error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cuda_surface) {
|
||||
if (cuda_failed(cuda_functions.cuMemAllocPitch(
|
||||
&cuda_surface,
|
||||
&cuda_surface_pitch,
|
||||
// Planar 16-bit YUV
|
||||
encoder_params.width * 2,
|
||||
encoder_params.height * 3,
|
||||
16
|
||||
))) {
|
||||
if (cuda_failed(cuda_functions.cuMemAllocPitch(&cuda_surface, &cuda_surface_pitch,
|
||||
// Planar 16-bit YUV
|
||||
encoder_params.width * 2,
|
||||
encoder_params.height * 3,
|
||||
16))) {
|
||||
BOOST_LOG(error) << "NvEnc: cuMemAllocPitch() failed: error " << last_cuda_error;
|
||||
return false;
|
||||
}
|
||||
@@ -256,8 +231,7 @@ namespace nvenc {
|
||||
}
|
||||
|
||||
nvenc_d3d11_on_cuda::autopop_context nvenc_d3d11_on_cuda::push_context() {
|
||||
if (cuda_context &&
|
||||
cuda_succeeded(cuda_functions.cuCtxPushCurrent(cuda_context))) {
|
||||
if (cuda_context && cuda_succeeded(cuda_functions.cuCtxPushCurrent(cuda_context))) {
|
||||
return {*this, cuda_context};
|
||||
} else {
|
||||
BOOST_LOG(error) << "NvEnc: cuCtxPushCurrent() failed: error " << last_cuda_error;
|
||||
@@ -265,5 +239,5 @@ namespace nvenc {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
#endif
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
// lib includes
|
||||
#include <ffnvcodec/dynlink_cuda.h>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_d3d11.h"
|
||||
#include "nvenc_sdk.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
/**
|
||||
* @brief Interop Direct3D11 on CUDA NVENC encoder.
|
||||
@@ -21,9 +19,10 @@ namespace nvenc {
|
||||
/**
|
||||
* @param d3d_device Direct3D11 device that will create input surface texture.
|
||||
* CUDA encoding device will be derived from it.
|
||||
* @param dll Shared NVENC driver module.
|
||||
*/
|
||||
explicit nvenc_d3d11_on_cuda(ID3D11Device *d3d_device);
|
||||
~nvenc_d3d11_on_cuda();
|
||||
explicit nvenc_d3d11_on_cuda(ID3D11Device *d3d_device, ::nvenc::shared_dll dll);
|
||||
~nvenc_d3d11_on_cuda() override;
|
||||
|
||||
ID3D11Texture2D *get_input_texture() override;
|
||||
|
||||
@@ -84,5 +83,5 @@ namespace nvenc {
|
||||
size_t cuda_surface_pitch = 0;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_dynamic_factory.cpp
|
||||
* @brief Definitions for runtime NVENC SDK selection on Windows.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
|
||||
// this include
|
||||
#include "nvenc_dynamic_factory.h"
|
||||
|
||||
// standard includes
|
||||
#include <bit>
|
||||
#include <utility>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_dynamic_factory_versions.h"
|
||||
#include "src/logging.h"
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef _WIN64
|
||||
constexpr auto nvenc_dll_name = "nvEncodeAPI64.dll";
|
||||
#else
|
||||
constexpr auto nvenc_dll_name = "nvEncodeAPI.dll";
|
||||
#endif
|
||||
|
||||
constexpr auto minimum_driver_version = "456.71";
|
||||
|
||||
using get_max_supported_version_fn = std::uint32_t(WINAPI *)(std::uint32_t *);
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace nvenc {
|
||||
|
||||
nvenc_dynamic_factory::nvenc_dynamic_factory(
|
||||
shared_dll dll,
|
||||
nvenc_sdk_version sdk_version,
|
||||
create_encoder_fn create_native,
|
||||
create_encoder_fn create_on_cuda
|
||||
):
|
||||
dll(std::move(dll)),
|
||||
selected_sdk_version(sdk_version),
|
||||
create_native(std::move(create_native)),
|
||||
create_on_cuda(std::move(create_on_cuda)) {
|
||||
}
|
||||
|
||||
std::shared_ptr<nvenc_dynamic_factory> nvenc_dynamic_factory::get() {
|
||||
return get({
|
||||
[]() {
|
||||
return make_shared_dll(LoadLibraryEx(nvenc_dll_name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32));
|
||||
},
|
||||
[](HMODULE dll, const char *symbol) {
|
||||
return GetProcAddress(dll, symbol);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<nvenc_dynamic_factory> nvenc_dynamic_factory::get(const nvenc_runtime_api &runtime_api) {
|
||||
auto dll = runtime_api.load_driver();
|
||||
if (!dll) {
|
||||
BOOST_LOG(debug) << "NvEnc: Couldn't load NvEnc library " << nvenc_dll_name;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto get_max_version = std::bit_cast<get_max_supported_version_fn>(
|
||||
runtime_api.get_symbol(dll.get(), "NvEncodeAPIGetMaxSupportedVersion")
|
||||
);
|
||||
if (!get_max_version) {
|
||||
BOOST_LOG(error) << "NvEnc: No NvEncodeAPIGetMaxSupportedVersion() in " << nvenc_dll_name;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::uint32_t packed_max_version = 0;
|
||||
if (get_max_version(&packed_max_version) != 0U) {
|
||||
BOOST_LOG(error) << "NvEnc: NvEncodeAPIGetMaxSupportedVersion() failed";
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto max_version = decode_nvenc_driver_version(packed_max_version);
|
||||
const auto sdk_version = select_nvenc_sdk_version(max_version);
|
||||
switch (sdk_version) {
|
||||
case nvenc_sdk_version::sdk_13_0:
|
||||
return std::make_shared<nvenc_dynamic_factory>(
|
||||
std::move(dll),
|
||||
sdk_version,
|
||||
detail::create_nvenc_d3d11_native_1300,
|
||||
detail::create_nvenc_d3d11_on_cuda_1300
|
||||
);
|
||||
|
||||
case nvenc_sdk_version::sdk_12_0:
|
||||
return std::make_shared<nvenc_dynamic_factory>(
|
||||
std::move(dll),
|
||||
sdk_version,
|
||||
detail::create_nvenc_d3d11_native_1200,
|
||||
detail::create_nvenc_d3d11_on_cuda_1200
|
||||
);
|
||||
|
||||
case nvenc_sdk_version::sdk_11_0:
|
||||
return std::make_shared<nvenc_dynamic_factory>(
|
||||
std::move(dll),
|
||||
sdk_version,
|
||||
detail::create_nvenc_d3d11_native_1100,
|
||||
detail::create_nvenc_d3d11_on_cuda_1100
|
||||
);
|
||||
|
||||
case nvenc_sdk_version::unsupported:
|
||||
default:
|
||||
BOOST_LOG(error) << "NvEnc: minimum required driver version is " << minimum_driver_version;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<nvenc_d3d11_interface> nvenc_dynamic_factory::create_nvenc_d3d11_native(
|
||||
ID3D11Device *d3d_device
|
||||
) const {
|
||||
return create_native(d3d_device, dll);
|
||||
}
|
||||
|
||||
std::unique_ptr<nvenc_d3d11_interface> nvenc_dynamic_factory::create_nvenc_d3d11_on_cuda(
|
||||
ID3D11Device *d3d_device
|
||||
) const {
|
||||
return create_on_cuda(d3d_device, dll);
|
||||
}
|
||||
|
||||
nvenc_sdk_version nvenc_dynamic_factory::sdk_version() const {
|
||||
return selected_sdk_version;
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_dynamic_factory.h
|
||||
* @brief Declarations for runtime NVENC SDK selection on Windows.
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
|
||||
// standard includes
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_d3d11_interface.h"
|
||||
#include "nvenc_shared_dll.h"
|
||||
#include "nvenc_version.h"
|
||||
|
||||
namespace nvenc {
|
||||
|
||||
/**
|
||||
* @brief Windows runtime operations used to discover the installed NVENC API.
|
||||
*/
|
||||
struct nvenc_runtime_api {
|
||||
using load_driver_fn = std::function<shared_dll()>; ///< Load the NVENC driver module.
|
||||
|
||||
/**
|
||||
* @brief Resolve an export from the loaded NVENC driver module.
|
||||
*/
|
||||
using get_symbol_fn = std::function<FARPROC(HMODULE, const char *)>;
|
||||
|
||||
load_driver_fn load_driver; ///< Function that loads the NVENC driver module.
|
||||
get_symbol_fn get_symbol; ///< Resolve a driver export.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Factory bound to the newest NVENC SDK supported by the installed driver.
|
||||
*/
|
||||
class nvenc_dynamic_factory {
|
||||
public:
|
||||
/**
|
||||
* @brief SDK-specific encoder constructor.
|
||||
*/
|
||||
using create_encoder_fn =
|
||||
std::function<std::unique_ptr<nvenc_d3d11_interface>(ID3D11Device *, shared_dll)>;
|
||||
|
||||
/**
|
||||
* @brief Construct a factory bound to one NVENC SDK implementation.
|
||||
*
|
||||
* @param dll Shared NVENC driver module.
|
||||
* @param sdk_version Selected SDK version.
|
||||
* @param create_native Native Direct3D11 encoder constructor.
|
||||
* @param create_on_cuda CUDA-interoperability encoder constructor.
|
||||
*/
|
||||
nvenc_dynamic_factory(
|
||||
shared_dll dll,
|
||||
nvenc_sdk_version sdk_version,
|
||||
create_encoder_fn create_native,
|
||||
create_encoder_fn create_on_cuda
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Load the NVENC driver and select a compatible SDK implementation.
|
||||
*
|
||||
* @return Initialized factory, or an empty pointer when NVENC is unavailable.
|
||||
*/
|
||||
static std::shared_ptr<nvenc_dynamic_factory> get();
|
||||
|
||||
/**
|
||||
* @brief Select a compatible SDK implementation using the supplied runtime operations.
|
||||
*
|
||||
* @param runtime_api Runtime operations used to load and query the NVENC driver.
|
||||
* @return Initialized factory, or an empty pointer when NVENC is unavailable.
|
||||
*/
|
||||
static std::shared_ptr<nvenc_dynamic_factory> get(const nvenc_runtime_api &runtime_api);
|
||||
|
||||
/**
|
||||
* @brief Create a native Direct3D11 NVENC encoder.
|
||||
*
|
||||
* @param d3d_device Direct3D11 device used for encoding.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_native(ID3D11Device *d3d_device) const;
|
||||
|
||||
/**
|
||||
* @brief Create a CUDA NVENC encoder with Direct3D11 input surfaces.
|
||||
*
|
||||
* @param d3d_device Direct3D11 device used to create input textures.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_on_cuda(ID3D11Device *d3d_device) const;
|
||||
|
||||
/**
|
||||
* @brief Get the SDK implementation selected for this factory.
|
||||
*
|
||||
* @return Selected NVENC SDK version.
|
||||
*/
|
||||
nvenc_sdk_version sdk_version() const;
|
||||
|
||||
private:
|
||||
shared_dll dll;
|
||||
nvenc_sdk_version selected_sdk_version;
|
||||
create_encoder_fn create_native;
|
||||
create_encoder_fn create_on_cuda;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_dynamic_factory_impl.cpp
|
||||
* @brief SDK-specific constructors used by the runtime NVENC factory.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef NVENC_NAMESPACE
|
||||
#error NVENC_NAMESPACE must identify the version-specific implementation namespace
|
||||
#endif
|
||||
|
||||
#ifndef NVENC_FACTORY_SUFFIX
|
||||
#error NVENC_FACTORY_SUFFIX must identify the version-specific constructor suffix
|
||||
#endif
|
||||
|
||||
// standard includes
|
||||
#include <utility>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_d3d11_native.h"
|
||||
#include "nvenc_d3d11_on_cuda.h"
|
||||
#include "nvenc_dynamic_factory_versions.h"
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define NVENC_CONCAT_IMPL(left, right) left##right
|
||||
#define NVENC_CONCAT(left, right) NVENC_CONCAT_IMPL(left, right)
|
||||
|
||||
namespace nvenc::detail {
|
||||
|
||||
std::unique_ptr<nvenc_d3d11_interface> NVENC_CONCAT(create_nvenc_d3d11_native_, NVENC_FACTORY_SUFFIX)(
|
||||
ID3D11Device *device,
|
||||
shared_dll dll
|
||||
) {
|
||||
return std::make_unique<NVENC_NAMESPACE::nvenc_d3d11_native>(device, std::move(dll));
|
||||
}
|
||||
|
||||
std::unique_ptr<nvenc_d3d11_interface> NVENC_CONCAT(create_nvenc_d3d11_on_cuda_, NVENC_FACTORY_SUFFIX)(
|
||||
ID3D11Device *device,
|
||||
shared_dll dll
|
||||
) {
|
||||
return std::make_unique<NVENC_NAMESPACE::nvenc_d3d11_on_cuda>(device, std::move(dll));
|
||||
}
|
||||
|
||||
} // namespace nvenc::detail
|
||||
|
||||
#undef NVENC_CONCAT
|
||||
#undef NVENC_CONCAT_IMPL
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_dynamic_factory_versions.h
|
||||
* @brief Declarations for SDK-specific NVENC encoder constructors.
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
|
||||
// standard includes
|
||||
#include <memory>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_d3d11_interface.h"
|
||||
#include "nvenc_shared_dll.h"
|
||||
|
||||
namespace nvenc::detail {
|
||||
|
||||
/**
|
||||
* @brief Create an SDK 11.0 native Direct3D11 encoder.
|
||||
*
|
||||
* @param device Direct3D11 device used for encoding.
|
||||
* @param dll Shared NVENC driver module.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_native_1100(ID3D11Device *device, shared_dll dll);
|
||||
/**
|
||||
* @brief Create an SDK 11.0 CUDA-interoperability encoder.
|
||||
*
|
||||
* @param device Direct3D11 device used for input surfaces.
|
||||
* @param dll Shared NVENC driver module.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_on_cuda_1100(ID3D11Device *device, shared_dll dll);
|
||||
/**
|
||||
* @brief Create an SDK 12.0 native Direct3D11 encoder.
|
||||
*
|
||||
* @param device Direct3D11 device used for encoding.
|
||||
* @param dll Shared NVENC driver module.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_native_1200(ID3D11Device *device, shared_dll dll);
|
||||
/**
|
||||
* @brief Create an SDK 12.0 CUDA-interoperability encoder.
|
||||
*
|
||||
* @param device Direct3D11 device used for input surfaces.
|
||||
* @param dll Shared NVENC driver module.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_on_cuda_1200(ID3D11Device *device, shared_dll dll);
|
||||
/**
|
||||
* @brief Create an SDK 13.0 native Direct3D11 encoder.
|
||||
*
|
||||
* @param device Direct3D11 device used for encoding.
|
||||
* @param dll Shared NVENC driver module.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_native_1300(ID3D11Device *device, shared_dll dll);
|
||||
/**
|
||||
* @brief Create an SDK 13.0 CUDA-interoperability encoder.
|
||||
*
|
||||
* @param device Direct3D11 device used for input surfaces.
|
||||
* @param dll Shared NVENC driver module.
|
||||
* @return SDK-neutral encoder instance.
|
||||
*/
|
||||
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_on_cuda_1300(ID3D11Device *device, shared_dll dll);
|
||||
|
||||
} // namespace nvenc::detail
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_encoder.h
|
||||
* @brief Declarations for the SDK-neutral NVENC encoder interface.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// standard includes
|
||||
#include <cstdint>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_config.h"
|
||||
#include "nvenc_encoded_frame.h"
|
||||
|
||||
namespace platf {
|
||||
enum class pix_fmt_e;
|
||||
}
|
||||
|
||||
namespace video {
|
||||
struct config_t;
|
||||
struct sunshine_colorspace_t;
|
||||
} // namespace video
|
||||
|
||||
namespace nvenc {
|
||||
|
||||
/**
|
||||
* @brief SDK-neutral standalone NVENC encoder interface.
|
||||
*/
|
||||
class nvenc_encoder {
|
||||
public:
|
||||
/**
|
||||
* @brief Destroy the SDK-neutral encoder interface.
|
||||
*/
|
||||
virtual ~nvenc_encoder() = default;
|
||||
|
||||
/**
|
||||
* @brief Create the encoder.
|
||||
*
|
||||
* @param config NVENC encoder configuration.
|
||||
* @param client_config Stream configuration requested by the client.
|
||||
* @param colorspace Sunshine colorspace metadata.
|
||||
* @param buffer_format Platform-agnostic input surface format.
|
||||
* @return `true` on success, `false` on error.
|
||||
*/
|
||||
virtual bool create_encoder(
|
||||
const nvenc_config &config,
|
||||
const video::config_t &client_config,
|
||||
const video::sunshine_colorspace_t &colorspace,
|
||||
platf::pix_fmt_e buffer_format
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* @brief Destroy the encoder.
|
||||
*/
|
||||
virtual void destroy_encoder() = 0;
|
||||
|
||||
/**
|
||||
* @brief Encode the next frame using the platform-specific input surface.
|
||||
*
|
||||
* @param frame_index Frame index that uniquely identifies the frame.
|
||||
* @param force_idr Whether to encode the frame as a forced IDR.
|
||||
* @return Encoded frame.
|
||||
*/
|
||||
virtual nvenc_encoded_frame encode_frame(std::uint64_t frame_index, bool force_idr) = 0;
|
||||
|
||||
/**
|
||||
* @brief Invalidate reference frames in the requested range.
|
||||
*
|
||||
* @param first_frame First frame index of the invalidation range.
|
||||
* @param last_frame Last frame index of the invalidation range.
|
||||
* @return `true` on success, `false` on error.
|
||||
*/
|
||||
virtual bool invalidate_ref_frames(std::uint64_t first_frame, std::uint64_t last_frame) = 0;
|
||||
};
|
||||
|
||||
} // namespace nvenc
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_sdk.h
|
||||
* @brief Imports one NVENC SDK into its version-specific implementation namespace.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @def NVENC_NAMESPACE
|
||||
* @brief Namespace used for the documented NVENC implementation.
|
||||
*/
|
||||
#define NVENC_NAMESPACE nvenc
|
||||
|
||||
/**
|
||||
* @def NVENC_SDK_VERSION
|
||||
* @brief NVENC SDK version used while generating documentation.
|
||||
*/
|
||||
// Doxygen must select the same preprocessor interface used by versioned build targets.
|
||||
#define NVENC_SDK_VERSION 1300 // NOSONAR(cpp:S5028)
|
||||
#endif
|
||||
|
||||
#ifndef NVENC_NAMESPACE
|
||||
#error NVENC_NAMESPACE must identify the version-specific implementation namespace
|
||||
#endif
|
||||
|
||||
#ifndef NVENC_SDK_VERSION
|
||||
#error NVENC_SDK_VERSION must identify the version-specific NVENC SDK
|
||||
#endif
|
||||
|
||||
// Include common platform and integer declarations outside the SDK namespace.
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
// The version-specific namespace is populated by the SDK headers included below.
|
||||
namespace NVENC_NAMESPACE { // NOSONAR(cpp:S3261)
|
||||
#ifndef DOXYGEN
|
||||
#include <ffnvcodec/dynlink_cuda.h>
|
||||
#include <ffnvcodec/nvEncodeAPI.h>
|
||||
|
||||
#if NVENCAPI_MAJOR_VERSION * 100 + NVENCAPI_MINOR_VERSION != NVENC_SDK_VERSION
|
||||
#error NVENC_SDK_VERSION does not match the selected nv-codec-headers package
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if NVENC_SDK_VERSION < 1200
|
||||
/**
|
||||
* @brief Video format values added as named types after SDK 11.0.
|
||||
*/
|
||||
enum NV_ENC_VUI_VIDEO_FORMAT {
|
||||
NV_ENC_VUI_VIDEO_FORMAT_COMPONENT = 0,
|
||||
NV_ENC_VUI_VIDEO_FORMAT_PAL = 1,
|
||||
NV_ENC_VUI_VIDEO_FORMAT_NTSC = 2,
|
||||
NV_ENC_VUI_VIDEO_FORMAT_SECAM = 3,
|
||||
NV_ENC_VUI_VIDEO_FORMAT_MAC = 4,
|
||||
NV_ENC_VUI_VIDEO_FORMAT_UNSPECIFIED = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Color-primary values added as named types after SDK 11.0.
|
||||
*/
|
||||
enum NV_ENC_VUI_COLOR_PRIMARIES {
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_UNDEFINED = 0,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_BT709 = 1,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_UNSPECIFIED = 2,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_RESERVED = 3,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_BT470M = 4,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_BT470BG = 5,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_SMPTE170M = 6,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_SMPTE240M = 7,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_FILM = 8,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_BT2020 = 9,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_SMPTE428 = 10,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_SMPTE431 = 11,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_SMPTE432 = 12,
|
||||
NV_ENC_VUI_COLOR_PRIMARIES_JEDEC_P22 = 22,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Transfer-characteristic values added as named types after SDK 11.0.
|
||||
*/
|
||||
enum NV_ENC_VUI_TRANSFER_CHARACTERISTIC {
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_UNDEFINED = 0,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT709 = 1,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_UNSPECIFIED = 2,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_RESERVED = 3,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT470M = 4,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT470BG = 5,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE170M = 6,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE240M = 7,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_LINEAR = 8,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_LOG = 9,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_LOG_SQRT = 10,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_IEC61966_2_4 = 11,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT1361_ECG = 12,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SRGB = 13,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT2020_10 = 14,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_BT2020_12 = 15,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE2084 = 16,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_SMPTE428 = 17,
|
||||
NV_ENC_VUI_TRANSFER_CHARACTERISTIC_ARIB_STD_B67 = 18,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Matrix-coefficient values added as named types after SDK 11.0.
|
||||
*/
|
||||
enum NV_ENC_VUI_MATRIX_COEFFS {
|
||||
NV_ENC_VUI_MATRIX_COEFFS_RGB = 0,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_BT709 = 1,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_UNSPECIFIED = 2,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_RESERVED = 3,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_FCC = 4,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_BT470BG = 5,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_SMPTE170M = 6,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_SMPTE240M = 7,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_YCGCO = 8,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_BT2020_NCL = 9,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_BT2020_CL = 10,
|
||||
NV_ENC_VUI_MATRIX_COEFFS_SMPTE2085 = 11,
|
||||
};
|
||||
#endif
|
||||
} // namespace NVENC_NAMESPACE
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_shared_dll.h
|
||||
* @brief Windows module lifetime helpers shared by NVENC factories and encoders.
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
|
||||
// standard includes
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
// platform includes
|
||||
#include <Windows.h>
|
||||
|
||||
namespace nvenc {
|
||||
|
||||
/**
|
||||
* @brief Shared ownership wrapper for a loaded Windows module.
|
||||
*/
|
||||
using shared_dll = std::shared_ptr<std::remove_pointer_t<HMODULE>>;
|
||||
|
||||
/**
|
||||
* @brief Release a Windows module when its final shared owner is destroyed.
|
||||
*/
|
||||
struct shared_dll_deleter {
|
||||
/**
|
||||
* @brief Release the module.
|
||||
*
|
||||
* @param dll Module handle to release.
|
||||
*/
|
||||
void operator()(HMODULE dll) const {
|
||||
if (dll) {
|
||||
FreeLibrary(dll);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Wrap a Windows module handle in shared ownership.
|
||||
*
|
||||
* @param dll Module handle returned by `LoadLibraryEx()`.
|
||||
* @return Shared module handle.
|
||||
*/
|
||||
inline shared_dll make_shared_dll(HMODULE dll) {
|
||||
return shared_dll(dll, shared_dll_deleter {});
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
#endif
|
||||
@@ -8,7 +8,7 @@
|
||||
// local includes
|
||||
#include "nvenc_utils.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
@@ -102,4 +102,4 @@ namespace nvenc {
|
||||
return colorspace;
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
|
||||
@@ -9,15 +9,13 @@
|
||||
#include <dxgiformat.h>
|
||||
#endif
|
||||
|
||||
// lib includes
|
||||
#include <ffnvcodec/nvEncodeAPI.h>
|
||||
|
||||
// local includes
|
||||
#include "nvenc_colorspace.h"
|
||||
#include "nvenc_sdk.h"
|
||||
#include "src/platform/common.h"
|
||||
#include "src/video_colorspace.h"
|
||||
|
||||
namespace nvenc {
|
||||
namespace NVENC_NAMESPACE {
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
@@ -45,4 +43,4 @@ namespace nvenc {
|
||||
*/
|
||||
nvenc_colorspace_t nvenc_colorspace_from_sunshine_colorspace(const video::sunshine_colorspace_t &sunshine_colorspace);
|
||||
|
||||
} // namespace nvenc
|
||||
} // namespace NVENC_NAMESPACE
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file src/nvenc/nvenc_version.h
|
||||
* @brief NVENC SDK version selection helpers.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// standard includes
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace nvenc {
|
||||
|
||||
/**
|
||||
* @brief NVENC SDK implementations compiled into Sunshine.
|
||||
*/
|
||||
enum class nvenc_sdk_version : std::uint32_t {
|
||||
unsupported = 0U, ///< No compatible SDK implementation is available.
|
||||
sdk_11_0 = 1100U, ///< Video Codec SDK 11.0.
|
||||
sdk_12_0 = 1200U, ///< Video Codec SDK 12.0.
|
||||
sdk_13_0 = 1300U, ///< Video Codec SDK 13.0.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Convert the packed driver API version to a comparable integer.
|
||||
*
|
||||
* @param version Version returned by `NvEncodeAPIGetMaxSupportedVersion()`.
|
||||
* @return Version encoded as `major * 100 + minor`.
|
||||
*/
|
||||
constexpr std::uint32_t decode_nvenc_driver_version(std::uint32_t version) {
|
||||
return (version >> 4U) * 100U + (version & 0x0FU);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Select the newest compiled SDK supported by the installed driver.
|
||||
*
|
||||
* @param max_version Maximum driver API version encoded as `major * 100 + minor`.
|
||||
* @return Selected SDK implementation, or `unsupported` when the driver is too old.
|
||||
*/
|
||||
constexpr nvenc_sdk_version select_nvenc_sdk_version(std::uint32_t max_version) {
|
||||
using enum nvenc_sdk_version;
|
||||
if (max_version >= std::to_underlying(sdk_13_0)) {
|
||||
return sdk_13_0;
|
||||
}
|
||||
if (max_version >= std::to_underlying(sdk_12_0)) {
|
||||
return sdk_12_0;
|
||||
}
|
||||
if (max_version >= std::to_underlying(sdk_11_0)) {
|
||||
return sdk_11_0;
|
||||
}
|
||||
return unsupported;
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
@@ -69,7 +69,7 @@ namespace video {
|
||||
} // namespace video
|
||||
|
||||
namespace nvenc {
|
||||
class nvenc_base;
|
||||
class nvenc_encoder;
|
||||
}
|
||||
|
||||
namespace platf {
|
||||
@@ -638,7 +638,7 @@ namespace platf {
|
||||
*/
|
||||
virtual bool init_encoder(const video::config_t &client_config, const video::sunshine_colorspace_t &colorspace) = 0;
|
||||
|
||||
nvenc::nvenc_base *nvenc = nullptr; ///< NVENC encoder instance owned by the encode device.
|
||||
nvenc::nvenc_encoder *nvenc = nullptr; ///< NVENC encoder instance owned by the encode device.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -190,8 +190,7 @@ namespace cuda {
|
||||
|
||||
auto hwframe_ctx = (AVHWFramesContext *) hw_frames_ctx->data;
|
||||
|
||||
if (hwframe_ctx->sw_format != AV_PIX_FMT_NV12 &&
|
||||
hwframe_ctx->sw_format != AV_PIX_FMT_YUV444P) {
|
||||
if (hwframe_ctx->sw_format != AV_PIX_FMT_NV12 && hwframe_ctx->sw_format != AV_PIX_FMT_YUV444P) {
|
||||
BOOST_LOG(error) << "cuda::cuda_t doesn't support any format other than AV_PIX_FMT_NV12 and AV_PIX_FMT_YUV444P"sv;
|
||||
return -1;
|
||||
}
|
||||
@@ -469,10 +468,7 @@ namespace cuda {
|
||||
|
||||
auto hw_frames_ctx = (AVHWFramesContext *) hw_frames_ctx_buf->data;
|
||||
|
||||
if (hw_frames_ctx->sw_format != AV_PIX_FMT_NV12 &&
|
||||
hw_frames_ctx->sw_format != AV_PIX_FMT_YUV444P &&
|
||||
hw_frames_ctx->sw_format != AV_PIX_FMT_P010LE &&
|
||||
hw_frames_ctx->sw_format != AV_PIX_FMT_YUV444P16LE) {
|
||||
if (hw_frames_ctx->sw_format != AV_PIX_FMT_NV12 && hw_frames_ctx->sw_format != AV_PIX_FMT_YUV444P && hw_frames_ctx->sw_format != AV_PIX_FMT_P010LE && hw_frames_ctx->sw_format != AV_PIX_FMT_YUV444P16LE) {
|
||||
BOOST_LOG(error) << "cuda::gl_cuda_vram_t doesn't support any format other than AV_PIX_FMT_NV12, AV_PIX_FMT_P010LE, AV_PIX_FMT_YUV444P and AV_PIX_FMT_YUV444P16LE"sv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -860,19 +860,11 @@ namespace platf {
|
||||
if (display_name.empty() || std::ranges::all_of(display_name, ::isdigit)) {
|
||||
return util::from_view(display_name);
|
||||
}
|
||||
// display_name is a connector name (not empty and containing non-digits) try to resolve correct monitor index like correlate_wayland does
|
||||
auto index_begin = display_name.find_last_of('-');
|
||||
std::int64_t index;
|
||||
if (index_begin == std::string_view::npos) {
|
||||
index = 1;
|
||||
} else {
|
||||
index = std::max<int64_t>(1, util::from_view(display_name.substr(index_begin + 1)));
|
||||
}
|
||||
auto type = kms::from_view(display_name.substr(0, index_begin));
|
||||
// display_name is a connector name (not empty and containing non-digits)
|
||||
for (auto &card_descriptor : kms::card_descriptors) {
|
||||
for (const auto &monitor_descriptor : card_descriptor.crtc_to_monitor | std::views::values) {
|
||||
if (monitor_descriptor.type == type && monitor_descriptor.index == index) {
|
||||
BOOST_LOG(debug) << "Mapped '"sv << display_name << "' to a monitor index " << monitor_descriptor.monitor_index;
|
||||
if (display_name == std::format("{}-{}", drmModeGetConnectorTypeName(monitor_descriptor.type), monitor_descriptor.index)) {
|
||||
BOOST_LOG(info) << "Mapped '"sv << display_name << "' to kmsgrab monitor index " << monitor_descriptor.monitor_index;
|
||||
return monitor_descriptor.monitor_index;
|
||||
}
|
||||
}
|
||||
@@ -2171,6 +2163,7 @@ namespace platf {
|
||||
|
||||
kms::card_descriptors = std::move(cds);
|
||||
|
||||
BOOST_LOG(debug) << "Final KMS display_names return list: " << (display_names | std::views::join_with(' ') | std::ranges::to<std::string>());
|
||||
return display_names;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,8 +272,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
key_map
|
||||
);
|
||||
|
||||
if (temp_map >= kKeyCodesMap + sizeof(kKeyCodesMap) / sizeof(kKeyCodesMap[0]) ||
|
||||
temp_map->win_keycode != keycode || temp_map->mac_keycode == -1) {
|
||||
if (temp_map >= kKeyCodesMap + sizeof(kKeyCodesMap) / sizeof(kKeyCodesMap[0]) || temp_map->win_keycode != keycode || temp_map->mac_keycode == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,8 +90,7 @@ namespace platf {
|
||||
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) {10, 15, 0})] &&
|
||||
// Double check that these weakly-linked symbols have been loaded:
|
||||
CGPreflightScreenCaptureAccess != nullptr && CGRequestScreenCaptureAccess != nullptr &&
|
||||
!CGPreflightScreenCaptureAccess()) {
|
||||
CGPreflightScreenCaptureAccess != nullptr && CGRequestScreenCaptureAccess != nullptr && !CGPreflightScreenCaptureAccess()) {
|
||||
BOOST_LOG(error) << "No screen capture permission!"sv;
|
||||
BOOST_LOG(error) << "Please activate it in 'System Preferences' -> 'Privacy' -> 'Screen Recording'"sv;
|
||||
CGRequestScreenCaptureAccess();
|
||||
|
||||
@@ -377,9 +377,7 @@ namespace platf::audio {
|
||||
}
|
||||
|
||||
// Prefer the native channel layout of captured audio device when channel counts match
|
||||
if (mixer_waveformat->nChannels == format.channel_count &&
|
||||
mixer_waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||
mixer_waveformat->cbSize >= 22) {
|
||||
if (mixer_waveformat->nChannels == format.channel_count && mixer_waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE && mixer_waveformat->cbSize >= 22) {
|
||||
auto waveformatext_pointer = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(mixer_waveformat.get());
|
||||
capture_waveformat.dwChannelMask = waveformatext_pointer->dwChannelMask;
|
||||
}
|
||||
@@ -765,8 +763,7 @@ namespace platf::audio {
|
||||
for (
|
||||
status = audio_capture->GetNextPacketSize(&packet_size);
|
||||
SUCCEEDED(status) && packet_size > 0;
|
||||
status = audio_capture->GetNextPacketSize(&packet_size)
|
||||
) {
|
||||
status = audio_capture->GetNextPacketSize(&packet_size)) {
|
||||
DWORD buffer_flags;
|
||||
status = audio_capture->GetBuffer(
|
||||
(BYTE **) &sample_aligned.samples,
|
||||
|
||||
@@ -28,7 +28,7 @@ typedef long NTSTATUS;
|
||||
/**
|
||||
* @brief Enumerates supported d3 DKMT GPU PREFERENCE QUERY STATE options.
|
||||
*/
|
||||
typedef enum _D3DKMT_GPU_PREFERENCE_QUERY_STATE: DWORD {
|
||||
typedef enum _D3DKMT_GPU_PREFERENCE_QUERY_STATE : DWORD {
|
||||
D3DKMT_GPU_PREFERENCE_STATE_UNINITIALIZED, ///< The GPU preference isn't initialized.
|
||||
D3DKMT_GPU_PREFERENCE_STATE_HIGH_PERFORMANCE, ///< The highest performing GPU is preferred.
|
||||
D3DKMT_GPU_PREFERENCE_STATE_MINIMUM_POWER, ///< The minimum-powered GPU is preferred.
|
||||
|
||||
@@ -24,9 +24,7 @@ extern "C" {
|
||||
#include "src/config.h"
|
||||
#include "src/logging.h"
|
||||
#include "src/nvenc/nvenc_config.h"
|
||||
#include "src/nvenc/nvenc_d3d11_native.h"
|
||||
#include "src/nvenc/nvenc_d3d11_on_cuda.h"
|
||||
#include "src/nvenc/nvenc_utils.h"
|
||||
#include "src/nvenc/nvenc_dynamic_factory.h"
|
||||
#include "src/video.h"
|
||||
#include "utf_utils.h"
|
||||
|
||||
@@ -557,9 +555,7 @@ namespace platf::dxgi {
|
||||
void apply_colorspace(const ::video::sunshine_colorspace_t &colorspace) {
|
||||
auto color_vectors = ::video::color_vectors_from_colorspace(colorspace, true);
|
||||
|
||||
if (format == DXGI_FORMAT_AYUV ||
|
||||
format == DXGI_FORMAT_R16_UINT ||
|
||||
format == DXGI_FORMAT_Y410) {
|
||||
if (format == DXGI_FORMAT_AYUV || format == DXGI_FORMAT_R16_UINT || format == DXGI_FORMAT_Y410) {
|
||||
color_vectors = ::video::color_vectors_from_colorspace(colorspace, false);
|
||||
}
|
||||
|
||||
@@ -1240,21 +1236,25 @@ namespace platf::dxgi {
|
||||
* @return True when the D3D11 device resources are initialized.
|
||||
*/
|
||||
bool init_device(std::shared_ptr<platf::display_t> display, adapter_t::pointer adapter_p, pix_fmt_e pix_fmt) {
|
||||
buffer_format = nvenc::nvenc_format_from_sunshine_format(pix_fmt);
|
||||
if (buffer_format == NV_ENC_BUFFER_FORMAT_UNDEFINED) {
|
||||
BOOST_LOG(error) << "Unexpected pixel format for NvENC ["sv << from_pix_fmt(pix_fmt) << ']';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (base.init(display, adapter_p, pix_fmt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pix_fmt == pix_fmt_e::yuv444p16) {
|
||||
nvenc_d3d = std::make_unique<nvenc::nvenc_d3d11_on_cuda>(base.device.get());
|
||||
} else {
|
||||
nvenc_d3d = std::make_unique<nvenc::nvenc_d3d11_native>(base.device.get());
|
||||
auto factory = nvenc::nvenc_dynamic_factory::get();
|
||||
if (!factory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pix_fmt == pix_fmt_e::yuv444p16) {
|
||||
nvenc_d3d = factory->create_nvenc_d3d11_on_cuda(base.device.get());
|
||||
} else {
|
||||
nvenc_d3d = factory->create_nvenc_d3d11_native(base.device.get());
|
||||
}
|
||||
if (!nvenc_d3d) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer_format = pix_fmt;
|
||||
nvenc = nvenc_d3d.get();
|
||||
|
||||
return true;
|
||||
@@ -1272,8 +1272,7 @@ namespace platf::dxgi {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto nvenc_colorspace = nvenc::nvenc_colorspace_from_sunshine_colorspace(colorspace);
|
||||
if (!nvenc_d3d->create_encoder(config::video.nv, client_config, nvenc_colorspace, buffer_format)) {
|
||||
if (!nvenc_d3d->create_encoder(config::video.nv, client_config, colorspace, buffer_format)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1293,8 +1292,8 @@ namespace platf::dxgi {
|
||||
|
||||
private:
|
||||
d3d_base_encode_device base;
|
||||
std::unique_ptr<nvenc::nvenc_d3d11> nvenc_d3d;
|
||||
NV_ENC_BUFFER_FORMAT buffer_format = NV_ENC_BUFFER_FORMAT_UNDEFINED;
|
||||
std::unique_ptr<nvenc::nvenc_d3d11_interface> nvenc_d3d;
|
||||
platf::pix_fmt_e buffer_format = platf::pix_fmt_e::unknown;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1392,8 +1391,7 @@ namespace platf::dxgi {
|
||||
auto alpha_cursor_img = make_cursor_alpha_image(img_data, shape_info);
|
||||
auto xor_cursor_img = make_cursor_xor_image(img_data, shape_info);
|
||||
|
||||
if (!set_cursor_texture(device.get(), cursor_alpha, std::move(alpha_cursor_img), shape_info) ||
|
||||
!set_cursor_texture(device.get(), cursor_xor, std::move(xor_cursor_img), shape_info)) {
|
||||
if (!set_cursor_texture(device.get(), cursor_alpha, std::move(alpha_cursor_img), shape_info) || !set_cursor_texture(device.get(), cursor_xor, std::move(xor_cursor_img), shape_info)) {
|
||||
return capture_e::error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,7 @@ namespace platf::dxgi {
|
||||
display->output->GetDesc(&output_desc);
|
||||
|
||||
auto monitor_factory = winrt::get_activation_factory<winrt::GraphicsCaptureItem, IGraphicsCaptureItemInterop>();
|
||||
if (monitor_factory == nullptr ||
|
||||
FAILED(status = monitor_factory->CreateForMonitor(output_desc.Monitor, winrt::guid_of<winrt::IGraphicsCaptureItem>(), winrt::put_abi(item)))) {
|
||||
if (monitor_factory == nullptr || FAILED(status = monitor_factory->CreateForMonitor(output_desc.Monitor, winrt::guid_of<winrt::IGraphicsCaptureItem>(), winrt::put_abi(item)))) {
|
||||
BOOST_LOG(error) << "Screen capture is not supported on this device for this release of Windows: failed to acquire display: [0x"sv << util::hex(status).to_string_view() << ']';
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -401,8 +401,7 @@ namespace platf {
|
||||
uint16_t normalizedSmallMotor = smallMotor << 8;
|
||||
|
||||
// Don't resend duplicate rumble data
|
||||
if (normalizedSmallMotor != gamepad.last_rumble.data.rumble.highfreq ||
|
||||
normalizedLargeMotor != gamepad.last_rumble.data.rumble.lowfreq) {
|
||||
if (normalizedSmallMotor != gamepad.last_rumble.data.rumble.highfreq || normalizedLargeMotor != gamepad.last_rumble.data.rumble.lowfreq) {
|
||||
// We have to use the client-relative index when communicating back to the client
|
||||
gamepad_feedback_msg_t msg = gamepad_feedback_msg_t::make_rumble(
|
||||
gamepad.client_relative_index,
|
||||
@@ -430,9 +429,7 @@ namespace platf {
|
||||
|
||||
if (gamepad.gp.get() == target) {
|
||||
// Don't resend duplicate RGB data
|
||||
if (r != gamepad.last_rgb_led.data.rgb_led.r ||
|
||||
g != gamepad.last_rgb_led.data.rgb_led.g ||
|
||||
b != gamepad.last_rgb_led.data.rgb_led.b) {
|
||||
if (r != gamepad.last_rgb_led.data.rgb_led.r || g != gamepad.last_rgb_led.data.rgb_led.g || b != gamepad.last_rgb_led.data.rgb_led.b) {
|
||||
// We have to use the client-relative index when communicating back to the client
|
||||
gamepad_feedback_msg_t msg = gamepad_feedback_msg_t::make_rgb_led(gamepad.client_relative_index, r, g, b);
|
||||
gamepad.feedback_queue->raise(msg);
|
||||
@@ -822,8 +819,7 @@ namespace platf {
|
||||
|
||||
// Try to find a matching pointer ID
|
||||
for (UINT32 i = 0; i < ARRAYSIZE(raw->touchInfo); i++) {
|
||||
if (raw->touchInfo[i].touchInfo.pointerInfo.pointerId == pointerId &&
|
||||
raw->touchInfo[i].touchInfo.pointerInfo.pointerFlags != POINTER_FLAG_NONE) {
|
||||
if (raw->touchInfo[i].touchInfo.pointerInfo.pointerId == pointerId && raw->touchInfo[i].touchInfo.pointerInfo.pointerFlags != POINTER_FLAG_NONE) {
|
||||
if (eventType == LI_TOUCH_EVENT_DOWN && (raw->touchInfo[i].touchInfo.pointerInfo.pointerFlags & POINTER_FLAG_INCONTACT)) {
|
||||
BOOST_LOG(warning) << "Pointer "sv << pointerId << " already down. Did the client drop an up/cancel event?"sv;
|
||||
}
|
||||
@@ -982,9 +978,7 @@ namespace platf {
|
||||
auto raw = (client_input_raw_t *) input;
|
||||
|
||||
// Bail if we're not running on an OS that supports virtual touch input
|
||||
if (!raw->global->fnCreateSyntheticPointerDevice ||
|
||||
!raw->global->fnInjectSyntheticPointerInput ||
|
||||
!raw->global->fnDestroySyntheticPointerDevice) {
|
||||
if (!raw->global->fnCreateSyntheticPointerDevice || !raw->global->fnInjectSyntheticPointerInput || !raw->global->fnDestroySyntheticPointerDevice) {
|
||||
BOOST_LOG(warning) << "Touch input requires Windows 10 1809 or later"sv;
|
||||
return;
|
||||
}
|
||||
@@ -1108,9 +1102,7 @@ namespace platf {
|
||||
auto raw = (client_input_raw_t *) input;
|
||||
|
||||
// Bail if we're not running on an OS that supports virtual pen input
|
||||
if (!raw->global->fnCreateSyntheticPointerDevice ||
|
||||
!raw->global->fnInjectSyntheticPointerInput ||
|
||||
!raw->global->fnDestroySyntheticPointerDevice) {
|
||||
if (!raw->global->fnCreateSyntheticPointerDevice || !raw->global->fnInjectSyntheticPointerInput || !raw->global->fnDestroySyntheticPointerDevice) {
|
||||
BOOST_LOG(warning) << "Pen input requires Windows 10 1809 or later"sv;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,8 +100,7 @@ namespace {
|
||||
bool nt_set_timer_resolution_max() {
|
||||
ULONG maximum;
|
||||
ULONG minimum;
|
||||
if (ULONG current; !NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, ¤t)) ||
|
||||
!NT_SUCCESS(NtSetTimerResolution(maximum, TRUE, ¤t))) {
|
||||
if (ULONG current; !NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, ¤t)) || !NT_SUCCESS(NtSetTimerResolution(maximum, TRUE, ¤t))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -110,8 +109,7 @@ namespace {
|
||||
bool nt_set_timer_resolution_min() {
|
||||
ULONG maximum;
|
||||
ULONG minimum;
|
||||
if (ULONG current; !NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, ¤t)) ||
|
||||
!NT_SUCCESS(NtSetTimerResolution(minimum, TRUE, ¤t))) {
|
||||
if (ULONG current; !NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, ¤t)) || !NT_SUCCESS(NtSetTimerResolution(minimum, TRUE, ¤t))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -270,8 +270,7 @@ namespace nvprefs {
|
||||
status = NvAPI_DRS_GetSetting(session_handle, profile_handle, PREFERRED_PSTATE_ID, &setting);
|
||||
|
||||
if (!get_nvprefs_options().sunshine_high_power_mode) {
|
||||
if (status == NVAPI_OK &&
|
||||
setting.settingLocation == NVDRS_CURRENT_PROFILE_LOCATION) {
|
||||
if (status == NVAPI_OK && setting.settingLocation == NVDRS_CURRENT_PROFILE_LOCATION) {
|
||||
// User requested to not use high power mode for sunshine.exe,
|
||||
// remove the setting from application profile if it's been set previously
|
||||
|
||||
@@ -285,9 +284,7 @@ namespace nvprefs {
|
||||
|
||||
info_message(std::wstring(L"Removed PREFERRED_PSTATE for ") + sunshine_application_path);
|
||||
}
|
||||
} else if (status != NVAPI_OK ||
|
||||
setting.settingLocation != NVDRS_CURRENT_PROFILE_LOCATION ||
|
||||
setting.u32CurrentValue != PREFERRED_PSTATE_PREFER_MAX) {
|
||||
} else if (status != NVAPI_OK || setting.settingLocation != NVDRS_CURRENT_PROFILE_LOCATION || setting.u32CurrentValue != PREFERRED_PSTATE_PREFER_MAX) {
|
||||
// Set power setting if needed
|
||||
setting = {};
|
||||
setting.version = NVDRS_SETTING_VER1;
|
||||
|
||||
@@ -204,8 +204,7 @@ namespace nvprefs {
|
||||
}
|
||||
|
||||
// Restore global profile settings with undo data
|
||||
if (pimpl->driver_settings.restore_global_profile_to_undo(*pimpl->undo_data) &&
|
||||
pimpl->driver_settings.save_settings()) {
|
||||
if (pimpl->driver_settings.restore_global_profile_to_undo(*pimpl->undo_data) && pimpl->driver_settings.save_settings()) {
|
||||
// Global profile settings sucessfully restored, can delete undo file
|
||||
if (!pimpl->undo_file->delete_file()) {
|
||||
error_message("Couldn't delete undo file");
|
||||
|
||||
+1
-2
@@ -301,8 +301,7 @@ namespace proc {
|
||||
} else if (_process.running()) {
|
||||
// The app is still running only if the initial process launched is still running
|
||||
return _app_id;
|
||||
} else if (_app.auto_detach && _process.native_exit_code() == 0 &&
|
||||
std::chrono::steady_clock::now() - _app_launch_time < 5s) {
|
||||
} else if (_app.auto_detach && _process.native_exit_code() == 0 && std::chrono::steady_clock::now() - _app_launch_time < 5s) {
|
||||
BOOST_LOG(info) << "App exited gracefully within 5 seconds of launch. Treating the app as a detached command."sv;
|
||||
BOOST_LOG(info) << "Adjust this behavior in the Applications tab or apps.json if this is not what you want."sv;
|
||||
placebo = true;
|
||||
|
||||
+1
-2
@@ -1289,8 +1289,7 @@ namespace rtsp_stream {
|
||||
|
||||
// Check that any required encryption is enabled
|
||||
auto encryption_mode = net::encryption_mode_for_address(sock.remote_endpoint().address());
|
||||
if (encryption_mode == config::ENCRYPTION_MODE_MANDATORY &&
|
||||
(config.encryptionFlagsEnabled & (SS_ENC_VIDEO | SS_ENC_AUDIO)) != (SS_ENC_VIDEO | SS_ENC_AUDIO)) {
|
||||
if (encryption_mode == config::ENCRYPTION_MODE_MANDATORY && (config.encryptionFlagsEnabled & (SS_ENC_VIDEO | SS_ENC_AUDIO)) != (SS_ENC_VIDEO | SS_ENC_AUDIO)) {
|
||||
BOOST_LOG(error) << "Rejecting client that cannot comply with mandatory encryption requirement"sv;
|
||||
|
||||
respond(sock, session, &option, 403, "Forbidden", req->sequenceNumber, {});
|
||||
|
||||
+2
-4
@@ -1711,13 +1711,11 @@ namespace stream {
|
||||
session->video.cipher->encrypt(std::string_view {(char *) inspect, (size_t) blocksize}, prefix->tag, (uint8_t *) inspect, &iv);
|
||||
}
|
||||
|
||||
if (x - next_shard_to_send + 1 >= send_batch_size ||
|
||||
x + 1 == shards.size()) {
|
||||
if (x - next_shard_to_send + 1 >= send_batch_size || x + 1 == shards.size()) {
|
||||
// Do pacing within the frame.
|
||||
// Also trigger pacing before the first send_batch() of the frame
|
||||
// to account for the last send_batch() of the previous frame.
|
||||
if (ratecontrol_group_packets_sent >= ratecontrol_packets_in_1ms ||
|
||||
ratecontrol_frame_packets_sent == 0) {
|
||||
if (ratecontrol_group_packets_sent >= ratecontrol_packets_in_1ms || ratecontrol_frame_packets_sent == 0) {
|
||||
auto due = ratecontrol_frame_start +
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(1ms) *
|
||||
ratecontrol_frame_packets_sent / ratecontrol_packets_in_1ms;
|
||||
|
||||
+40
-29
@@ -5,6 +5,27 @@
|
||||
// macros
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
|
||||
/**
|
||||
* @def TRAY_ICON
|
||||
* @brief Path to the default system tray icon.
|
||||
*/
|
||||
#define TRAY_ICON WEB_DIR "images/logo-sunshine.svg"
|
||||
/**
|
||||
* @def TRAY_ICON_PLAYING
|
||||
* @brief Path to the system tray icon used while streaming.
|
||||
*/
|
||||
#define TRAY_ICON_PLAYING WEB_DIR "images/sunshine-playing.svg"
|
||||
/**
|
||||
* @def TRAY_ICON_PAUSING
|
||||
* @brief Path to the system tray icon used while streaming is paused.
|
||||
*/
|
||||
#define TRAY_ICON_PAUSING WEB_DIR "images/sunshine-pausing.svg"
|
||||
/**
|
||||
* @def TRAY_ICON_LOCKED
|
||||
* @brief Path to the system tray icon used for pairing requests.
|
||||
*/
|
||||
#define TRAY_ICON_LOCKED WEB_DIR "images/sunshine-locked.svg"
|
||||
|
||||
#if defined(_WIN32)
|
||||
/**
|
||||
* @def WIN32_LEAN_AND_MEAN
|
||||
@@ -13,36 +34,7 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <accctrl.h>
|
||||
#include <aclapi.h>
|
||||
/**
|
||||
* @def TRAY_ICON
|
||||
* @brief Macro for TRAY ICON.
|
||||
*/
|
||||
#define TRAY_ICON WEB_DIR "images/sunshine.ico"
|
||||
/**
|
||||
* @def TRAY_ICON_PLAYING
|
||||
* @brief Macro for TRAY ICON PLAYING.
|
||||
*/
|
||||
#define TRAY_ICON_PLAYING WEB_DIR "images/sunshine-playing.ico"
|
||||
/**
|
||||
* @def TRAY_ICON_PAUSING
|
||||
* @brief Macro for TRAY ICON PAUSING.
|
||||
*/
|
||||
#define TRAY_ICON_PAUSING WEB_DIR "images/sunshine-pausing.ico"
|
||||
/**
|
||||
* @def TRAY_ICON_LOCKED
|
||||
* @brief Macro for TRAY ICON LOCKED.
|
||||
*/
|
||||
#define TRAY_ICON_LOCKED WEB_DIR "images/sunshine-locked.ico"
|
||||
#elif defined(__linux__) || defined(linux) || defined(__linux) || defined(__FreeBSD__)
|
||||
#define TRAY_ICON WEB_DIR "images/logo-sunshine.svg"
|
||||
#define TRAY_ICON_PLAYING WEB_DIR "images/sunshine-playing.svg"
|
||||
#define TRAY_ICON_PAUSING WEB_DIR "images/sunshine-pausing.svg"
|
||||
#define TRAY_ICON_LOCKED WEB_DIR "images/sunshine-locked.svg"
|
||||
#elif defined(__APPLE__) || defined(__MACH__)
|
||||
#define TRAY_ICON WEB_DIR "images/logo-sunshine-16.png"
|
||||
#define TRAY_ICON_PLAYING WEB_DIR "images/sunshine-playing-16.png"
|
||||
#define TRAY_ICON_PAUSING WEB_DIR "images/sunshine-pausing-16.png"
|
||||
#define TRAY_ICON_LOCKED WEB_DIR "images/sunshine-locked-16.png"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <unordered_map>
|
||||
@@ -176,6 +168,25 @@ namespace system_tray {
|
||||
.allIconPaths = {TRAY_ICON, TRAY_ICON_LOCKED, TRAY_ICON_PLAYING, TRAY_ICON_PAUSING},
|
||||
};
|
||||
|
||||
#ifdef SUNSHINE_TESTS
|
||||
const struct tray &tray_data_for_testing() {
|
||||
return tray;
|
||||
}
|
||||
|
||||
bool tray_initialized_for_testing() {
|
||||
return tray_initialized;
|
||||
}
|
||||
|
||||
void reset_tray_data_for_testing() {
|
||||
tray.icon = tray.allIconPaths[0];
|
||||
tray.tooltip = PROJECT_NAME;
|
||||
tray.notification_icon = nullptr;
|
||||
tray.notification_text = nullptr;
|
||||
tray.notification_title = nullptr;
|
||||
tray.notification_cb = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get resource path.
|
||||
*
|
||||
|
||||
@@ -96,4 +96,25 @@ namespace system_tray {
|
||||
* @return 0 if initialization was successful, non-zero otherwise.
|
||||
*/
|
||||
int init_tray_threaded();
|
||||
|
||||
#ifdef SUNSHINE_TESTS
|
||||
/**
|
||||
* @brief Get the tray data used by the system tray implementation.
|
||||
*
|
||||
* @return Read-only tray data for unit-test assertions.
|
||||
*/
|
||||
const struct tray &tray_data_for_testing();
|
||||
|
||||
/**
|
||||
* @brief Check whether the system tray is initialized.
|
||||
*
|
||||
* @return true if the system tray is initialized; otherwise, false.
|
||||
*/
|
||||
bool tray_initialized_for_testing();
|
||||
|
||||
/**
|
||||
* @brief Restore the persistent tray data to its initial state between tests.
|
||||
*/
|
||||
void reset_tray_data_for_testing();
|
||||
#endif
|
||||
} // namespace system_tray
|
||||
|
||||
+10
-15
@@ -18,6 +18,9 @@ extern "C" {
|
||||
#include <libavutil/mastering_display_metadata.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
#include <ffnvcodec/nvEncodeAPI.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
// local includes
|
||||
@@ -27,7 +30,7 @@ extern "C" {
|
||||
#include "globals.h"
|
||||
#include "input.h"
|
||||
#include "logging.h"
|
||||
#include "nvenc/nvenc_base.h"
|
||||
#include "nvenc/nvenc_encoder.h"
|
||||
#include "platform/common.h"
|
||||
#include "sync.h"
|
||||
#include "video.h"
|
||||
@@ -3135,9 +3138,7 @@ namespace video {
|
||||
|
||||
auto encoder_codec_name = encoder.codec_from_config(config).name;
|
||||
|
||||
if ((encoder.flags & YUV444_SUPPORT) &&
|
||||
disp->is_codec_supported(encoder_codec_name, config) &&
|
||||
validate_config(disp, encoder, config) >= 0) {
|
||||
if ((encoder.flags & YUV444_SUPPORT) && disp->is_codec_supported(encoder_codec_name, config) && validate_config(disp, encoder, config) >= 0) {
|
||||
flag_map[encoder_t::YUV444] = true;
|
||||
} else {
|
||||
flag_map[encoder_t::YUV444] = false;
|
||||
@@ -3177,9 +3178,7 @@ namespace video {
|
||||
|
||||
auto encoder_codec_name = encoder.codec_from_config(config).name;
|
||||
|
||||
if ((encoder.flags & YUV444_SUPPORT) &&
|
||||
disp->is_codec_supported(encoder_codec_name, config) &&
|
||||
validate_config(disp, encoder, config) >= 0) {
|
||||
if ((encoder.flags & YUV444_SUPPORT) && disp->is_codec_supported(encoder_codec_name, config) && validate_config(disp, encoder, config) >= 0) {
|
||||
flag_map[encoder_t::DYNAMIC_RANGE_YUV444] = true;
|
||||
} else {
|
||||
flag_map[encoder_t::DYNAMIC_RANGE_YUV444] = false;
|
||||
@@ -3309,29 +3308,25 @@ namespace video {
|
||||
}
|
||||
|
||||
// Skip it if it doesn't support the specified codec at all
|
||||
if ((active_hevc_mode >= 2 && !encoder->hevc[encoder_t::PASSED]) ||
|
||||
(active_av1_mode >= 2 && !encoder->av1[encoder_t::PASSED])) {
|
||||
if ((active_hevc_mode >= 2 && !encoder->hevc[encoder_t::PASSED]) || (active_av1_mode >= 2 && !encoder->av1[encoder_t::PASSED])) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip it if it doesn't support HDR on the specified codec
|
||||
if ((active_hevc_mode == 5 && !encoder->hevc[encoder_t::DYNAMIC_RANGE] && !encoder->hevc[encoder_t::DYNAMIC_RANGE_YUV444]) ||
|
||||
(active_av1_mode == 5 && !encoder->av1[encoder_t::DYNAMIC_RANGE] && !encoder->av1[encoder_t::DYNAMIC_RANGE_YUV444])) {
|
||||
if ((active_hevc_mode == 5 && !encoder->hevc[encoder_t::DYNAMIC_RANGE] && !encoder->hevc[encoder_t::DYNAMIC_RANGE_YUV444]) || (active_av1_mode == 5 && !encoder->av1[encoder_t::DYNAMIC_RANGE] && !encoder->av1[encoder_t::DYNAMIC_RANGE_YUV444])) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip it if it doesn't support HDR on the specified codec
|
||||
if ((active_hevc_mode == 4 && !encoder->hevc[encoder_t::DYNAMIC_RANGE_YUV444]) ||
|
||||
(active_av1_mode == 4 && !encoder->av1[encoder_t::DYNAMIC_RANGE_YUV444])) {
|
||||
if ((active_hevc_mode == 4 && !encoder->hevc[encoder_t::DYNAMIC_RANGE_YUV444]) || (active_av1_mode == 4 && !encoder->av1[encoder_t::DYNAMIC_RANGE_YUV444])) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip it if it doesn't support HDR on the specified codec
|
||||
if ((active_hevc_mode == 3 && !encoder->hevc[encoder_t::DYNAMIC_RANGE]) ||
|
||||
(active_av1_mode == 3 && !encoder->av1[encoder_t::DYNAMIC_RANGE])) {
|
||||
if ((active_hevc_mode == 3 && !encoder->hevc[encoder_t::DYNAMIC_RANGE]) || (active_av1_mode == 3 && !encoder->av1[encoder_t::DYNAMIC_RANGE])) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"disabled_def_cbox": "Par défaut : décoché",
|
||||
"dismiss": "Ignorer",
|
||||
"do_cmd": "Commande de début",
|
||||
"elevated": "Élevée",
|
||||
"elevated": "Permissions élevées",
|
||||
"enabled": "Activé",
|
||||
"enabled_def": "Activé (par défaut)",
|
||||
"enabled_def_cbox": "Par défaut : décoché",
|
||||
@@ -23,7 +23,7 @@
|
||||
"loading": "Chargement en cours...",
|
||||
"note": "Note :",
|
||||
"password": "Mot de passe",
|
||||
"run_as": "Exécuter en tant qu'Administrateur",
|
||||
"run_as": "Exécuter en tant qu'administrateur",
|
||||
"save": "Sauvegarder",
|
||||
"search": "Rechercher...",
|
||||
"see_more": "Voir plus",
|
||||
@@ -42,11 +42,11 @@
|
||||
"applications_title": "Applications",
|
||||
"auto_detach": "Continuer le streaming si l'application quitte rapidement",
|
||||
"auto_detach_desc": "Cela va tenter de détecter automatiquement les applications de type launcher qui se ferment rapidement après le lancement d'un autre programme ou d'une instance d'eux-mêmes. Lorsqu'une application de type lanceur est détectée, elle est traitée comme une application détachée.",
|
||||
"badge_admin": "Administrateur",
|
||||
"badge_app_prep": "Préparation de l'application",
|
||||
"badge_auto_detach": "Auto-detach",
|
||||
"badge_detached": "Détaché",
|
||||
"badge_no_global_prep": "Pas de préparation globale",
|
||||
"badge_admin": "Admin",
|
||||
"badge_app_prep": "Prép. de l'app",
|
||||
"badge_auto_detach": "Détach. auto",
|
||||
"badge_detached": "Détachée(s)",
|
||||
"badge_no_global_prep": "Sans prép. globale",
|
||||
"cmd": "Commande",
|
||||
"cmd_desc": "L'application principale à démarrer. Si vide, aucune application ne sera démarrée.",
|
||||
"cmd_note": "Si le chemin vers l'exécutable de la commande contient des espaces, vous devez l'entourer de guillemets.",
|
||||
@@ -89,13 +89,13 @@
|
||||
"loading": "Chargement...",
|
||||
"name": "Nom",
|
||||
"no_applications": "Aucune application n'a encore été ajoutée",
|
||||
"no_covers_found": "Aucune pochette trouvée",
|
||||
"no_covers_found": "Aucune jaquette trouvée",
|
||||
"no_search_results": "Aucune application ne correspond à votre recherche",
|
||||
"output_desc": "Le fichier dans lequel la sortie de la commande est stockée, s'il n'est pas spécifié, la sortie est ignorée",
|
||||
"output_name": "Sortie",
|
||||
"run_as_desc": "Cela peut être nécessaire pour certaines applications qui nécessitent des autorisations d'administrateur pour fonctionner correctement.",
|
||||
"search_placeholder": "Rechercher des applications...",
|
||||
"searching_covers": "Recherche de pochettes...",
|
||||
"searching_covers": "Recherche de jaquettes...",
|
||||
"sort_ascending": "Ascendant",
|
||||
"sort_by_name": "Trier par nom",
|
||||
"sort_default": "Ordre par défaut",
|
||||
@@ -174,13 +174,13 @@
|
||||
"coder_cabac": "cabac -- contexte de codage arithmétique binaire adaptatif - qualité supérieure",
|
||||
"coder_cavlc": "cavlc -- codage de la durée adaptative du contexte - décodage plus rapide",
|
||||
"configuration": "Configuration",
|
||||
"configuration_desc": "Configurer les paramètres de l'hôte de Sunshine pour correspondre à votre configuration de streaming.",
|
||||
"configuration_desc": "Configurer les paramètres de l'hôte Sunshine pour correspondre à votre configuration de streaming.",
|
||||
"controller": "Activer l'entrée manette",
|
||||
"controller_desc": "Permet aux invités de contrôler le système hôte avec une manette",
|
||||
"credentials_file": "Fichier des identifiants",
|
||||
"credentials_file_desc": "Stocker le nom d'utilisateur/mot de passe séparément du fichier de données de Sunshine.",
|
||||
"csrf_allowed_origins": "Origines CSRF autorisées",
|
||||
"csrf_allowed_origins_desc": "Liste séparée par des virgules des origines autorisées pour la protection CSRF (ajoutée aux valeurs par défaut : variantes localhost et port UI web). Ajoute uniquement les origines en qui vous avez confiance. Chaque origine doit inclure le protocole et l'hôte (par exemple, https://example.com).",
|
||||
"csrf_allowed_origins_desc": "Liste séparée par des virgules des origines autorisées pour la protection CSRF (ajoutée aux valeurs par défaut : variantes localhost et port UI web). Ajoutez uniquement les origines en qui vous avez confiance. Chaque origine doit inclure le protocole et l'hôte (par exemple, https://example.com).",
|
||||
"dd_config_ensure_active": "Activer l'affichage automatiquement",
|
||||
"dd_config_ensure_only_display": "Désactiver les autres affichages et n'activer que l'affichage spécifié",
|
||||
"dd_config_ensure_primary": "Activer l'affichage automatiquement et en faire un affichage principal",
|
||||
@@ -224,7 +224,7 @@
|
||||
"dd_wa_hdr_toggle_delay": "Activer la solution de contournement à haut contraste pour HDR",
|
||||
"ds4_back_as_touchpad_click": "Mapper Retour/Sélection au clic du pavé tactile",
|
||||
"ds4_back_as_touchpad_click_desc": "Lorsque vous forcez l'émulation DS4, mappez le bouton Retour/Sélection sur le clic du pavé tactile.",
|
||||
"ds5_inputtino_randomize_mac": "Aléatoire du contrôleur virtuel MAC",
|
||||
"ds5_inputtino_randomize_mac": "Randomiser le MAC du contrôleur virtuel",
|
||||
"ds5_inputtino_randomize_mac_desc": "Lors de l'enregistrement du contrôleur, utilisez un MAC aléatoire au lieu d'un MAC basé sur l'index interne des contrôleurs pour éviter de mélanger les paramètres de configuration des différents contrôleurs lorsque ceux-ci sont échangés côté client.",
|
||||
"encoder": "Forcer un encodeur spécifique",
|
||||
"encoder_desc": "Forcer un encodeur spécifique, sinon Sunshine sélectionnera la meilleure option disponible. Note : Si vous spécifiez un encodeur matériel sous Windows, il doit correspondre au GPU où l'affichage est connecté.",
|
||||
@@ -315,7 +315,7 @@
|
||||
"nvenc_preset_desc": "Des nombres plus élevés améliorent la compression (qualité à un débit donné) au prix d'une latence d'encodage accrue. Il est recommandé de modifier uniquement lorsque limité par le réseau ou le décodage, sinon l'effet similaire peut être atteint en augmentant le débit.",
|
||||
"nvenc_realtime_hags": "Utiliser la priorité en temps réel dans la planification matérielle du gpu accéléré",
|
||||
"nvenc_realtime_hags_desc": "Actuellement, les pilotes NVIDIA peuvent geler dans l'encodeur lorsque HAGS est activé, la priorité en temps réel est utilisée et l'utilisation de VRAM est proche du maximum. Désactiver cette option réduit la priorité à la hauteur, en évitant le gel au prix de performances de capture réduites lorsque le GPU est lourdement chargé.",
|
||||
"nvenc_spatial_aq": "Spatial AQ",
|
||||
"nvenc_spatial_aq": "AQ spatial",
|
||||
"nvenc_spatial_aq_desc": "Assignez des valeurs QP plus élevées aux zones uniformes de la vidéo. Il est conseillé de l'activer lors de la diffusion à des débits binaires réduits.",
|
||||
"nvenc_split_encode": "Encodage d'images fractionnées",
|
||||
"nvenc_split_encode_desc": "Diviser l'encodage de chaque image vidéo en plusieurs unités matérielles NVENC. Réduit considérablement la latence du traitement hôte avec une pénalité marginale d'efficacité de la compression. L'option par défaut active SFE si les conditions suivantes sont remplies : il y a plus de 2 unités NVENC, le flux a une résolution de 4K ou plus, et le préréglage est P1-P4. Réglez cette option sur Activé pour utiliser SFE avec des résolutions inférieures ou des préréglages plus élevés.",
|
||||
@@ -333,8 +333,8 @@
|
||||
"origin_web_ui_allowed_pc": "Seul localhost peut accéder à l'interface Web",
|
||||
"origin_web_ui_allowed_wan": "N'importe qui peut accéder à l'interface Web",
|
||||
"output_name": "Identifiant de l'affichage",
|
||||
"output_name_desc_macos": "Lors du démarrage de Sunshine, vous devriez voir la liste des affichages détectés. Note : Vous devez utiliser la valeur de l'id entre parenthèses. Ci-dessous est un exemple ; la sortie réelle peut être trouvée dans l'onglet Dépannage.",
|
||||
"output_name_desc_unix": "Lors du démarrage de Sunshine, vous devriez voir la liste des affichages détectés. Note : Vous devez utiliser la valeur de l'id entre parenthèses.",
|
||||
"output_name_desc_macos": "Lors du démarrage de Sunshine, vous devriez voir la liste des affichages détectés. Note : vous devez utiliser la valeur de l'id entre parenthèses. Un exemple est affiché ci-dessous ; la sortie réelle peut être trouvée dans l'onglet Dépannage.",
|
||||
"output_name_desc_unix": "Lors du démarrage de Sunshine, vous devriez voir la liste des affichages détectés. Note : il est recommendé d'utiliser le nom de connecteur de l'affichage (par exemple DP-0) mais selon la méthode de capture utilisée d'autres valeurs sont possibles (voir la documentation pour plus de détails). Un exemple est affiché ci-dessous ; la sortie réelle peut être trouvée dans l'onglet Dépannage.",
|
||||
"output_name_desc_windows": "Spécifiez manuellement un identifiant de périphérique d'affichage à utiliser pour la capture. Si ce champ est vide, l'affichage principal sera capturé. Remarque : Si vous avez spécifié un GPU ci-dessus, cet affichage doit être connecté à ce GPU. Lors du démarrage de Sunshine, vous devriez voir la liste des affichages détectés. Ci-dessous un exemple ; la sortie réelle peut être consultée dans l'onglet Dépannage.",
|
||||
"packetsize": "Limite de taille de paquet",
|
||||
"packetsize_desc": "Limitez la taille du paquet pour éviter la fragmentation sur un lien MTU faible. Cela permet de réduire la perte de paquets et le micro-stuttering, tout en streamant via un VPN de couche 2 pour les clients qui ne peuvent pas configurer cette valeur, comme Moonlight pour Android/iOS. Réduisez le débit lorsque vous utilisez des valeurs faibles. Les valeurs supérieures à 1456 requièrent des cadres jumbo. Limites: 0, 200-65536. Une valeur de 0 désactivera la limite.",
|
||||
@@ -400,27 +400,27 @@
|
||||
"upnp_desc": "Configurer automatiquement la redirection de port pour le streaming sur Internet",
|
||||
"vaapi_blbrc": "Contrôle du débit basé sur le niveau de bloc (BLBRC)",
|
||||
"vaapi_blbrc_desc": "Active le contrôle du débit de niveau de bloc, qui assigne différents blocs de débit par bloc. Peut être combiné avec les méthodes de contrôle de débit CBR/VBR-type sur les encodeurs pris en charge.",
|
||||
"vaapi_quality": "VA-API Quality",
|
||||
"vaapi_quality_balanced": "équilibré -- équilibré",
|
||||
"vaapi_quality_desc": "Détermine le compromis entre la qualité et la consommation de vitesse/énergie.",
|
||||
"vaapi_quality": "Qualité VA-API",
|
||||
"vaapi_quality_balanced": "balanced -- équilibré",
|
||||
"vaapi_quality_desc": "Détermine le compromis choisi entre la qualité et la consommation de vitesse/consommation d'énergie.",
|
||||
"vaapi_quality_group": "Paramètres de qualité VA-API",
|
||||
"vaapi_quality_quality": "qualité -- préférer la qualité",
|
||||
"vaapi_quality_speed": "Vitesse -- Préférez la vitesse",
|
||||
"vaapi_quality_quality": "quality -- préférer la qualité",
|
||||
"vaapi_quality_speed": "speed -- privilégier la vitesse",
|
||||
"vaapi_rc": "Contrôle du débit VA-API",
|
||||
"vaapi_rc_avbr": "avbr -- débit variable moyen",
|
||||
"vaapi_rc_cbr": "cbr -- débit constant",
|
||||
"vaapi_rc_cqp": "cqp -- mode constant qp",
|
||||
"vaapi_rc_desc": "Ceci contrôle la méthode de contrôle du débit pour s'assurer que nous ne dépassons pas la cible du bitrate client. Notez que les méthodes de contrôle de débit prises en charge varient selon le vendeur, et que automatiquement peut forcer la mise en application stricte du débit sur certains appareils.",
|
||||
"vaapi_rc_cqp": "cqp -- mode qp constant",
|
||||
"vaapi_rc_desc": "Ceci contrôle la méthode de contrôle du débit pour s'assurer que nous ne dépassons pas la cible du bitrate client. Notez que les méthodes de contrôle de débit prises en charge varient selon le vendeur, et qu'automatiquement peut forcer la mise en application stricte du débit sur certains appareils.",
|
||||
"vaapi_rc_group": "Paramètres de contrôle du débit VA-API",
|
||||
"vaapi_rc_icq": "icq -- mode constant intelligent qp",
|
||||
"vaapi_rc_qvbr": "qvbr -- Débit variable de qualité",
|
||||
"vaapi_rc_vbr": "vbr -- Débit variable",
|
||||
"vaapi_rc_icq": "icq -- mode qp constant intelligent",
|
||||
"vaapi_rc_qvbr": "qvbr -- débit variable défini par la qualité",
|
||||
"vaapi_rc_vbr": "vbr -- débit variable",
|
||||
"vaapi_strict_rc_buffer": "Appliquer strictement les limites de débit d'images pour H.264/HEVC sur les GPU AMD",
|
||||
"vaapi_strict_rc_buffer_desc": "L'activation de cette option peut éviter de laisser tomber des images sur le réseau pendant les changements de scène, mais la qualité de la vidéo peut être réduite pendant le mouvement.",
|
||||
"vk_rc_cbr": "CBR (débit constant) (par défaut)",
|
||||
"vk_rc_cqp": "CQP (Constant QP)",
|
||||
"vk_rc_cqp": "CQP (QP constant)",
|
||||
"vk_rc_mode": "Contrôle du débit",
|
||||
"vk_rc_mode_desc": "Mode de contrôle du débit pour l'encodage. Permet au pilote de décider.",
|
||||
"vk_rc_mode_desc": "Mode de contrôle du débit pour l'encodage. Auto laisse le pilote décider.",
|
||||
"vk_rc_vbr": "VBR (débit variable)",
|
||||
"vk_tune": "Réglage",
|
||||
"vk_tune_desc": "Les modes de faible latence réduisent le délai d'encodage au détriment de la qualité.",
|
||||
@@ -470,26 +470,26 @@
|
||||
"theme_dark": "Sombre",
|
||||
"theme_dracula": "Dracula",
|
||||
"theme_ember": "Braise",
|
||||
"theme_ember_light": "Ember Light",
|
||||
"theme_ember_light": "Braise",
|
||||
"theme_forest": "Forêt",
|
||||
"theme_group_dark": "Thèmes Sombres",
|
||||
"theme_group_light": "Thèmes légers",
|
||||
"theme_group_dark": "Thèmes sombres",
|
||||
"theme_group_light": "Thèmes clairs",
|
||||
"theme_indigo": "Indigo",
|
||||
"theme_latte": "Dernier",
|
||||
"theme_latte": "Latte",
|
||||
"theme_lavender": "Lavande",
|
||||
"theme_light": "Clair",
|
||||
"theme_midnight": "Minuit",
|
||||
"theme_mocha": "Mocha",
|
||||
"theme_mocha": "Moka",
|
||||
"theme_monochrome": "Monochrome",
|
||||
"theme_moonlight": "Moonlight",
|
||||
"theme_moonlight": "Clair de lune",
|
||||
"theme_nord": "Nord",
|
||||
"theme_ocean": "Océan",
|
||||
"theme_random": "Aléatoire",
|
||||
"theme_rose": "Rose",
|
||||
"theme_rose_pine": "Pin de rose",
|
||||
"theme_rose_pine_dawn": "Rosé Aube Pine",
|
||||
"theme_rose_pine": "Rosé Pine",
|
||||
"theme_rose_pine_dawn": "Rosé Pine dawn",
|
||||
"theme_slate": "Ardoise",
|
||||
"theme_sunshine": "Sunshine",
|
||||
"theme_sunshine": "Rayon de soleil",
|
||||
"toggle_theme": "Thème",
|
||||
"troubleshoot": "Dépannage"
|
||||
},
|
||||
@@ -504,7 +504,7 @@
|
||||
"new_creds": "Nouveaux identifiants",
|
||||
"new_username_desc": "S'il n'est pas spécifié, le nom d'utilisateur ne changera pas",
|
||||
"password_change": "Changement du mot de passe",
|
||||
"password_change_desc": "Mettez à jour le nom d'utilisateur et le mot de passe utilisés pour se connecter à l'interface web Sunshine. Vous devrez vous reconnecter après les avoir changés.",
|
||||
"password_change_desc": "Mettez à jour le nom d'utilisateur et le mot de passe utilisés pour se connecter à l'interface web de Sunshine. Vous devrez vous reconnecter après les avoir changés.",
|
||||
"success_msg": "Le mot de passe a été modifié avec succès ! Cette page sera bientôt rechargée, votre navigateur vous demandera les nouveaux identifiants."
|
||||
},
|
||||
"pin": {
|
||||
|
||||
@@ -110,6 +110,58 @@ endif()
|
||||
file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/tests/*.h
|
||||
${CMAKE_SOURCE_DIR}/tests/*.cpp)
|
||||
if(SUNSHINE_ENABLE_TRAY AND (WIN32 OR APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux"))
|
||||
set(SUNSHINE_TRAY_TEST_ICON_SOURCE_DIR
|
||||
"${CMAKE_SOURCE_DIR}/src_assets/common/assets/web/public/images")
|
||||
set(SUNSHINE_TRAY_TEST_ICON_DESTINATION_DIR
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/test_assets/web/images")
|
||||
file(MAKE_DIRECTORY "${SUNSHINE_TRAY_TEST_ICON_DESTINATION_DIR}")
|
||||
|
||||
configure_file(
|
||||
"${CMAKE_SOURCE_DIR}/sunshine.svg"
|
||||
"${SUNSHINE_TRAY_TEST_ICON_DESTINATION_DIR}/logo-sunshine.svg"
|
||||
COPYONLY)
|
||||
|
||||
set(SUNSHINE_TRAY_TEST_ICONS
|
||||
sunshine-locked.svg
|
||||
sunshine-playing.svg
|
||||
sunshine-pausing.svg)
|
||||
|
||||
foreach(icon IN LISTS SUNSHINE_TRAY_TEST_ICONS)
|
||||
configure_file(
|
||||
"${SUNSHINE_TRAY_TEST_ICON_SOURCE_DIR}/${icon}"
|
||||
"${SUNSHINE_TRAY_TEST_ICON_DESTINATION_DIR}/${icon}"
|
||||
COPYONLY)
|
||||
endforeach()
|
||||
|
||||
add_library(sunshine_tray_test_helpers STATIC
|
||||
${CMAKE_SOURCE_DIR}/third-party/tray/tests/notification_utils.cpp
|
||||
${CMAKE_SOURCE_DIR}/third-party/tray/tests/screenshot_utils.cpp)
|
||||
set_target_properties(sunshine_tray_test_helpers PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
target_include_directories(sunshine_tray_test_helpers PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/third-party/tray)
|
||||
target_link_libraries(sunshine_tray_test_helpers PRIVATE
|
||||
lizardbyte::common)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(sunshine_tray_test_helpers PRIVATE
|
||||
gdi32
|
||||
gdiplus)
|
||||
else()
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Gui)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui)
|
||||
set(SUNSHINE_TRAY_TEST_QT_GUI_TARGET Qt${QT_VERSION_MAJOR}::Gui)
|
||||
|
||||
target_link_libraries(sunshine_tray_test_helpers PRIVATE
|
||||
${SUNSHINE_TRAY_TEST_QT_GUI_TARGET})
|
||||
if(APPLE)
|
||||
target_link_libraries(sunshine_tray_test_helpers PRIVATE
|
||||
"-framework Cocoa")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
# Add macOS-specific test files only when building tests for macOS
|
||||
if (APPLE)
|
||||
file(GLOB_RECURSE MACOS_TEST_SOURCES CONFIGURE_DEPENDS
|
||||
@@ -173,6 +225,15 @@ set(TEST_LINK_LIBRARIES
|
||||
${PLATFORM_LIBRARIES}
|
||||
)
|
||||
|
||||
if(SUNSHINE_ENABLE_TRAY AND (WIN32 OR APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux"))
|
||||
list(APPEND TEST_LINK_LIBRARIES
|
||||
sunshine_tray_test_helpers)
|
||||
if(SUNSHINE_TRAY_TEST_QT_GUI_TARGET)
|
||||
list(APPEND TEST_LINK_LIBRARIES
|
||||
${SUNSHINE_TRAY_TEST_QT_GUI_TARGET})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add the specific libgcov library if found
|
||||
if(GCOV_LINK_LIBRARY)
|
||||
list(APPEND TEST_LINK_LIBRARIES ${GCOV_LINK_LIBRARY})
|
||||
|
||||
@@ -61,8 +61,7 @@ namespace log_checker {
|
||||
|
||||
for (std::string line; std::getline(input, line);) {
|
||||
line = remove_timestamp_prefix(line);
|
||||
if (line.size() >= end_str.size() &&
|
||||
line.compare(line.size() - end_str.size(), end_str.size(), end_str) == 0) {
|
||||
if (line.size() >= end_str.size() && line.compare(line.size() - end_str.size(), end_str.size(), end_str) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @file tests/unit/test_nvenc_dynamic_factory.cpp
|
||||
* @brief Tests for the Windows runtime NVENC SDK factory.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
|
||||
// standard includes
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
// lib includes
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// local includes
|
||||
#include "src/nvenc/nvenc_dynamic_factory.h"
|
||||
|
||||
namespace {
|
||||
|
||||
std::uint32_t reported_version; ///< Version returned by the fake NVENC driver.
|
||||
std::uint32_t reported_status; ///< Status returned by the fake NVENC driver.
|
||||
|
||||
/**
|
||||
* @brief Fake implementation of `NvEncodeAPIGetMaxSupportedVersion()`.
|
||||
*
|
||||
* @param version Receives the configured packed API version.
|
||||
* @return Configured NVENC status code.
|
||||
*/
|
||||
std::uint32_t WINAPI get_fake_max_supported_version(std::uint32_t *version) {
|
||||
*version = reported_version;
|
||||
return reported_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Minimal SDK-neutral encoder used to verify factory callbacks.
|
||||
*/
|
||||
class fake_nvenc_encoder final: public nvenc::nvenc_d3d11_interface {
|
||||
public:
|
||||
bool create_encoder(
|
||||
const nvenc::nvenc_config &,
|
||||
const video::config_t &,
|
||||
const video::sunshine_colorspace_t &,
|
||||
platf::pix_fmt_e
|
||||
) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void destroy_encoder() override {
|
||||
}
|
||||
|
||||
nvenc::nvenc_encoded_frame encode_frame(std::uint64_t frame_index, bool force_idr) override {
|
||||
return {{}, frame_index, force_idr, false};
|
||||
}
|
||||
|
||||
bool invalidate_ref_frames(std::uint64_t, std::uint64_t) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3D11Texture2D *get_input_texture() override {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Make a non-owning fake Windows module handle for factory discovery tests.
|
||||
*
|
||||
* @return Shared fake module handle.
|
||||
*/
|
||||
nvenc::shared_dll make_fake_dll() {
|
||||
constexpr std::uintptr_t fake_handle_value = 1U;
|
||||
return {
|
||||
reinterpret_cast<HMODULE>(fake_handle_value),
|
||||
[](HMODULE) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make runtime operations that expose the fake version query function.
|
||||
*
|
||||
* @return Runtime operations for a successfully loaded fake NVENC driver.
|
||||
*/
|
||||
nvenc::nvenc_runtime_api make_fake_runtime_api() {
|
||||
return {
|
||||
[]() {
|
||||
return make_fake_dll();
|
||||
},
|
||||
[](HMODULE dll, const char *symbol) {
|
||||
EXPECT_EQ(dll, make_fake_dll().get());
|
||||
EXPECT_EQ(std::string_view {symbol}, "NvEncodeAPIGetMaxSupportedVersion");
|
||||
return std::bit_cast<FARPROC>(&get_fake_max_supported_version);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
TEST(NvencDynamicFactoryTest, HandlesUnavailableDriver) {
|
||||
bool resolved_symbol = false;
|
||||
const nvenc::nvenc_runtime_api runtime_api {
|
||||
[]() {
|
||||
return nvenc::shared_dll {};
|
||||
},
|
||||
[&resolved_symbol](HMODULE, const char *) {
|
||||
resolved_symbol = true;
|
||||
return FARPROC {};
|
||||
},
|
||||
};
|
||||
|
||||
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(runtime_api));
|
||||
EXPECT_FALSE(resolved_symbol);
|
||||
}
|
||||
|
||||
TEST(NvencDynamicFactoryTest, HandlesMissingVersionQuery) {
|
||||
const nvenc::nvenc_runtime_api runtime_api {
|
||||
[]() {
|
||||
return make_fake_dll();
|
||||
},
|
||||
[](HMODULE, const char *) {
|
||||
return FARPROC {};
|
||||
},
|
||||
};
|
||||
|
||||
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(runtime_api));
|
||||
}
|
||||
|
||||
TEST(NvencDynamicFactoryTest, HandlesFailedVersionQuery) {
|
||||
reported_version = 1300U;
|
||||
reported_status = 1U;
|
||||
|
||||
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(make_fake_runtime_api()));
|
||||
}
|
||||
|
||||
TEST(NvencDynamicFactoryTest, RejectsUnsupportedDriver) {
|
||||
reported_version = 10U << 4U;
|
||||
reported_status = 0U;
|
||||
|
||||
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(make_fake_runtime_api()));
|
||||
}
|
||||
|
||||
TEST(NvencDynamicFactoryTest, SelectsSupportedSdkImplementations) {
|
||||
using enum nvenc::nvenc_sdk_version;
|
||||
constexpr std::array test_cases {
|
||||
std::pair {11U << 4U, sdk_11_0},
|
||||
std::pair {12U << 4U, sdk_12_0},
|
||||
std::pair {13U << 4U, sdk_13_0},
|
||||
std::pair {14U << 4U, sdk_13_0},
|
||||
};
|
||||
reported_status = 0U;
|
||||
|
||||
for (const auto &[version, expected] : test_cases) {
|
||||
reported_version = version;
|
||||
const auto factory = nvenc::nvenc_dynamic_factory::get(make_fake_runtime_api());
|
||||
ASSERT_TRUE(factory);
|
||||
EXPECT_EQ(factory->sdk_version(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NvencDynamicFactoryTest, UsesConfiguredEncoderConstructors) {
|
||||
bool created_native = false;
|
||||
bool created_on_cuda = false;
|
||||
const auto dll = make_fake_dll();
|
||||
nvenc::nvenc_dynamic_factory factory {
|
||||
dll,
|
||||
nvenc::nvenc_sdk_version::sdk_13_0,
|
||||
[&created_native, &dll](ID3D11Device *, nvenc::shared_dll callback_dll) {
|
||||
created_native = true;
|
||||
EXPECT_EQ(callback_dll, dll);
|
||||
return std::make_unique<fake_nvenc_encoder>();
|
||||
},
|
||||
[&created_on_cuda, &dll](ID3D11Device *, nvenc::shared_dll callback_dll) {
|
||||
created_on_cuda = true;
|
||||
EXPECT_EQ(callback_dll, dll);
|
||||
return std::make_unique<fake_nvenc_encoder>();
|
||||
},
|
||||
};
|
||||
|
||||
EXPECT_EQ(factory.sdk_version(), nvenc::nvenc_sdk_version::sdk_13_0);
|
||||
EXPECT_TRUE(factory.create_nvenc_d3d11_native(nullptr));
|
||||
EXPECT_TRUE(factory.create_nvenc_d3d11_on_cuda(nullptr));
|
||||
EXPECT_TRUE(created_native);
|
||||
EXPECT_TRUE(created_on_cuda);
|
||||
}
|
||||
|
||||
TEST(NvencDynamicFactoryTest, UsesDefaultWindowsRuntime) {
|
||||
const auto factory = nvenc::nvenc_dynamic_factory::get();
|
||||
EXPECT_TRUE(!factory || factory->sdk_version() != nvenc::nvenc_sdk_version::unsupported);
|
||||
}
|
||||
|
||||
TEST(NvencSharedDllTest, OwnsLoadedModuleUntilLastReference) {
|
||||
const auto handle = LoadLibraryEx("version.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
ASSERT_NE(handle, nullptr);
|
||||
|
||||
auto dll = nvenc::make_shared_dll(handle);
|
||||
EXPECT_EQ(dll.get(), handle);
|
||||
auto copy = dll;
|
||||
EXPECT_EQ(copy.use_count(), 2);
|
||||
|
||||
dll.reset();
|
||||
EXPECT_EQ(copy.use_count(), 1);
|
||||
copy.reset();
|
||||
}
|
||||
|
||||
TEST(NvencSharedDllTest, AcceptsNullModule) {
|
||||
auto dll = nvenc::make_shared_dll(nullptr);
|
||||
EXPECT_FALSE(dll);
|
||||
dll.reset();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file tests/unit/test_nvenc_version.cpp
|
||||
* @brief Tests for runtime NVENC SDK version selection.
|
||||
*/
|
||||
|
||||
// standard includes
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
// lib includes
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// local includes
|
||||
#include "src/nvenc/nvenc_version.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Expected SDK selection for a driver API version.
|
||||
*/
|
||||
struct nvenc_version_test_case {
|
||||
std::uint32_t max_version; ///< Maximum API version reported by the driver.
|
||||
nvenc::nvenc_sdk_version expected; ///< SDK implementation Sunshine should select.
|
||||
};
|
||||
|
||||
TEST(NvencVersionTest, DecodesPackedDriverVersion) {
|
||||
EXPECT_EQ(nvenc::decode_nvenc_driver_version((11U << 4U) | 0U), 1100U);
|
||||
EXPECT_EQ(nvenc::decode_nvenc_driver_version((13U << 4U) | 1U), 1301U);
|
||||
}
|
||||
|
||||
TEST(NvencVersionTest, SelectsNewestCompatibleSdk) {
|
||||
using enum nvenc::nvenc_sdk_version;
|
||||
constexpr std::array test_cases {
|
||||
nvenc_version_test_case {1000U, unsupported},
|
||||
nvenc_version_test_case {1099U, unsupported},
|
||||
nvenc_version_test_case {1100U, sdk_11_0},
|
||||
nvenc_version_test_case {1101U, sdk_11_0},
|
||||
nvenc_version_test_case {1199U, sdk_11_0},
|
||||
nvenc_version_test_case {1200U, sdk_12_0},
|
||||
nvenc_version_test_case {1201U, sdk_12_0},
|
||||
nvenc_version_test_case {1299U, sdk_12_0},
|
||||
nvenc_version_test_case {1300U, sdk_13_0},
|
||||
nvenc_version_test_case {1301U, sdk_13_0},
|
||||
nvenc_version_test_case {1400U, sdk_13_0},
|
||||
};
|
||||
|
||||
for (const auto &[max_version, expected] : test_cases) {
|
||||
EXPECT_EQ(nvenc::select_nvenc_sdk_version(max_version), expected);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,421 @@
|
||||
/**
|
||||
* @file tests/unit/test_system_tray.cpp
|
||||
* @brief Tests for Sunshine's system tray integration.
|
||||
*/
|
||||
#include "../tests_common.h"
|
||||
|
||||
// standard includes
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
|
||||
// Only test the system tray if it is enabled.
|
||||
#if defined(SUNSHINE_TRAY) && SUNSHINE_TRAY >= 1
|
||||
|
||||
// lib includes
|
||||
#include <tray.h>
|
||||
|
||||
// local includes
|
||||
#include <src/system_tray.h>
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(_WIN32)
|
||||
// lib includes
|
||||
#include <lizardbyte/common/env.h>
|
||||
|
||||
// test includes
|
||||
#include "third-party/tray/tests/notification_utils.h"
|
||||
#include "third-party/tray/tests/screenshot_utils.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* @brief Process pending Qt tray events without blocking.
|
||||
*
|
||||
* @param iterations Maximum number of event iterations to process.
|
||||
* @param delay Delay between event iterations.
|
||||
*/
|
||||
void pump_tray_events(const int iterations = 100, const std::chrono::milliseconds delay = 5ms) {
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
if (tray_loop(0) != 0) {
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(delay);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief Wait for the threaded tray worker to finish initialization.
|
||||
*
|
||||
* @param timeout Maximum time to wait.
|
||||
* @return true if the tray initialized before the timeout; otherwise, false.
|
||||
*/
|
||||
bool wait_for_tray_initialization(const std::chrono::milliseconds timeout) {
|
||||
const auto deadline = std::chrono::steady_clock::now() + timeout;
|
||||
while (std::chrono::steady_clock::now() < deadline) {
|
||||
if (system_tray::tray_initialized_for_testing()) {
|
||||
return true;
|
||||
}
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Verify the persistent menu exposed by Sunshine.
|
||||
*/
|
||||
void verify_menu() {
|
||||
const auto &tray_data = system_tray::tray_data_for_testing();
|
||||
ASSERT_NE(tray_data.menu, nullptr);
|
||||
|
||||
EXPECT_STREQ(tray_data.menu[0].text, "Open Sunshine");
|
||||
EXPECT_NE(tray_data.menu[0].cb, nullptr);
|
||||
EXPECT_STREQ(tray_data.menu[1].text, "-");
|
||||
EXPECT_EQ(tray_data.menu[1].cb, nullptr);
|
||||
EXPECT_STREQ(tray_data.menu[2].text, "Donate");
|
||||
ASSERT_NE(tray_data.menu[2].submenu, nullptr);
|
||||
EXPECT_STREQ(tray_data.menu[2].submenu[0].text, "GitHub Sponsors");
|
||||
EXPECT_STREQ(tray_data.menu[2].submenu[1].text, "Patreon");
|
||||
EXPECT_STREQ(tray_data.menu[2].submenu[2].text, "PayPal");
|
||||
EXPECT_EQ(tray_data.menu[2].submenu[3].text, nullptr);
|
||||
EXPECT_STREQ(tray_data.menu[3].text, "-");
|
||||
|
||||
#ifdef _WIN32
|
||||
EXPECT_STREQ(tray_data.menu[4].text, "Reset Display Device Config");
|
||||
EXPECT_NE(tray_data.menu[4].cb, nullptr);
|
||||
EXPECT_STREQ(tray_data.menu[5].text, "Restart");
|
||||
EXPECT_NE(tray_data.menu[5].cb, nullptr);
|
||||
EXPECT_STREQ(tray_data.menu[6].text, "Quit");
|
||||
EXPECT_NE(tray_data.menu[6].cb, nullptr);
|
||||
EXPECT_EQ(tray_data.menu[7].text, nullptr);
|
||||
#else
|
||||
EXPECT_STREQ(tray_data.menu[4].text, "Restart");
|
||||
EXPECT_NE(tray_data.menu[4].cb, nullptr);
|
||||
EXPECT_STREQ(tray_data.menu[5].text, "Quit");
|
||||
EXPECT_NE(tray_data.menu[5].cb, nullptr);
|
||||
EXPECT_EQ(tray_data.menu[6].text, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verify the current user-visible tray state.
|
||||
*
|
||||
* @param icon_index Index of the expected tray icon.
|
||||
* @param tooltip Expected tray tooltip.
|
||||
* @param notification_title Expected notification title, or nullptr when none is expected.
|
||||
* @param notification_text Expected notification text, or nullptr when none is expected.
|
||||
* @param notification_icon_index Index of the expected notification icon, or no value when none is expected.
|
||||
* @param expects_notification_callback Whether a notification callback is expected.
|
||||
*/
|
||||
void verify_state(
|
||||
const std::size_t icon_index,
|
||||
const char *tooltip,
|
||||
const char *notification_title,
|
||||
const char *notification_text,
|
||||
const std::optional<std::size_t> notification_icon_index,
|
||||
const bool expects_notification_callback
|
||||
) {
|
||||
const auto &tray_data = system_tray::tray_data_for_testing();
|
||||
ASSERT_GE(tray_data.iconPathCount, 4);
|
||||
|
||||
EXPECT_STREQ(tray_data.icon, tray_data.allIconPaths[icon_index]);
|
||||
EXPECT_STREQ(tray_data.tooltip, tooltip);
|
||||
EXPECT_STREQ(tray_data.notification_title, notification_title);
|
||||
EXPECT_STREQ(tray_data.notification_text, notification_text);
|
||||
if (notification_icon_index.has_value()) {
|
||||
EXPECT_STREQ(tray_data.notification_icon, tray_data.allIconPaths[*notification_icon_index]);
|
||||
} else {
|
||||
EXPECT_EQ(tray_data.notification_icon, nullptr);
|
||||
}
|
||||
if (expects_notification_callback) {
|
||||
EXPECT_NE(tray_data.notification_cb, nullptr);
|
||||
} else {
|
||||
EXPECT_EQ(tray_data.notification_cb, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verify every user-visible tray state transition.
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
void verify_state_transitions() {
|
||||
verify_state(0, PROJECT_NAME, nullptr, nullptr, std::nullopt, false);
|
||||
|
||||
system_tray::update_tray_playing("Moonlight");
|
||||
verify_state(2, "Streaming started for Moonlight", "Stream Started", "Streaming started for Moonlight", 2, false);
|
||||
|
||||
system_tray::update_tray_pausing("Moonlight");
|
||||
verify_state(3, "Streaming paused for Moonlight", "Stream Paused", "Streaming paused for Moonlight", 3, false);
|
||||
|
||||
system_tray::update_tray_stopped("Moonlight");
|
||||
verify_state(0, PROJECT_NAME, "Application Stopped", "Application Moonlight successfully stopped", 0, false);
|
||||
|
||||
system_tray::update_tray_require_pin();
|
||||
verify_state(0, PROJECT_NAME, "Incoming Pairing Request", "Click here to complete the pairing process", 1, true);
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief Fixture that resets the process-wide tray state between tests.
|
||||
*/
|
||||
class SystemTrayTest: public testing::Test {
|
||||
protected:
|
||||
/**
|
||||
* @brief Reset any tray state left by an earlier test.
|
||||
*/
|
||||
void SetUp() override {
|
||||
EXPECT_EQ(system_tray::end_tray(), 0);
|
||||
#ifndef _WIN32
|
||||
std::ignore = tray_loop(0);
|
||||
std::ignore = tray_restore_mouse_position();
|
||||
#endif
|
||||
system_tray::reset_tray_data_for_testing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shut down and reset the tray after a test.
|
||||
*/
|
||||
void TearDown() override {
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(_WIN32)
|
||||
dismissNativeNotifications();
|
||||
#endif
|
||||
EXPECT_EQ(system_tray::end_tray(), 0);
|
||||
#ifdef _WIN32
|
||||
std::this_thread::sleep_for(250ms);
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
std::ignore = tray_loop(0);
|
||||
std::ignore = tray_restore_mouse_position();
|
||||
#endif
|
||||
system_tray::reset_tray_data_for_testing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the tray and process its initial events.
|
||||
*
|
||||
* @return The result returned by system_tray::init_tray().
|
||||
*/
|
||||
int initialize_tray() const {
|
||||
const int result = system_tray::init_tray();
|
||||
#ifndef _WIN32
|
||||
if (result == 0) {
|
||||
pump_tray_events();
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SystemTrayTest, UpdatesAreIgnoredBeforeInitialization) {
|
||||
EXPECT_FALSE(system_tray::tray_initialized_for_testing());
|
||||
EXPECT_EQ(system_tray::process_tray_events(), 1);
|
||||
|
||||
system_tray::update_tray_playing("Moonlight");
|
||||
system_tray::update_tray_pausing("Moonlight");
|
||||
system_tray::update_tray_stopped("Moonlight");
|
||||
system_tray::update_tray_require_pin();
|
||||
|
||||
const auto &tray_data = system_tray::tray_data_for_testing();
|
||||
EXPECT_STREQ(tray_data.icon, tray_data.allIconPaths[0]);
|
||||
EXPECT_STREQ(tray_data.tooltip, PROJECT_NAME);
|
||||
EXPECT_EQ(tray_data.notification_title, nullptr);
|
||||
EXPECT_EQ(tray_data.notification_text, nullptr);
|
||||
EXPECT_EQ(tray_data.notification_icon, nullptr);
|
||||
EXPECT_EQ(tray_data.notification_cb, nullptr);
|
||||
EXPECT_EQ(system_tray::end_tray(), 0);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_F(SystemTrayTest, LifecycleMenuAndStateTransitions) {
|
||||
if (const int result = initialize_tray(); result != 0) {
|
||||
GTEST_SKIP() << "System tray is unavailable in this environment (code " << result << ")";
|
||||
}
|
||||
|
||||
EXPECT_TRUE(system_tray::tray_initialized_for_testing());
|
||||
verify_menu();
|
||||
verify_state_transitions();
|
||||
|
||||
std::jthread exit_thread([]() {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
std::ignore = system_tray::end_tray();
|
||||
});
|
||||
EXPECT_NE(system_tray::process_tray_events(), 0);
|
||||
exit_thread.join();
|
||||
EXPECT_FALSE(system_tray::tray_initialized_for_testing());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_F(SystemTrayTest, InitializesTrayForWorkflowConfiguration) {
|
||||
if (std::getenv("SUNSHINE_CONFIGURE_TRAY_ICONS") == nullptr) {
|
||||
GTEST_SKIP() << "Only required while configuring Windows runner tray icon visibility";
|
||||
}
|
||||
|
||||
ASSERT_EQ(system_tray::init_tray_threaded(), 0);
|
||||
ASSERT_TRUE(wait_for_tray_initialization(10s));
|
||||
verify_menu();
|
||||
EXPECT_EQ(system_tray::end_tray(), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(_WIN32)
|
||||
/**
|
||||
* @brief Fixture that stores visual tray evidence in the test output directory.
|
||||
*/
|
||||
class SystemTrayVisualTest: public SystemTrayTest {
|
||||
protected:
|
||||
/**
|
||||
* @brief Initialize a clean screenshot output directory for this test suite.
|
||||
*/
|
||||
static void SetUpTestSuite() {
|
||||
const std::filesystem::path test_binary_dir {SUNSHINE_TEST_BIN_DIR};
|
||||
std::error_code remove_error;
|
||||
std::filesystem::remove_all(test_binary_dir / "screenshots", remove_error);
|
||||
screenshot::initialize(test_binary_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait for a tray notification to be rendered.
|
||||
*/
|
||||
static void wait_for_notification() {
|
||||
#ifndef _WIN32
|
||||
pump_tray_events();
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
if (lizardbyte::common::is_github_actions()) {
|
||||
#ifdef _WIN32
|
||||
std::this_thread::sleep_for(2s);
|
||||
#else
|
||||
pump_tray_events(40, 50ms);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
std::this_thread::sleep_for(500ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Capture a screenshot and dismiss its native notification.
|
||||
*
|
||||
* @param name Screenshot filename without the PNG extension.
|
||||
*/
|
||||
static void capture_notification(const std::string &name) {
|
||||
wait_for_notification();
|
||||
EXPECT_TRUE(screenshot::capture(name));
|
||||
waitForNativeNotificationTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the tray on the platform's production execution path.
|
||||
*
|
||||
* @return Zero when initialization succeeds; otherwise, a non-zero error code.
|
||||
*/
|
||||
int initialize_visual_tray() const {
|
||||
#ifdef _WIN32
|
||||
if (const int result = system_tray::init_tray_threaded(); result != 0) {
|
||||
return result;
|
||||
}
|
||||
return wait_for_tray_initialization(10s) ? 0 : 1;
|
||||
#else
|
||||
return initialize_tray();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SystemTrayVisualTest, CapturesIconTooltipNotificationsAndMenu) {
|
||||
std::string unavailable_reason;
|
||||
if (!screenshot::is_available(&unavailable_reason)) {
|
||||
GTEST_SKIP() << "Screenshot tooling is unavailable: " << unavailable_reason;
|
||||
}
|
||||
|
||||
const auto &tray_data = system_tray::tray_data_for_testing();
|
||||
ASSERT_EQ(tray_data.iconPathCount, 4);
|
||||
for (int icon_index = 0; icon_index < tray_data.iconPathCount; ++icon_index) {
|
||||
ASSERT_NE(tray_data.allIconPaths[icon_index], nullptr);
|
||||
ASSERT_TRUE(std::filesystem::is_regular_file(tray_data.allIconPaths[icon_index]))
|
||||
<< "Missing system tray test icon: " << tray_data.allIconPaths[icon_index];
|
||||
}
|
||||
|
||||
if (const int result = initialize_visual_tray(); result != 0) {
|
||||
GTEST_SKIP() << "System tray is unavailable in this environment (code " << result << ")";
|
||||
}
|
||||
|
||||
verify_menu();
|
||||
verify_state(0, PROJECT_NAME, nullptr, nullptr, std::nullopt, false);
|
||||
EXPECT_TRUE(screenshot::capture("sunshine_tray_initial"));
|
||||
|
||||
const int tooltip_position_result = tray_position_mouse_over_icon();
|
||||
if (lizardbyte::common::is_github_actions()) {
|
||||
ASSERT_EQ(tooltip_position_result, 0);
|
||||
}
|
||||
if (tooltip_position_result == 0) {
|
||||
#ifdef _WIN32
|
||||
std::this_thread::sleep_for(1s);
|
||||
#else
|
||||
pump_tray_events(20, 50ms);
|
||||
#endif
|
||||
EXPECT_TRUE(screenshot::capture("sunshine_tray_tooltip"));
|
||||
EXPECT_EQ(tray_restore_mouse_position(), 0);
|
||||
}
|
||||
|
||||
dismissNativeNotifications();
|
||||
system_tray::update_tray_playing("Moonlight");
|
||||
verify_state(2, "Streaming started for Moonlight", "Stream Started", "Streaming started for Moonlight", 2, false);
|
||||
capture_notification("sunshine_tray_streaming");
|
||||
system_tray::update_tray_pausing("Moonlight");
|
||||
verify_state(3, "Streaming paused for Moonlight", "Stream Paused", "Streaming paused for Moonlight", 3, false);
|
||||
capture_notification("sunshine_tray_paused");
|
||||
system_tray::update_tray_stopped("Moonlight");
|
||||
verify_state(0, PROJECT_NAME, "Application Stopped", "Application Moonlight successfully stopped", 0, false);
|
||||
capture_notification("sunshine_tray_stopped");
|
||||
system_tray::update_tray_require_pin();
|
||||
verify_state(0, PROJECT_NAME, "Incoming Pairing Request", "Click here to complete the pairing process", 1, true);
|
||||
capture_notification("sunshine_tray_pairing_request");
|
||||
|
||||
int menu_position_result = -1;
|
||||
if (lizardbyte::common::is_github_actions()) {
|
||||
#ifdef _WIN32
|
||||
std::this_thread::sleep_for(500ms);
|
||||
#else
|
||||
pump_tray_events();
|
||||
#endif
|
||||
menu_position_result = tray_position_mouse_over_icon();
|
||||
ASSERT_EQ(menu_position_result, 0);
|
||||
}
|
||||
|
||||
std::atomic_bool capture_result {false};
|
||||
std::jthread capture_thread([&capture_result]() {
|
||||
capture_result.store(screenshot::capture("sunshine_tray_menu"), std::memory_order_release);
|
||||
std::ignore = system_tray::end_tray();
|
||||
});
|
||||
|
||||
tray_show_menu();
|
||||
if (menu_position_result == 0) {
|
||||
EXPECT_EQ(tray_restore_mouse_position(), 0);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
capture_thread.join();
|
||||
#else
|
||||
EXPECT_NE(system_tray::process_tray_events(), 0);
|
||||
capture_thread.join();
|
||||
#endif
|
||||
EXPECT_TRUE(capture_result.load(std::memory_order_acquire));
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
TEST(SystemTrayDisabled, ReportsDisabledBuild) {
|
||||
GTEST_SKIP() << "System tray support is disabled in this build";
|
||||
}
|
||||
|
||||
#endif
|
||||
Vendored
+1
-1
Submodule third-party/build-deps updated: 522fa8e5c6...a9a9277cda
Vendored
+1
-1
Submodule third-party/lizardbyte-common updated: 06cd442b80...011ad2bb13
Vendored
-1
Submodule third-party/nv-codec-headers deleted from 33a9ede8d9
Vendored
+1
-1
Submodule third-party/tray updated: 8ea4c6835d...1d0d69623f
@@ -285,8 +285,7 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
|
||||
case WAIT_OBJECT_0:
|
||||
// The service is shutting down, so try to gracefully terminate Sunshine.exe.
|
||||
// If it doesn't terminate in 20 seconds, we will forcefully terminate it.
|
||||
if (!RunTerminationHelper(console_token, process_info.dwProcessId) ||
|
||||
WaitForSingleObject(process_info.hProcess, 20000) != WAIT_OBJECT_0) {
|
||||
if (!RunTerminationHelper(console_token, process_info.dwProcessId) || WaitForSingleObject(process_info.hProcess, 20000) != WAIT_OBJECT_0) {
|
||||
// If it won't terminate gracefully, kill it now
|
||||
TerminateProcess(process_info.hProcess, ERROR_PROCESS_ABORTED);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
version = "3.14.1"
|
||||
version = "3.14.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohappyeyeballs" },
|
||||
@@ -24,49 +24,49 @@ dependencies = [
|
||||
{ name = "propcache" },
|
||||
{ name = "yarl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/82/78/8ea7308cac6934de8c74a14f3d5f65d1c89287426688be79538d0e5c013d/aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035", size = 7955794, upload-time = "2026-06-07T21:09:35.529Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/a1/5fafa04e1ca91ddb47608699d60649c1c6db3cf41c99e78fc4056f9513db/aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15", size = 508531, upload-time = "2026-06-07T21:08:02.093Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/2e/bfa02f699d87ffc86d5959270b28f1cb410add3ccaced8ed2e0b8a5238fc/aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8", size = 514718, upload-time = "2026-06-07T21:08:04.476Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/a5/9594ad6289eebbc97d167c44213d557807f90e59115caad24de21ad2c3b1/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3", size = 487918, upload-time = "2026-06-07T21:08:06.377Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/61/16a32c36c3c49edec122a3dc811f2057df2f94d3b14aa107c8017d981618/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba", size = 494014, upload-time = "2026-06-07T21:08:08.263Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/89/3ebcf96ed99c05bec9c434aaac6963fd3cbab4a786ae739908a144d9ce44/aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397", size = 502398, upload-time = "2026-06-07T21:08:10.244Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/3d/b74870a0c2d40c355928cd5b96c7a11fa821b8a40fc41365e64479b151fb/aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448", size = 758018, upload-time = "2026-06-07T21:08:12.447Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/66/f42f5c984d99e49c6cff5f26f590750f2e2f7ef1fcfb99966ab5be1b632e/aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004", size = 512462, upload-time = "2026-06-07T21:08:14.624Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/a7/248e1aebe0c7810b0271e021a0f2a5eb6e78a051885b3c9df49f42a5802d/aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983", size = 512824, upload-time = "2026-06-07T21:08:16.572Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/97/2aa0e5ba0727dc3bd5aaebb7ccbc510f7dfb7fb961ec87497cd496635ab1/aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe", size = 1749898, upload-time = "2026-06-07T21:08:18.635Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/8d/e97f6c96c891d457c8479d92a514ba194d0412f981d72c70341ee18488ed/aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333", size = 1710114, upload-time = "2026-06-07T21:08:20.892Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/e6/aa8d7e863048c8fceb5cd6ce74017311cec3ead07847387e12265fb4444e/aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0", size = 1802541, upload-time = "2026-06-07T21:08:23.044Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/a8/72193137de57fda4ebfae4563182d082c8856e3b6e9871d0b46f028fb369/aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a", size = 1875776, upload-time = "2026-06-07T21:08:25.288Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/18/938441025db6769a3464596b2410af3afde0b21eb2f204c6f766f68af4bd/aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602", size = 1760329, upload-time = "2026-06-07T21:08:27.363Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/29/bf2496b4065e76e09fe48015aaffe5ce161d8f089b06ac6982070f653076/aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca", size = 1587293, upload-time = "2026-06-07T21:08:29.805Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/a2/2136674d52123b1354bd05dd5753c318db47dc0c927cc70b27bab3755456/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35", size = 1714756, upload-time = "2026-06-07T21:08:32.094Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/b9/e5fd2e6f915503081c0f9b1e8540947037929c70c191da2e4d54b31a21a1/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844", size = 1721052, upload-time = "2026-06-07T21:08:34.167Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/5a/2833e324a2263e104e31e2e91bc5bbee81bc499afd32203faee048a883f0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496", size = 1766888, upload-time = "2026-06-07T21:08:36.95Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/fa/dea6511870913162f3b2e8c42a7614eb203a4540b8c2da43e0bfb0548f3c/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5", size = 1581679, upload-time = "2026-06-07T21:08:39.292Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/bd/3cf0d55e71784b33534e9710a67d382d900598b4787fbce6cc7317f8c42a/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95", size = 1782021, upload-time = "2026-06-07T21:08:41.407Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/af/14bb5843eccbe234f4dfb78ab73e549d99727247e62ae5d62cbd22eaf5b0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444", size = 1742574, upload-time = "2026-06-07T21:08:43.795Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/1e/fbeb7af9210a67ac0f9c9bec0f8f4568497924e33137a3d5b48e1cf85f3f/aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0", size = 457773, upload-time = "2026-06-07T21:08:46.168Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/2b/13e8d741a9ec5db7d900c060554cf8352ab85e44e2a4469ebb9d377bda17/aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719", size = 485001, upload-time = "2026-06-07T21:08:48.401Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/30/491acfa2c4d6c3ff59c49a14fc1b50be3241e25bbb0c84c09e2da4d11395/aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec", size = 453809, upload-time = "2026-06-07T21:08:50.7Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/e3/19dbe1a1f4cc6230eb9e314de7fe68053b0992f9302b27d12141a0b5db53/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2", size = 793320, upload-time = "2026-06-07T21:08:52.775Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/20/1b7182219ba1b108430d6e4dc53d25ae02dcfcf5a045b33af4e8c5167527/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340", size = 529077, upload-time = "2026-06-07T21:08:55Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d", size = 532476, upload-time = "2026-06-07T21:08:57.176Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/02/9ac85e081e53da2e061b02fa7758fe0a12d17b8ce2d1f5e6c7cb76730328/aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94", size = 1922347, upload-time = "2026-06-07T21:08:59.563Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/3e/d3ba07a0ab38b5389e10bec4362d21e10a4f667cba2d79ba30837b3a5059/aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc", size = 1786465, upload-time = "2026-06-07T21:09:01.909Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/cb/e2ee978a00cfb2df829704a69528b18154eba5939f45bc1efa8f33aee4c5/aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251", size = 1909423, upload-time = "2026-06-07T21:09:04.357Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/5d/1430334858b1022b58ae50399a918f0bd6fe8fa7fa183598d657ff61e040/aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1", size = 2001906, upload-time = "2026-06-07T21:09:06.722Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/4e/560c7472d3d198a23aa5c8b19a5115bf6a9b77b7d3e4bb363da320430ad2/aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3", size = 1877095, upload-time = "2026-06-07T21:09:09.011Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/f1/4745806578d447db4a784a8591e2dae3afdfc2bcb96f8f81271b13df6543/aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c", size = 1676222, upload-time = "2026-06-07T21:09:11.461Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/c9/48255813cca749a229ef0ab476004ec623728ad79a9c0840616f6c076325/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203", size = 1842922, upload-time = "2026-06-07T21:09:14.118Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/c0/bbd054e2bee909f529523a5af3891052606af5143c09f5f183ec3b234676/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1", size = 1825035, upload-time = "2026-06-07T21:09:16.447Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/ae/90395d4376deceb74e09ec26b6adf7d2015a6f8802d6d84446af860fef04/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665", size = 1849512, upload-time = "2026-06-07T21:09:18.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/bd/fb25f3049957553d4ce0ba6ae480aa2f592a6985497fca590837d16c1be0/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1", size = 1668571, upload-time = "2026-06-07T21:09:21.458Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/22/7f73303d64dd567ff3addca90b556690ed1233a47b8f55d242fb90af3681/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d", size = 1881159, upload-time = "2026-06-07T21:09:23.813Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/be/0474c5a8b5640e1e4aa1923430a91f4151be82e511373fe764189b89aef5/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c", size = 1841409, upload-time = "2026-06-07T21:09:26.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/3c/bb4a7cba26956cb3da4553cc2056cf67be5b5ff6e6d8fa4fbdff73bfb7ae/aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365", size = 494166, upload-time = "2026-06-07T21:09:28.505Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/84/ec80c2c1f66a952555a9f86df6b33af65108a6febfa0471b69013a12f807/aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9", size = 530255, upload-time = "2026-06-07T21:09:30.843Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/71/6e22be134a4061ada85a92951b842f2657f17d926b727f3f94c56ae963d6/aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6", size = 469640, upload-time = "2026-06-07T21:09:33.028Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/20/887fdcf832326571b370ffc347b3e70abe101096f3720126aac161b1d872/aiohttp-3.14.3-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:49f7325beb0f85ef4aef5f48f490269575f83e6e2acad00a1d80b807eb027062", size = 509067, upload-time = "2026-07-23T01:55:42.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/a3/92cec936f78cc4bf0fa5554ebe593b73459d94e3c62303e1902a4cccb6f7/aiohttp-3.14.3-cp314-cp314-android_24_x86_64.whl", hash = "sha256:e3be98a7c30b8c25d573dafba7171d66dfb05ee6a9070fc46535464ff97700a6", size = 514774, upload-time = "2026-07-23T01:55:44.937Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/ba/2a0c38df3fc557620b6a5acd98364af050053b6285b4dc7ee74100c63c18/aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:614c61d478b83953e261d02bb2df750f17227cd33ef8002945bf5aebbde21919", size = 488134, upload-time = "2026-07-23T01:55:47.135Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/d6/d51b7d4bf309af3693940d8ffd2b9ed0b682434ef85959b7c9c137f60cf8/aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:1caa7b0d05f3e3a36f87788c59e970a7ee1cefcfcbb924a9f138c4a6551c9cb7", size = 494201, upload-time = "2026-07-23T01:55:49.451Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/5a/8f624384e5f1efabb5229b94157eb966b021e97bdb188c62860c2ae243c2/aiohttp-3.14.3-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:dfa68deb2a443bdaa3ea5297b0699c1464f08aef3812b486d1348eee61b07dc0", size = 502766, upload-time = "2026-07-23T01:55:51.656Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/26/4ff0164370deec18fb19254ee4ab10b7a73304ac0c860b13f5f84663759b/aiohttp-3.14.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e72ee89e28d907a18f46959b4eb0bb06701cc7f8cf4366e00029e2ccfaaf5924", size = 756557, upload-time = "2026-07-23T01:55:53.964Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/a3/7056b86dc0d9ec709ea9777eae3b0161428f943372f8b98c01c11593b682/aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ad4c8b7488d745d2ca4838ebd8ae5ba9b56341d30b1da43640e4ce87f9f49646", size = 510168, upload-time = "2026-07-23T01:55:56.22Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/ed/0357a015892fd68058bf2d39d3fd1958e459b997a7db30aaa6aaa434ae96/aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:db332af25642007330fca8be5c4d194caf2bea7a7fc84415aff3497af5dfee6b", size = 512957, upload-time = "2026-07-23T01:55:58.437Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/d1/8aba53f15ccb2238405f5e9d30e2a8ca44f93878c26e7165ade00d374b1c/aiohttp-3.14.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25bd2708db6bdf6a6630dd37bdcdfcb47c4434d22ac69c64665b802910140b30", size = 1750149, upload-time = "2026-07-23T01:56:00.856Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/bd/40c3fee327529284375c6701cbb0fa4600cc2e8432af1378f897e2ef7d3a/aiohttp-3.14.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cef89a58e628c4efcac3275c2d68083f82426dcdc89c1492a6f654f9f7ea6ab9", size = 1707685, upload-time = "2026-07-23T01:56:03.371Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/a3/ca0cc6724cca8114b05694abd916060758c79894c3aa5b012cdadc1bc28e/aiohttp-3.14.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c23ec8ee9d5ab2f5421f9c7fffce208435607af27fd46d4a44e031954352838f", size = 1803911, upload-time = "2026-07-23T01:56:05.817Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/b5/85b099c299c3ffd38ad9b3e43694c8a346934e4a30c88c4fd5a841234f77/aiohttp-3.14.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e2667f0bbe7eb6c74eae5e9691441ad186e5845ca3cff63230fc09c4e7514f5d", size = 1876929, upload-time = "2026-07-23T01:56:08.413Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/b7/1da684a04175473fa4cddbf9a2f572e79514c3fd27a74597f43057d4f3da/aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18cb43369747b2ae007bd2655fb8e63a099c2ff1d207962943636dac989b3147", size = 1761112, upload-time = "2026-07-23T01:56:10.918Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/16/bc4b55e3e5cb175fd69c53c90d60d2f47797cb343da5106e23863dc4dba4/aiohttp-3.14.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d77640cc618c1d99fc4f8589c0f24a730adfa54eb1e57ef7bf0c8dfb78da898c", size = 1583500, upload-time = "2026-07-23T01:56:13.613Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/e8/13a9d957a1ee40837f46aa30f0f4c657e673ad86a2e6362a9f9be20d26d9/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:53e5179d8abb5710f8e83ba207c41c8d1261fcffd4616500e15ca2b7a33be10a", size = 1713940, upload-time = "2026-07-23T01:56:15.969Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/05/d33c680c1bcf1c7e130f9cbfc1fc02fe8bb0c4af2a94a53dd5fb56131e5c/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:cd817772b2fcf2b8c0905795318485f9ec16eae60b29feb7f4c77085311637f0", size = 1724413, upload-time = "2026-07-23T01:56:18.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/1d/af798d306f7a74b6a632dbcabcf62a4c91391b7582d2a8c6d7712e2cc54e/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4e3ac92d90e92773b2362d506068e9a948192bd553e743c5b2429e28527c8661", size = 1770748, upload-time = "2026-07-23T01:56:21.074Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/92/ad720d472556a995049206867765e9410969684f86ee09423ff9969044c1/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3f42e9b78301f11c8f861746175d8b9c1ccef713fcad9eab396e2f6db8ed4a22", size = 1577564, upload-time = "2026-07-23T01:56:23.475Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/ad/0ed7586cbef7a884e23a752fa2bb987a122e6a5dd50dab109258d0a95193/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9d9edccfe496b476db5f398d97b865e9a6752bcf8aec4eef8390ce20fb64bb41", size = 1782080, upload-time = "2026-07-23T01:56:25.994Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/ea/dbaed0d73e8a69aad653b045dab451c67c2454bb731a37b45a86593e9422/aiohttp-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c5ec8fb1bcc31a8466f74aaf26c345d5c386fa4bd08a3f0eb9c7a4a3fe8b5bf", size = 1745813, upload-time = "2026-07-23T01:56:28.604Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/1b/6893d4bc57e434fc93a6c9217c637d967a0b651d989f6e3265179375754a/aiohttp-3.14.3-cp314-cp314-win32.whl", hash = "sha256:38901a84da3ce22249f6e860bf8f90d141bcab7da090cc398f8bb58c0e44b7da", size = 455872, upload-time = "2026-07-23T01:56:31.031Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/8b/c7baa1ba1eda4db6989baefe5de6d99834921b84ebd7918624febcb9f290/aiohttp-3.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:8b3b60de05f3dcb6f6a00f818bb2ec781cee4de0645f59ccaf99b1d1823b6100", size = 481030, upload-time = "2026-07-23T01:56:33.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/8c/c29d067df825a2df88ca432db848aa2fe8199598359cc06c12b09320cac9/aiohttp-3.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:1576145bdceeb92382d899751e12743a3a5b8e460a841e3e50543859e54864dc", size = 453669, upload-time = "2026-07-23T01:56:35.731Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/a4/9c033beb355d39b6147980597ec9645e4729243f686ee4dc73945de72030/aiohttp-3.14.3-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:8800c996b01c2772a783e3e46f3e1abd5823029adca0df54231960de9bfefa5b", size = 791403, upload-time = "2026-07-23T01:56:37.972Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/ca/87c32a0a7704583cfc49660bd817889bae5b830bf53b5dcb4e92145ac2da/aiohttp-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ebe8e504f058fe91223351cecd2d9d6946c9d241bb0250d898ffbdf584cc72b0", size = 526413, upload-time = "2026-07-23T01:56:40.523Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:30402d03a7c0ff52bce290b57e564e9079fd9d0cb545c8aba73f86a103162d2e", size = 532135, upload-time = "2026-07-23T01:56:42.876Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/45/f8919fd936e8b79fcd9bda7b6d8e62613462a713f4f17987fd7c34399142/aiohttp-3.14.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fc7b5bfec6573f3ae844f457fdde5adeb713f8b8e4a81ad64fc207b49383716", size = 1922742, upload-time = "2026-07-23T01:56:45.528Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/ec/9ca76b28a27525b0cc53e20842e0228b022f301ce1f436b7d814b4aaf2df/aiohttp-3.14.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8a5fd34f7f7410d1730d5c2ba873cacb2eed3fede366feb268a70ba22581ed8f", size = 1787371, upload-time = "2026-07-23T01:56:48.045Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/04/6acdbf17315f7b55f1937e3387acb89a3cddeb4995689553d064af8e92ab/aiohttp-3.14.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:270d3dace9ca2f10f0da5d8ebe519b7a310fc6112ed916e32df5866df0888553", size = 1912623, upload-time = "2026-07-23T01:56:50.605Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/e6/438b0c79ca6f45eb9fd9817dd4c01a91919a38c0de5ee9e05e2b4dc0ece7/aiohttp-3.14.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3ae5b3a59436d089b5395d910121a390feed4d00578eb95a0fd1a329fe963100", size = 2005515, upload-time = "2026-07-23T01:56:53.153Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/6b/62cbd6577758699525f5c712d1ddef57d9875fbab0ae8d5f5a202fd598f8/aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2498f0fe69ead802f9675beca44a7c21c62fdaa4ec5145ea1c3ad6edbee29f85", size = 1879906, upload-time = "2026-07-23T01:56:55.818Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/95/18bcbf830a21dc3aae24d8f6b6feaf3db1d2090242d00a7868db2ffb0b67/aiohttp-3.14.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a0dc483c00da8b673abbb367eb6f8d8f4bcec30eb58529ea13cb42e7fd2dfa33", size = 1675849, upload-time = "2026-07-23T01:56:58.861Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/19/47f4968659c5e23606c3790c80fc624e691c153d036148449ee84d31b287/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c7d3a97c678d34fc5b59da671ee9cd630096ddc643e7b5a30d54a2a6f3574d3f", size = 1843496, upload-time = "2026-07-23T01:57:01.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/af/38c33c4dd82fddcb4e56c4653b6f1072a8edbc6b7fa15809f14932c41e2d/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8fb78a83c9e5f741ca3a68cfb455c1f5bb83b4e7249a3848b3cd78d0a8563b0", size = 1827746, upload-time = "2026-07-23T01:57:05.131Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/9d/0537cda4885ac8f5b7053d164dd06312f4c483a4edcb8ee5b8aaf2a989bf/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:74ab5b6a9fb13e873e5a90946588baecaf488745e1db1a4a5c433f971f035098", size = 1853810, upload-time = "2026-07-23T01:57:08.043Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/fe/26f9c5e6458385aa86497836b0dea6fb2f027827d63f37c7856cce9286ee/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd52f811e65f6fb634b1047159657c98f52b407f8efec907bcfc09da9a4c0a25", size = 1668895, upload-time = "2026-07-23T01:57:10.837Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/4c/618b1db9b9ba079b8875d2cdf78e7c4a3bf72903bd5850fee7dd9544600a/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f0f177d1b195b9e06376cfd7d308d8a1b920909a609d03ac82a8c73bbb16d3b9", size = 1883833, upload-time = "2026-07-23T01:57:13.672Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/c6/bd959bd1e4771f9fd944e9e436224c48c77b018b73b519b5aad346335bcc/aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:498c6c623134f8e09a3c4e60bcd607a0b4590dd7dbf08dd40851b27cbb520ccb", size = 1844251, upload-time = "2026-07-23T01:57:16.593Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/19/08d41839658bdd44a0ed2480f3891705ecb487ce28c0dde62c9040c997e0/aiohttp-3.14.3-cp314-cp314t-win32.whl", hash = "sha256:b304db572b4368edd8dda8a2274f73156fe15558fca4a917cb8a09fc47af5963", size = 474180, upload-time = "2026-07-23T01:57:19.306Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/5d/3cd6ef0a2b2851f7ab913b5b079334781bd50ff56a323e4454063377a080/aiohttp-3.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b20032766aedf6261c7a566585a40867d092ac03a0d81592d5370ef9b054f99b", size = 500528, upload-time = "2026-07-23T01:57:21.762Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/37/cfd1ed540a4d318da025590d96b728e63713c09e9377950fc655dadeb856/aiohttp-3.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:2e1161602f45a54de2ce0905243a95f58cb42dcd378402f3697f5e0b21e9d2e7", size = 469280, upload-time = "2026-07-23T01:57:24.241Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -101,27 +101,27 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "clang-format"
|
||||
version = "21.1.8"
|
||||
version = "22.1.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/29/ed/019e682e9f8a5a5abf4258b293453092ef9524b540ada591ccfdff1246df/clang_format-21.1.8.tar.gz", hash = "sha256:99369fe76526ba6be6d7a8093fee6cd266bbf5ce72597a0d79a4ce9a625b28cf", size = 11509, upload-time = "2025-12-16T20:34:33.065Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bd/55/b48aba45ba2638a706df1680e3dcdf96f94aed8e884886192d411d7a0071/clang_format-22.1.8.tar.gz", hash = "sha256:61a23f4fc0ad1932e1b0300ca451108bf1e751eb89f478062d87f888db9190e6", size = 11508, upload-time = "2026-07-11T14:08:34.542Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/17/1d/4b1d85acb99a2ee3bad0b20cc3e82c58fbfb39bf4dd5856ac1f2c4f36e65/clang_format-21.1.8-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:f447091c346027a09728a0a96128fe058419fe06cf200ccc3dc98bcd4399e351", size = 1465604, upload-time = "2025-12-16T20:34:03.955Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/38/a61466227a8a6bf22c583f7bd810e75c9a356cfc63c6a712a201103a4ad3/clang_format-21.1.8-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:9a78fabba6b382866819b42a7b220d235a3baf6128a40fb7bd590c037f69879b", size = 1459014, upload-time = "2025-12-16T20:34:05.929Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/5d/6720c895c5cfc01831fac55ecf849f10d03d6222700909af14f6047c933b/clang_format-21.1.8-py2.py3-none-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2a044953efab5f7d0261f3a76aabc01358592faac1b73af38d8c83db6e91a69", size = 1725482, upload-time = "2025-12-16T20:34:07.525Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/0d/074b940884ced1b5c93e2e7fc8a941673519a938e7f31aeade321e3ab094/clang_format-21.1.8-py2.py3-none-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:143d2dffa71058d05ac5ad71321682e23d638bce22c8f2e3d01ed457d841a5f3", size = 1856680, upload-time = "2025-12-16T20:34:09.987Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/d5/46e22ae8c4385a7836db7403ced63ea8056c971cbb806bf0c6f0d2133acc/clang_format-21.1.8-py2.py3-none-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6a4b61a743dad5afc5e60be0c5c8f162f6cf27fff9eed56ec0bf65c2bcbd8a8d", size = 2031282, upload-time = "2025-12-16T20:34:11.565Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/2a/cad75567c312d945cc26aaee7e1b7135703fed9c7e7ad15c427bf6ad7a84/clang_format-21.1.8-py2.py3-none-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:94de66c5eeca1270825348687d384750d91f1d8d12216b2df0aea892859be33a", size = 2047763, upload-time = "2025-12-16T20:34:13.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/c2/403e7371b1ab0f6175d708ecc93cf18085ea9f903e8fe7d17c43df698f06/clang_format-21.1.8-py2.py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d12b864b596b80810cdd7f97556c485dc09cfe2952503958535f01359e025fbb", size = 1804755, upload-time = "2025-12-16T20:34:14.813Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/33/9e7db5fc4abefb25022d266957f666bfc263ae3e51abdd2c997d2880ceee/clang_format-21.1.8-py2.py3-none-manylinux_2_31_armv7l.whl", hash = "sha256:b81f1e909f5e7ef862a7818dc22b302a3ff407f3534e3395aa7ba26746cc890e", size = 1643208, upload-time = "2025-12-16T20:34:16.898Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/9f/43f4e384cb8943418f94943f682835f375f15b9cc64c526d73a7360f2b2f/clang_format-21.1.8-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e10a5dca18a04997ad55c082bc0759edc7e337b24a2373ded109634fde12662a", size = 2701696, upload-time = "2025-12-16T20:34:19.043Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/6a/378187d72a465cebd3dbf7cd455e33b4931daa33e815b7865e6e65591a72/clang_format-21.1.8-py2.py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:10f7d7004d70b5e03fd3f764fc19fae89cd38d68b3482162cb09cac47c12c7b0", size = 2481266, upload-time = "2025-12-16T20:34:20.336Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/eb/2332edb1846d6832932191a590203a53ec69f585e718b51796335a1dcb6e/clang_format-21.1.8-py2.py3-none-musllinux_1_2_i686.whl", hash = "sha256:303d5fd53090422119136b1a458e98db429dedd5db0add50e70f885f8c95d82a", size = 2954000, upload-time = "2025-12-16T20:34:21.739Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/b5/eed5c95521b77d3cde024c3a23c7a80c46e78aa5b5a81c5cf935e7267588/clang_format-21.1.8-py2.py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:6b9e0b45cfaf4a18336a6db4666dd6a6aae840e38b038e6d568a65f43ade007c", size = 3076720, upload-time = "2025-12-16T20:34:23.139Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/55/7527fbe31423a1bb53653c2a2b20aa34a73ec33b99199bceaec0f5907295/clang_format-21.1.8-py2.py3-none-musllinux_1_2_s390x.whl", hash = "sha256:4dd0fee9eaee9915ba7fa08e60ee9ddfba1f754d10d71164482d9eb387c431f0", size = 3160892, upload-time = "2025-12-16T20:34:24.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/61/1623382bc78ef139c196473a5c76b840a071c9002cb5cd2694ac50327db9/clang_format-21.1.8-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9731aecf954651004f184347d0c589d4e91a39ccda21262ee17c60f80a4408b2", size = 2812487, upload-time = "2025-12-16T20:34:26.505Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/e1/74f2000d44e4904472e5685afb98d19566c515026214733f02bbdc73d6d8/clang_format-21.1.8-py2.py3-none-win32.whl", hash = "sha256:2f5883ca83f718d8c2272e98b3cbda422fec520824b5a1e335c631dc6d812da7", size = 1271310, upload-time = "2025-12-16T20:34:28.179Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/7a/c49c8af9135c6a6dfb9cd103328ba7b6551643dce71b57e58ea940884015/clang_format-21.1.8-py2.py3-none-win_amd64.whl", hash = "sha256:a7606da55e31ebf5b63dd75800392e6cca7c595a74100c2cebcda2d742130732", size = 1426467, upload-time = "2025-12-16T20:34:29.805Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/d3/8790b539afb6cb0d4474705d3750e78a1f0847ab6d3ef1b00dd1ae52f364/clang_format-21.1.8-py2.py3-none-win_arm64.whl", hash = "sha256:1aa10b3f647268361d08bf4f17ce70964b8d9c04d5539e7d8acbebd14dc4a49c", size = 1327254, upload-time = "2025-12-16T20:34:31.579Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/d8/29b9db6098da1a011ca3f7560c3942fa81404dbbb4367c3bd1d5c435da3b/clang_format-22.1.8-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:fc2ac5bd0ea41af49968fb69426207806d5f7016cb8f4bfbd44f4f1ffe8d53f2", size = 1492639, upload-time = "2026-07-11T14:08:10.531Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/55/539cc1036dae16659f50500ca34838cc5b16cd3e98e3faaf164186b98093/clang_format-22.1.8-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:d1147107222c0dda3e4869e9e8c4a79f9ed1de83819e5274de42b82adf3d2129", size = 1482323, upload-time = "2026-07-11T14:08:12.076Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/25/a9734da014eecc1f54c051ad643a28f2f6643dcc812ac59320e80e2b1a3b/clang_format-22.1.8-py2.py3-none-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48c3b8dcfe9d4e964ced0e744e0f1f8ddc711bce92e50f6cab21e10f54857d08", size = 1757825, upload-time = "2026-07-11T14:08:13.397Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/19/76bf4dfba7d418f3da4fe89ace66856abd79c8c314e750d5f0fb754de6f5/clang_format-22.1.8-py2.py3-none-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:07312f8a74bda89b6ce32fae46c589cd7bb210a5d3fb2829a70e28ff449f5b80", size = 1888650, upload-time = "2026-07-11T14:08:14.722Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/b0/25fb71006b581c4e1dc4680b61c61842836dd1adb860e02f898deed8a919/clang_format-22.1.8-py2.py3-none-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6d7382dd728431c0cecf3c7db6ac0904e162c7c18889696ab8dc0630ff9349b", size = 2070288, upload-time = "2026-07-11T14:08:15.98Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/94/f7c185f2f7c9cbd60878a260a2a03cc4eef0b9b9fbe8eb5045fa9b5ccbe9/clang_format-22.1.8-py2.py3-none-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7763ce0f45b5ff0b5ca7a830d6061ce431dcb644211f9b2bb483bfa66d6c78ca", size = 2101885, upload-time = "2026-07-11T14:08:17.329Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/88/b82c066fa807da4ca2518fecf79071361f6324b77375e5e92c059c0697fd/clang_format-22.1.8-py2.py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b00cff6bfd1f1686f073a4fdf1cb937dbd58bf7510c659477805c03afdea0816", size = 1841177, upload-time = "2026-07-11T14:08:18.828Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/7c/996fc84930d96db84418fbd16d3935ba77f42f9078d7610e4eae3e0e9294/clang_format-22.1.8-py2.py3-none-manylinux_2_31_armv7l.whl", hash = "sha256:396f66b2237131ae7c5c9a9c34d50b1b9bee60ec6754e8b0dcb943850c747aa6", size = 1684807, upload-time = "2026-07-11T14:08:20.092Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/42/423de2ddedd3e068f7b773d7a4a593266692bc6108a2dd8ad4403d2ae718/clang_format-22.1.8-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:02ff8ad2e6a60554cc6b9b34310f71adb04da39e94302e08e3a655b77e4dd31c", size = 2736272, upload-time = "2026-07-11T14:08:21.625Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/6b/fbb98122d35333012d47186d669c1bb9a1cb527faa9a4a12c43124662f8f/clang_format-22.1.8-py2.py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8fc6139349a64f82d24396c815f5584f56da8912482dceadd9e5d7a3f8c17d6c", size = 2515477, upload-time = "2026-07-11T14:08:23.166Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/99/a5e00402fe8281754df679a1028132a28ea0c0024d363509d9c29944ab85/clang_format-22.1.8-py2.py3-none-musllinux_1_2_i686.whl", hash = "sha256:65df71f1eab12de161b9059483be55cb72490ec7fc7ca4915b5de49722a76a46", size = 2986602, upload-time = "2026-07-11T14:08:24.679Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/f7/4a02e8f7d54f71c7ee4ce48c35cbe8f2be1afb1fbbca543f8db43f56a959/clang_format-22.1.8-py2.py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:0223471f781647d476ce0e09a0512521043343313e42932d900f97a15eacb510", size = 3120341, upload-time = "2026-07-11T14:08:26.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/05/6bd5e7bea1679dbed37a94a3b47d2ef0110792f64fd5761b2301d5b34fd2/clang_format-22.1.8-py2.py3-none-musllinux_1_2_s390x.whl", hash = "sha256:41e00922840376f8d1239db8fb5bc6b1d313bd09752344a85b0f8071112e5c7e", size = 3217448, upload-time = "2026-07-11T14:08:27.799Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/e3/3fcba146f12b9fbad24034136718d113dfacac03b1cf8273b2aa7bd641b0/clang_format-22.1.8-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:734d22be5c9d3a72a841444817aae8168c8f4bdccb08de491f05673e42ec7304", size = 2848689, upload-time = "2026-07-11T14:08:29.283Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/2b/5a7f2fba71179331b51bb547a02808a56aa515f8637adf035fd34c1d3b0b/clang_format-22.1.8-py2.py3-none-win32.whl", hash = "sha256:a796192453ae56c61e975fc56ee7defb4187013fc3de798cbe608cfe326762aa", size = 1298699, upload-time = "2026-07-11T14:08:30.63Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/60/c6783b3190a8f741107a44912a11c39c1a51e254e86a4c43cb0151cea0dd/clang_format-22.1.8-py2.py3-none-win_amd64.whl", hash = "sha256:5fe6ad3e9399d589aff5ead432568a84cdcbbd621f1708340819efd74cbf8176", size = 1465069, upload-time = "2026-07-11T14:08:31.935Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/ca/7e1fa4a6044c37c37356bb18fc938d2811754231e448aaffc192dc3774ce/clang_format-22.1.8-py2.py3-none-win_arm64.whl", hash = "sha256:1fac18f32426c6fd7acde7087511bd80e2c549b2cd7477099582c216ae82fa63", size = 1344986, upload-time = "2026-07-11T14:08:33.183Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -147,14 +147,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "colorlog"
|
||||
version = "6.11.0"
|
||||
version = "6.12.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0a/bf/cb30a51af3aa8ce63735f77e23dcd4fc0720fe0339bcb04f77345659c277/colorlog-6.11.0.tar.gz", hash = "sha256:9d90fb53fa906c8970c18fbe46506bae1fb5f86b513b8f867db37e4ace9be7ae", size = 17734, upload-time = "2026-07-17T12:16:46.59Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/55/ba79756cb90c8d69d599d57785398ac87bba7b19c80e87f4e8a562197c93/colorlog-6.12.0.tar.gz", hash = "sha256:2a7924c1dadf18b22a0eb8b06d1c7b01d5341707ec1641eb6fcc4fde0c3e8e5f", size = 18151, upload-time = "2026-07-23T13:40:40.71Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/a1/6b71004ab0fea510230be9ce05a4059029ac847c009fcc80b1b73d6fa5ab/colorlog-6.11.0-py3-none-any.whl", hash = "sha256:f1e27d75aa2cb138f3f640c0e305b65b680ccbef6ecc034eba7e03494ffcd2a1", size = 12016, upload-time = "2026-07-17T12:16:45.3Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/19/0b6647bf5e331521e55d2b63bfbdc210bd9cd605189273f03614a05f702d/colorlog-6.12.0-py3-none-any.whl", hash = "sha256:30d392604e9110045a2c2aeefc27d7a017abbab63f3a8aee594eac0801df784e", size = 12239, upload-time = "2026-07-23T13:40:39.562Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -302,7 +302,7 @@ c = [
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "babel", marker = "extra == 'locale'", specifier = "==2.18.0" },
|
||||
{ name = "clang-format", marker = "extra == 'lint-c'", specifier = "==21.1.8" },
|
||||
{ name = "clang-format", marker = "extra == 'lint-c'", specifier = "==22.1.8" },
|
||||
{ name = "cmakelang", marker = "extra == 'lint-c'", specifier = "==0.6.13" },
|
||||
{ name = "flake8", marker = "extra == 'lint-python'", specifier = "==7.3.0" },
|
||||
{ name = "gcovr", marker = "extra == 'test-c'", specifier = "==8.6" },
|
||||
@@ -312,7 +312,7 @@ requires-dist = [
|
||||
{ name = "lizardbyte-common", extras = ["locale"], marker = "extra == 'c'" },
|
||||
{ name = "lizardbyte-common", extras = ["test-c"], marker = "extra == 'c'" },
|
||||
{ name = "lizardbyte-common", extras = ["test-python"], marker = "extra == 'dev'" },
|
||||
{ name = "pytest", marker = "extra == 'test-python'", specifier = "==9.0.3" },
|
||||
{ name = "pytest", marker = "extra == 'test-python'", specifier = "==9.1.1" },
|
||||
{ name = "pytest-cov", marker = "extra == 'test-python'", specifier = "==7.1.0" },
|
||||
]
|
||||
provides-extras = ["dev", "c", "lint-c", "lint-python", "locale", "test-c", "test-python"]
|
||||
@@ -320,28 +320,28 @@ provides-extras = ["dev", "c", "lint-c", "lint-python", "locale", "test-c", "tes
|
||||
[package.metadata.requires-dev]
|
||||
c = [
|
||||
{ name = "babel", specifier = "==2.18.0" },
|
||||
{ name = "clang-format", specifier = "==21.1.8" },
|
||||
{ name = "clang-format", specifier = "==22.1.8" },
|
||||
{ name = "cmakelang", specifier = "==0.6.13" },
|
||||
{ name = "gcovr", specifier = "==8.6" },
|
||||
]
|
||||
dev = [
|
||||
{ name = "babel", specifier = "==2.18.0" },
|
||||
{ name = "clang-format", specifier = "==21.1.8" },
|
||||
{ name = "clang-format", specifier = "==22.1.8" },
|
||||
{ name = "cmakelang", specifier = "==0.6.13" },
|
||||
{ name = "flake8", specifier = "==7.3.0" },
|
||||
{ name = "gcovr", specifier = "==8.6" },
|
||||
{ name = "pytest", specifier = "==9.0.3" },
|
||||
{ name = "pytest", specifier = "==9.1.1" },
|
||||
{ name = "pytest-cov", specifier = "==7.1.0" },
|
||||
]
|
||||
lint-c = [
|
||||
{ name = "clang-format", specifier = "==21.1.8" },
|
||||
{ name = "clang-format", specifier = "==22.1.8" },
|
||||
{ name = "cmakelang", specifier = "==0.6.13" },
|
||||
]
|
||||
lint-python = [{ name = "flake8", specifier = "==7.3.0" }]
|
||||
locale = [{ name = "babel", specifier = "==2.18.0" }]
|
||||
test-c = [{ name = "gcovr", specifier = "==8.6" }]
|
||||
test-python = [
|
||||
{ name = "pytest", specifier = "==9.0.3" },
|
||||
{ name = "pytest", specifier = "==9.1.1" },
|
||||
{ name = "pytest-cov", specifier = "==7.1.0" },
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user