Skip to content

Commit 1e54ff0

Browse files
committed
vulkan: auto-detect GPU with connected display instead of hardcoding renderD128
On multi-GPU systems the Vulkan encoder defaulted to /dev/dri/renderD128 which may not be the GPU driving the display. This caused encode failures or unnecessary cross-GPU copies. Add platf::find_render_node_with_display() which scans DRM connectors to find the GPU with a connected monitor and returns its render node path. Use this as the default when adapter_name is not configured. Fallback chain: user config > auto-detected GPU > renderD128 > FFmpeg default.
1 parent e61d9ba commit 1e54ff0

File tree

6 files changed

+72
-3
lines changed

6 files changed

+72
-3
lines changed

src/platform/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,8 @@ namespace platf {
861861
*/
862862
std::string get_host_name();
863863

864+
std::string find_render_node_with_display();
865+
864866
/**
865867
* @brief Gets the supported gamepads for this platform backend.
866868
* @details This may be called prior to `platf::input()`!

src/platform/linux/misc.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
#include <fcntl.h>
3939
#include <unistd.h>
4040

41+
#ifdef SUNSHINE_BUILD_DRM
42+
#include <dirent.h>
43+
#include <xf86drm.h>
44+
#include <xf86drmMode.h>
45+
#endif
46+
4147
// local includes
4248
#include "graphics.h"
4349
#include "misc.h"
@@ -1163,4 +1169,53 @@ namespace platf {
11631169
std::unique_ptr<high_precision_timer> create_high_precision_timer() {
11641170
return std::make_unique<linux_high_precision_timer>();
11651171
}
1172+
1173+
std::string find_render_node_with_display() {
1174+
#ifdef SUNSHINE_BUILD_DRM
1175+
auto *dir = opendir("/dev/dri");
1176+
if (!dir) {
1177+
return {};
1178+
}
1179+
1180+
std::string result;
1181+
while (auto *entry = readdir(dir)) {
1182+
if (strncmp(entry->d_name, "card", 4) != 0 || !isdigit(entry->d_name[4])) {
1183+
continue;
1184+
}
1185+
1186+
std::string path = std::string("/dev/dri/") + entry->d_name;
1187+
int fd = open(path.c_str(), O_RDWR);
1188+
if (fd < 0) {
1189+
continue;
1190+
}
1191+
1192+
auto *res = drmModeGetResources(fd);
1193+
if (res) {
1194+
for (int i = 0; i < res->count_connectors && result.empty(); i++) {
1195+
auto *conn = drmModeGetConnector(fd, res->connectors[i]);
1196+
if (conn) {
1197+
if (conn->connection == DRM_MODE_CONNECTED) {
1198+
char *render = drmGetRenderDeviceNameFromFd(fd);
1199+
if (render) {
1200+
result = render;
1201+
free(render);
1202+
}
1203+
}
1204+
drmModeFreeConnector(conn);
1205+
}
1206+
}
1207+
drmModeFreeResources(res);
1208+
}
1209+
close(fd);
1210+
if (!result.empty()) {
1211+
break;
1212+
}
1213+
}
1214+
closedir(dir);
1215+
return result;
1216+
#else
1217+
return {};
1218+
#endif
1219+
}
1220+
11661221
} // namespace platf

src/platform/linux/vulkan_encode.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ namespace vk {
7979

8080
static int create_vulkan_hwdevice(AVBufferRef **hw_device_buf) {
8181
// Resolve render device path to Vulkan device index
82-
if (auto render_path = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name; render_path[0] == '/') {
82+
auto detected = platf::find_render_node_with_display();
83+
auto fallback = detected.empty() ? std::string("/dev/dri/renderD128") : detected;
84+
if (auto render_path = config::video.adapter_name.empty() ? fallback : config::video.adapter_name; render_path[0] == '/') {
8385
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) {
8486
return 0;
8587
}

src/platform/macos/misc.mm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,10 @@ operator bool() override {
560560
std::unique_ptr<high_precision_timer> create_high_precision_timer() {
561561
return std::make_unique<macos_high_precision_timer>();
562562
}
563+
564+
std::string find_render_node_with_display() {
565+
return {};
566+
}
563567
} // namespace platf
564568

565569
namespace dyn {

src/platform/windows/misc.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,4 +1791,8 @@ namespace platf {
17911791

17921792
return true;
17931793
}
1794+
1795+
std::string find_render_node_with_display() {
1796+
return {};
1797+
}
17941798
} // namespace platf

src/video.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3019,8 +3019,10 @@ namespace video {
30193019
return hw_device_buf;
30203020
}
30213021

3022-
// Try render device path first (like VAAPI does), then fallback to device indices
3023-
auto render_device = config::video.adapter_name.empty() ? "/dev/dri/renderD128" : config::video.adapter_name.c_str();
3022+
// Try render device path first, auto-detecting the GPU with a connected display
3023+
auto detected = platf::find_render_node_with_display();
3024+
auto fallback = detected.empty() ? std::string("/dev/dri/renderD128") : detected;
3025+
auto render_device = config::video.adapter_name.empty() ? fallback.c_str() : config::video.adapter_name.c_str();
30243026

30253027
auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VULKAN, render_device, nullptr, 0);
30263028
if (status >= 0) {

0 commit comments

Comments
 (0)