Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci-freebsd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ jobs:
devel/pkgconf \
ftp/curl \
graphics/libdrm \
graphics/vulkan-headers \
graphics/vulkan-loader \
graphics/wayland \
lang/python312 \
multimedia/libva \
Expand Down
15 changes: 15 additions & 0 deletions cmake/compile_definitions/linux.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ if(LIBVA_FOUND)
"${CMAKE_SOURCE_DIR}/src/platform/linux/vaapi.cpp")
endif()

# vulkan video encoding (via FFmpeg)
if(${SUNSHINE_ENABLE_VULKAN})
find_package(Vulkan REQUIRED)
else()
set(Vulkan_FOUND OFF)
endif()
if(Vulkan_FOUND)
list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_BUILD_VULKAN=1)
include_directories(SYSTEM ${Vulkan_INCLUDE_DIRS})
list(APPEND PLATFORM_LIBRARIES ${Vulkan_LIBRARIES})
list(APPEND PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.h"
"${CMAKE_SOURCE_DIR}/src/platform/linux/vulkan_encode.cpp")
endif()

# wayland
if(${SUNSHINE_ENABLE_WAYLAND})
find_package(Wayland REQUIRED)
Expand Down
2 changes: 2 additions & 0 deletions cmake/prep/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ elseif(UNIX) # Linux
"Enable KMS grab if available." ON)
option(SUNSHINE_ENABLE_VAAPI
"Enable building vaapi specific code." ON)
option(SUNSHINE_ENABLE_VULKAN
"Enable Vulkan video encoding." ON)
option(SUNSHINE_ENABLE_WAYLAND
"Enable building wayland specific code." ON)
option(SUNSHINE_ENABLE_X11
Expand Down
31 changes: 31 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2090,6 +2090,32 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>

### kms_vblank

<table>
<tr>
<td>Description</td>
<td colspan="2">
Wait for vertical blank (vblank) when using KMS capture. This synchronizes frame capture with the display
refresh rate, which can reduce tearing and improve frame pacing. When the display refresh rate is higher
than the stream frame rate, frames are automatically skipped to match the target FPS.
@note{Applies to Linux only, when using KMS capture.}
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
enabled
@endcode</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
kms_vblank = disabled
@endcode</td>
</tr>
</table>

### encoder

<table>
Expand Down Expand Up @@ -2126,6 +2152,11 @@ editing the `conf` file in a text editor. Use the examples as reference.
<td>vaapi</td>
<td>Use VA-API (AMD, Intel)</td>
</tr>
<tr>
<td>vulkan</td>
<td>Use Vulkan encoder (AMD, Intel, NVIDIA).
@note{Applies to Linux only.}</td>
</tr>
<tr>
<td>software</td>
<td>Encoding occurs on the CPU</td>
Expand Down
2 changes: 2 additions & 0 deletions packaging/linux/Arch/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ depends=(
'openssl'
'opus'
'udev'
'vulkan-icd-loader'
'which'
)

Expand All @@ -62,6 +63,7 @@ makedepends=(
'make'
'nodejs'
'npm'
'vulkan-headers'
)

checkdepends=(
Expand Down
4 changes: 4 additions & 0 deletions packaging/linux/copr/Sunshine.spec
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ BuildRequires: npm
BuildRequires: openssl-devel
BuildRequires: rpm-build
BuildRequires: systemd-rpm-macros
BuildRequires: vulkan-headers
BuildRequires: vulkan-loader-devel
BuildRequires: wget
BuildRequires: which

Expand Down Expand Up @@ -138,6 +140,7 @@ Requires: libX11 >= 1.7.3.1
Requires: numactl-libs >= 2.0.14
Requires: openssl >= 3.0.2
Requires: pulseaudio-libs >= 10.0
Requires: vulkan-loader
%endif

%if 0%{?suse_version}
Expand All @@ -154,6 +157,7 @@ Requires: libX11-6
Requires: libnuma1
Requires: libopenssl3
Requires: libpulse0
Requires: vulkan-loader
%endif

%description
Expand Down
2 changes: 2 additions & 0 deletions packaging/sunshine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class Sunshine < Formula
depends_on "pango"
depends_on "pulseaudio"
depends_on "systemd"
depends_on "vulkan-headers"
depends_on "vulkan-loader"
depends_on "wayland"
end

Expand Down
5 changes: 5 additions & 0 deletions scripts/linux_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ function add_arch_deps() {
'openssl'
'opus'
'udev'
'vulkan-headers'
'vulkan-icd-loader'
'wayland'
)

Expand Down Expand Up @@ -239,6 +241,7 @@ function add_debian_based_deps() {
"libxfixes-dev" # X11
"libxrandr-dev" # X11
"libxtst-dev" # X11
"libvulkan-dev" # Vulkan
"ninja-build"
"npm" # web-ui
"systemd"
Expand Down Expand Up @@ -313,6 +316,8 @@ function add_fedora_deps() {
"opus-devel"
"pulseaudio-libs-devel"
"rpm-build" # if you want to build an RPM binary package
"vulkan-headers"
"vulkan-loader-devel"
"wget" # necessary for cuda install with `run` file
"which" # necessary for cuda install with `run` file
"xorg-x11-server-Xvfb" # necessary for headless unit testing
Expand Down
10 changes: 10 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,12 @@ namespace config {
{}, // encoder
{}, // adapter_name
{}, // output_name
true, // kms_vblank

{
2, // vk.tune (default: ll - low latency)
2, // vk.rc_mode (default: cbr)
},

{
video_t::dd_t::config_option_e::disabled, // configuration_option
Expand Down Expand Up @@ -1120,6 +1126,10 @@ namespace config {
string_f(vars, "encoder", video.encoder);
string_f(vars, "adapter_name", video.adapter_name);
string_f(vars, "output_name", video.output_name);
bool_f(vars, "kms_vblank", video.kms_vblank);

int_f(vars, "vk_tune", video.vk.tune);
int_f(vars, "vk_rc_mode", video.vk.rc_mode);

generic_f(vars, "dd_configuration_option", video.dd.configuration_option, dd::config_option_from_view);
generic_f(vars, "dd_resolution_option", video.dd.resolution_option, dd::resolution_option_from_view);
Expand Down
6 changes: 6 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ namespace config {
std::string encoder;
std::string adapter_name;
std::string output_name;
bool kms_vblank; // Wait for vblank in KMS capture

struct {
int tune; // 0=default, 1=hq, 2=ll, 3=ull
int rc_mode; // 0=auto, 1=cqp, 2=cbr, 3=vbr
} vk;

struct dd_t {
struct workarounds_t {
Expand Down
1 change: 1 addition & 0 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ namespace platf {
dxgi, ///< DXGI
cuda, ///< CUDA
videotoolbox, ///< VideoToolbox
vulkan, ///< Vulkan
unknown ///< Unknown
};

Expand Down
21 changes: 20 additions & 1 deletion src/platform/linux/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,9 +543,28 @@ namespace egl {
gl::tex_t::make(1)
};

// If import failed with modifier, retry without modifier
if (!rgb->xrgb8 && xrgb.modifier != DRM_FORMAT_MOD_INVALID) {
static bool logged_modifier_fallback = false;
if (!logged_modifier_fallback) {
BOOST_LOG(info) << "RGB import with modifier 0x"sv << std::hex << xrgb.modifier
<< " failed, using implicit modifier"sv << std::dec;
logged_modifier_fallback = true;
}

surface_descriptor_t xrgb_linear = xrgb;
xrgb_linear.modifier = DRM_FORMAT_MOD_INVALID;
auto attribs_linear = surface_descriptor_to_egl_attribs(xrgb_linear);

rgb = rgb_t {
egl_display,
eglCreateImage(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attribs_linear.data()),
gl::tex_t::make(1)
};
}

if (!rgb->xrgb8) {
BOOST_LOG(error) << "Couldn't import RGB Image: "sv << util::hex(eglGetError()).to_string_view();

return std::nullopt;
}

Expand Down
Loading