ref:f2c9f34d90cef3438fc6a305f5d6baadf884f261

fix(deps): fix legacy nvenc presets and bump third-party/build-deps (#5668)

SHA: f2c9f34d90cef3438fc6a305f5d6baadf884f261
Author: Dave Lane <42013603+ReenigneArcher@users.noreply.github.com>
Date: 2026-09-10 15:54
Parents: 4ffca95
17 files changed +150 -58
Type
cmake/compile_definitions/common.cmake +4 −7
@@ -110,10 +110,12 @@
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}")
add_nvenc_sdk_implementation(nvenc_sdk_1301 1301 "${NV_CODEC_HEADERS_13_1_INCLUDE_DIR}")
list(APPEND NVENC_SOURCES
$<TARGET_OBJECTS:nvenc_sdk_1100>
$<TARGET_OBJECTS:nvenc_sdk_1200>
$<TARGET_OBJECTS:nvenc_sdk_1300>
$<TARGET_OBJECTS:nvenc_sdk_1301>
)
endif()
@@ -209,13 +211,8 @@
${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}")
if(NOT APPLE)
include_directories(BEFORE SYSTEM "${NV_CODEC_HEADERS_13_1_INCLUDE_DIR}")
else()
include_directories(
BEFORE SYSTEM
"${CMAKE_SOURCE_DIR}/third-party/build-deps/third-party/FFmpeg/nv-codec-headers/include"
)
endif()
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
cmake/dependencies/nv_codec_headers.cmake +23 −0
@@ -1,3 +1,23 @@
# Keep build-deps-owned declarations out of Sunshine's generated package lock.
set(SUNSHINE_CPM_PACKAGE_LOCK_ENABLED "${CPM_PACKAGE_LOCK_ENABLED}")
set(CPM_PACKAGE_LOCK_ENABLED OFF)
if(NOT APPLE)
set(SUNSHINE_PREPARED_NV_CODEC_HEADERS
"${FFMPEG_PREPARED_BINARIES}/include/ffnvcodec/nvEncodeAPI.h")
if(DEFINED FFMPEG_PREPARED_BINARIES AND EXISTS "${SUNSHINE_PREPARED_NV_CODEC_HEADERS}")
# Prepared FFmpeg bundles include the NV codec headers used to build them.
set(NV_CODEC_HEADERS_13_1_INCLUDE_DIR "${FFMPEG_PREPARED_BINARIES}/include")
message(STATUS "Using NV codec headers from prepared FFmpeg binaries")
else()
CPMGetPackage(nv_codec_headers_13_1)
set(NV_CODEC_HEADERS_13_1_INCLUDE_DIR "${nv_codec_headers_13_1_SOURCE_DIR}/include")
endif()
unset(SUNSHINE_PREPARED_NV_CODEC_HEADERS)
endif()
if(WIN32)
CPMGetPackage(nv_codec_headers_13)
CPMGetPackage(nv_codec_headers_11)
@@ -7,3 +27,6 @@
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()
set(CPM_PACKAGE_LOCK_ENABLED "${SUNSHINE_CPM_PACKAGE_LOCK_ENABLED}")
unset(SUNSHINE_CPM_PACKAGE_LOCK_ENABLED)
CMakeLists.txt +5 −0
@@ -68,5 +68,10 @@
return()
endif()
# Build-deps owns the dependency versions shared with its FFmpeg builds.
# Include its lock only for full builds so manifest-only configurations do not
# require the build-deps submodule.
include(${CMAKE_CURRENT_SOURCE_DIR}/third-party/build-deps/package-lock.cmake)
# project constants
include(${CMAKE_MODULE_PATH}/prep/constants.cmake)
package-lock.cmake +1 −34
@@ -31,37 +31,4 @@
# - `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
)
set(PATCH_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/patches")
packaging/linux/flatpak/modules/ffmpeg.json +4 −4
@@ -8,8 +8,8 @@
"sources": [
{
"type": "file",
"url": "https://github.com/LizardByte/build-deps/releases/download/v2026.905.170812/Linux-x86_64-ffmpeg.tar.gz",
"sha256": "880f0b9983ea9b55a6cceb2e5afa6388e256751f3cac2baf4ef0cf6eedc57aea",
"url": "https://github.com/LizardByte/build-deps/releases/download/v2026.910.121303/Linux-x86_64-ffmpeg.tar.gz",
"sha256": "496d2bbb674d01e6033e31b9dfc15cbc9dc1494e882a4505f6ab1e03f75b385c",
"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.905.170812/Linux-aarch64-ffmpeg.tar.gz",
"sha256": "096069f2737a93ff44ba6445b700213708ab1fec01fd015e528a47845b5fde46",
"url": "https://github.com/LizardByte/build-deps/releases/download/v2026.910.121303/Linux-aarch64-ffmpeg.tar.gz",
"sha256": "21f99409e1aba09191f9df28688fb7f9d44f98e65378a651324c632c19823aa0",
"dest-filename": "ffmpeg.tar.gz",
"only-arches": [
"aarch64"
src/config.cpp +6 −2
@@ -64,6 +64,10 @@
namespace nv {
std::string ffmpeg_preset_from_quality(const int quality_preset) {
return std::format("p{}", quality_preset);
}
/**
* @brief Parse the `nvenc_twopass` configuration value.
*
@@ -1619,11 +1623,11 @@
bool_f(vars, "nvenc_latency_over_power", video.nv_sunshine_high_power_mode);
#if !defined(__ANDROID__) && !defined(__APPLE__)
video.nv_legacy.preset = video.nv.quality_preset + 11;
video.nv_legacy.preset = nv::ffmpeg_preset_from_quality(video.nv.quality_preset);
video.nv_legacy.multipass = video.nv.two_pass == nvenc::nvenc_two_pass::quarter_resolution ? NV_ENC_TWO_PASS_QUARTER_RESOLUTION :
video.nv.two_pass == nvenc::nvenc_two_pass::full_resolution ? NV_ENC_TWO_PASS_FULL_RESOLUTION :
NV_ENC_MULTI_PASS_DISABLED;
video.nv_legacy.h264_coder = video.nv.h264_cavlc ? NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC : NV_ENC_H264_ENTROPY_CODING_MODE_CABAC;
video.nv_legacy.aq = video.nv.adaptive_quantization;
video.nv_legacy.spatial_aq = video.nv.adaptive_quantization;
video.nv_legacy.vbv_percentage_increase = video.nv.vbv_percentage_increase;
#endif
src/config.h +12 −2
@@ -17,6 +17,16 @@
#include "nvenc/nvenc_config.h"
namespace config {
namespace nv {
/**
* @brief Convert Sunshine's NVENC quality preset number to FFmpeg's stable symbolic name.
*
* @param quality_preset Validated Sunshine quality preset in the range 1 through 7.
* @return FFmpeg preset name from `p1` through `p7`.
*/
std::string ffmpeg_preset_from_quality(int quality_preset);
} // namespace nv
// Valid range for the packetsize limit
constexpr int PACKETSIZE_MIN = 200; ///< Lowest accepted configured packet size in bytes.
constexpr int PACKETSIZE_MAX = 65535; ///< Highest accepted configured packet size in bytes.
@@ -73,9 +83,9 @@
bool nv_sunshine_high_power_mode; ///< Request NVIDIA high-power mode for Sunshine.
struct {
std::string preset; ///< FFmpeg NVENC preset name shared by supported FFmpeg versions.
int preset; ///< Legacy NVENC preset selection.
int multipass; ///< Legacy NVENC multipass mode.
int h264_coder; ///< Legacy NVENC H.264 entropy-coding mode.
int spatial_aq; ///< FFmpeg NVENC spatial adaptive-quantization mode.
int aq; ///< Legacy NVENC adaptive-quantization mode.
int vbv_percentage_increase; ///< Legacy NVENC VBV buffer-size percentage increase.
} nv_legacy; ///< Legacy NVIDIA encoder options kept for config compatibility.
src/nvenc/nvenc_dynamic_factory.cpp +8 −0
@@ -78,6 +78,14 @@
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_1:
return std::make_shared<nvenc_dynamic_factory>(
std::move(dll),
sdk_version,
detail::create_nvenc_d3d11_native_1301,
detail::create_nvenc_d3d11_on_cuda_1301
);
case nvenc_sdk_version::sdk_13_0:
return std::make_shared<nvenc_dynamic_factory>(
std::move(dll),
src/nvenc/nvenc_dynamic_factory_versions.h +16 −0
@@ -62,6 +62,22 @@
* @return SDK-neutral encoder instance.
*/
std::unique_ptr<nvenc_d3d11_interface> create_nvenc_d3d11_on_cuda_1300(ID3D11Device *device, shared_dll dll);
/**
* @brief Create an SDK 13.1 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_1301(ID3D11Device *device, shared_dll dll);
/**
* @brief Create an SDK 13.1 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_1301(ID3D11Device *device, shared_dll dll);
} // namespace nvenc::detail
#endif
src/nvenc/nvenc_sdk.h +1 −1
@@ -16,7 +16,7 @@
* @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)
#define NVENC_SDK_VERSION 1301 // NOSONAR(cpp:S5028)
#endif
#ifndef NVENC_NAMESPACE
src/nvenc/nvenc_version.h +4 −0
@@ -18,6 +18,7 @@
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.
sdk_13_1 = 1301U, ///< Video Codec SDK 13.1.
};
/**
@@ -38,6 +39,9 @@
*/
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_1)) {
return sdk_13_1;
}
if (max_version >= std::to_underlying(sdk_13_0)) {
return sdk_13_0;
}
src/video.cpp +3 −3
@@ -786,7 +786,7 @@
{"tune"s, NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY},
{"rc"s, NV_ENC_PARAMS_RC_CBR},
{"multipass"s, &config::video.nv_legacy.multipass},
{"aq"s, &config::video.nv_legacy.aq},
{"spatial-aq"s, &config::video.nv_legacy.spatial_aq},
},
{}, // SDR-specific options
{}, // HDR-specific options
@@ -807,7 +807,7 @@
{"tune"s, NV_ENC_TUNING_INFO_ULTRA_LOW_LATENCY},
{"rc"s, NV_ENC_PARAMS_RC_CBR},
{"multipass"s, &config::video.nv_legacy.multipass},
{"aq"s, &config::video.nv_legacy.aq},
{"spatial-aq"s, &config::video.nv_legacy.spatial_aq},
},
{
// SDR-specific options
@@ -834,7 +834,7 @@
{"rc"s, NV_ENC_PARAMS_RC_CBR},
{"coder"s, &config::video.nv_legacy.h264_coder},
{"multipass"s, &config::video.nv_legacy.multipass},
{"spatial-aq"s, &config::video.nv_legacy.spatial_aq},
{"aq"s, &config::video.nv_legacy.aq},
},
{
// SDR-specific options
tests/unit/test_config.cpp +29 −0
@@ -15,6 +15,35 @@
#include <src/config.h>
#include <src/file_handler.h>
using namespace std::literals;
using NvencPresetNameParam = std::pair<int, std::string_view>;
/**
* @brief Parameterized coverage for FFmpeg's symbolic NVENC preset names.
*/
struct NvencPresetNameTest: testing::TestWithParam<NvencPresetNameParam> {};
TEST_P(NvencPresetNameTest, UsesStableSymbolicName) {
const auto &[quality_preset, expected] = GetParam();
EXPECT_EQ(expected, config::nv::ffmpeg_preset_from_quality(quality_preset));
}
INSTANTIATE_TEST_SUITE_P(
NvencQualityPresets,
NvencPresetNameTest,
testing::Values(
NvencPresetNameParam {1, "p1"sv},
NvencPresetNameParam {2, "p2"sv},
NvencPresetNameParam {3, "p3"sv},
NvencPresetNameParam {4, "p4"sv},
NvencPresetNameParam {5, "p5"sv},
NvencPresetNameParam {6, "p6"sv},
NvencPresetNameParam {7, "p7"sv}
)
);
namespace {
/**
tests/unit/test_nvenc_dynamic_factory.cpp +4 −3
@@ -145,6 +145,7 @@
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},
std::pair {(13U << 4U) | 1U, sdk_13_1},
std::pair {14U << 4U, sdk_13_1},
};
reported_status = 0U;
@@ -163,7 +164,7 @@
const auto dll = make_fake_dll();
nvenc::nvenc_dynamic_factory factory {
dll,
nvenc::nvenc_sdk_version::sdk_13_1,
nvenc::nvenc_sdk_version::sdk_13_0,
[&created_native, &dll](ID3D11Device *, nvenc::shared_dll callback_dll) {
created_native = true;
EXPECT_EQ(callback_dll, dll);
@@ -176,7 +177,7 @@
},
};
EXPECT_EQ(factory.sdk_version(), nvenc::nvenc_sdk_version::sdk_13_1);
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);
tests/unit/test_nvenc_version.cpp +2 −2
@@ -40,8 +40,8 @@
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},
nvenc_version_test_case {1301U, sdk_13_1},
nvenc_version_test_case {1400U, sdk_13_1},
};
for (const auto &[max_version, expected] : test_cases) {
tests/unit/test_video.cpp +28 −0
@@ -7,6 +7,7 @@
// standard includes
#include <algorithm>
#include <array>
#include <limits>
#include <optional>
#include <tuple>
@@ -64,6 +65,33 @@
return std::string(info.param->name);
}
);
#if !defined(_WIN32) && !defined(__APPLE__)
TEST(NvencAvcodecOptionsTest, UsesVersionStablePresetAndSpatialAqNames) {
const std::array codecs {
&video::nvenc.av1,
&video::nvenc.hevc,
&video::nvenc.h264,
};
for (const auto *codec : codecs) {
const auto preset = std::ranges::find(codec->common_options, "preset"sv, &video::encoder_t::option_t::name);
ASSERT_NE(codec->common_options.end(), preset);
ASSERT_TRUE(std::holds_alternative<std::string *>(preset->value));
EXPECT_EQ(&config::video.nv_legacy.preset, std::get<std::string *>(preset->value));
const auto spatial_aq = std::ranges::find(codec->common_options, "spatial-aq"sv, &video::encoder_t::option_t::name);
ASSERT_NE(codec->common_options.end(), spatial_aq);
ASSERT_TRUE(std::holds_alternative<int *>(spatial_aq->value));
EXPECT_EQ(&config::video.nv_legacy.spatial_aq, std::get<int *>(spatial_aq->value));
EXPECT_EQ(
codec->common_options.end(),
std::ranges::find(codec->common_options, "aq"sv, &video::encoder_t::option_t::name)
);
}
}
#endif
TEST_P(EncoderTest, ValidateEncoder) {
// todo:: test something besides fixture setup
third-party/build-deps +0 −0