Skip to content
Merged
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
9 changes: 9 additions & 0 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,15 @@ namespace platf {
*/
std::string get_host_name();

/**
* @brief Resolves the render device path to use for hardware encoding.
* @details If `config::video.adapter_name` is set, returns that.
* Otherwise, auto-detects the GPU with a connected display via `find_render_node_with_display()`.
* Falls back to `/dev/dri/renderD128` if detection fails.
* @return Resolved render device path (may be empty on non-Linux platforms).
*/
std::string resolve_render_device();

/**
* @brief Gets the supported gamepads for this platform backend.
* @details This may be called prior to `platf::input()`!
Expand Down
63 changes: 63 additions & 0 deletions src/platform/linux/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
#include <fcntl.h>
#include <unistd.h>

#ifdef SUNSHINE_BUILD_DRM
#include <dirent.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#endif

// local includes
#include "graphics.h"
#include "misc.h"
Expand Down Expand Up @@ -1163,4 +1169,61 @@ namespace platf {
std::unique_ptr<high_precision_timer> create_high_precision_timer() {
return std::make_unique<linux_high_precision_timer>();
}

std::string find_render_node_with_display() {
#ifdef SUNSHINE_BUILD_DRM
auto *dir = opendir("/dev/dri");
if (!dir) {
return {};
}

std::string result;
while (auto *entry = readdir(dir)) {
if (strncmp(entry->d_name, "card", 4) != 0 || !isdigit(entry->d_name[4])) {
continue;
}

std::string path = std::string("/dev/dri/") + entry->d_name;
int fd = open(path.c_str(), O_RDWR);
if (fd < 0) {
continue;
}

auto *res = drmModeGetResources(fd);
if (res) {
for (int i = 0; i < res->count_connectors && result.empty(); i++) {
auto *conn = drmModeGetConnector(fd, res->connectors[i]);
if (conn) {
if (conn->connection == DRM_MODE_CONNECTED) {
char *render = drmGetRenderDeviceNameFromFd(fd);
if (render) {
result = render;
free(render);
}
}
drmModeFreeConnector(conn);
}
}
drmModeFreeResources(res);
}
close(fd);
if (!result.empty()) {
break;
}
}
closedir(dir);
return result;
#else
return {};
#endif
}

std::string resolve_render_device() {
if (!config::video.adapter_name.empty()) {
return config::video.adapter_name;
}
auto detected = find_render_node_with_display();
return detected.empty() ? "/dev/dri/renderD128" : detected;
}

} // namespace platf
8 changes: 3 additions & 5 deletions src/platform/linux/vaapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,7 @@ namespace va {

va::display_t display {vaGetDisplayDRM(fd)};
if (!display) {
auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str();

BOOST_LOG(error) << "Couldn't open a va display from DRM with device: "sv << render_device;
BOOST_LOG(error) << "Couldn't open a va display from DRM with device: "sv << platf::resolve_render_device();
return -1;
}

Expand Down Expand Up @@ -642,9 +640,9 @@ namespace va {
}

std::unique_ptr<platf::avcodec_encode_device_t> make_avcodec_encode_device(int width, int height, int offset_x, int offset_y, bool vram) {
auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str();
auto render_device = platf::resolve_render_device();

file_t file = open(render_device, O_RDWR);
file_t file = ::open(render_device.c_str(), O_RDWR); // NOSONAR(cpp:S1874) - `_sopen_s` not available
if (file.el < 0) {
char string[1024];
BOOST_LOG(error) << "Couldn't open "sv << render_device << ": " << strerror_r(errno, string, sizeof(string));
Expand Down
2 changes: 1 addition & 1 deletion src/platform/linux/vulkan_encode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ namespace vk {

static int create_vulkan_hwdevice(AVBufferRef **hw_device_buf) {
// Resolve render device path to Vulkan device index
if (auto render_path = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name; render_path[0] == '/') {
if (auto render_path = platf::resolve_render_device(); render_path[0] == '/') {
if (auto idx = find_vulkan_index_for_render_node(render_path.c_str()); !idx.empty() && av_hwdevice_ctx_create(hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, idx.c_str(), nullptr, 0) >= 0) {
return 0;
}
Expand Down
4 changes: 4 additions & 0 deletions src/platform/macos/misc.mm
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,10 @@ operator bool() override {
std::unique_ptr<high_precision_timer> create_high_precision_timer() {
return std::make_unique<macos_high_precision_timer>();
}

std::string resolve_render_device() {
return {};
}
} // namespace platf

namespace dyn {
Expand Down
4 changes: 4 additions & 0 deletions src/platform/windows/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1791,4 +1791,8 @@ namespace platf {

return true;
}

std::string resolve_render_device() {
return {};
}
} // namespace platf
10 changes: 5 additions & 5 deletions src/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2994,9 +2994,9 @@ namespace video {
return hw_device_buf;
}

auto render_device = config::video.adapter_name.empty() ? nullptr : config::video.adapter_name.c_str();
auto render_device = platf::resolve_render_device();

auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VAAPI, render_device, nullptr, 0);
auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VAAPI, render_device.empty() ? nullptr : render_device.c_str(), nullptr, 0);
if (status < 0) {
char string[AV_ERROR_MAX_STRING_SIZE];
BOOST_LOG(error) << "Failed to create a VAAPI device: "sv << av_make_error_string(string, AV_ERROR_MAX_STRING_SIZE, status);
Expand All @@ -3019,10 +3019,10 @@ namespace video {
return hw_device_buf;
}

// Try render device path first (like VAAPI does), then fallback to device indices
auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str();
// Try render device path first, auto-detecting the GPU with a connected display
auto render_device = platf::resolve_render_device();

auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, render_device, nullptr, 0);
auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, render_device.c_str(), nullptr, 0);
if (status >= 0) {
BOOST_LOG(info) << "Using Vulkan device: "sv << render_device;
return hw_device_buf;
Expand Down
Loading