Skip to content

Commit d9ff6cd

Browse files
committed
harden vulkan encoder fallback and KMS monitor failure handling
1 parent 3c54d5f commit d9ff6cd

2 files changed

Lines changed: 55 additions & 11 deletions

File tree

src/platform/linux/kmsgrab.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,11 @@ namespace platf {
611611
int init(const std::string &display_name, const ::video::config_t &config) {
612612
delay = std::chrono::nanoseconds {1s} / config.framerate;
613613

614+
if (kms::card_descriptors.empty()) {
615+
BOOST_LOG(error) << "No KMS monitor descriptors are available; aborting monitor lookup for ["sv << display_name << ']';
616+
return -1;
617+
}
618+
614619
int monitor_index = util::from_view(display_name);
615620
int monitor = 0;
616621

@@ -777,7 +782,7 @@ namespace platf {
777782
}
778783
}
779784

780-
BOOST_LOG(error) << "Couldn't find monitor ["sv << monitor_index << ']';
785+
BOOST_LOG(error) << "Couldn't find monitor ["sv << monitor_index << "] in "sv << monitor << " enumerated KMS monitor(s)"sv;
781786
return -1;
782787

783788
// Neatly break from nested for loop
@@ -1616,6 +1621,12 @@ namespace platf {
16161621
std::vector<std::string> kms_display_names(mem_type_e hwdevice_type) {
16171622
int count = 0;
16181623

1624+
kms::env_width = 0;
1625+
kms::env_height = 0;
1626+
kms::env_logical_width = 0;
1627+
kms::env_logical_height = 0;
1628+
kms::card_descriptors.clear();
1629+
16191630
if (!fs::exists("/dev/dri")) {
16201631
BOOST_LOG(warning) << "Couldn't find /dev/dri, kmsgrab won't be enabled"sv;
16211632
return {};
@@ -1728,13 +1739,14 @@ namespace platf {
17281739
correlate_to_wayland(cds);
17291740
}
17301741

1731-
// Deduce the full virtual desktop size
1732-
kms::env_width = 0;
1733-
kms::env_height = 0;
1742+
BOOST_LOG(debug) << "Enumerated "sv << display_names.size() << " KMS monitor(s)"sv;
17341743

1735-
kms::env_logical_width = 0;
1736-
kms::env_logical_height = 0;
1744+
if (display_names.empty()) {
1745+
BOOST_LOG(error) << "No KMS monitors were found during enumeration"sv;
1746+
return {};
1747+
}
17371748

1749+
// Deduce the full virtual desktop size
17381750
for (auto &card_descriptor : cds) {
17391751
for (auto &[_, monitor_descriptor] : card_descriptor.crtc_to_monitor) {
17401752
BOOST_LOG(debug) << "Monitor description"sv;

src/video.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,8 @@ namespace video {
11811181
int active_av1_mode;
11821182
bool last_encoder_probe_supported_ref_frames_invalidation = false;
11831183
std::array<bool, 3> last_encoder_probe_supported_yuv444_for_codec = {};
1184+
constexpr auto no_display_available_msg = "Unable to start capture because no display is available"sv;
1185+
constexpr auto no_encoder_selected_msg = "No encoder selected; aborting capture instead of using invalid encoder state"sv;
11841186

11851187
void reset_display(std::shared_ptr<platf::display_t> &disp, const platf::mem_type_e &type, const std::string &display_name, const config_t &config) {
11861188
// We try this twice, in case we still get an error on reinitialization
@@ -1214,16 +1216,20 @@ namespace video {
12141216
}
12151217

12161218
// Refresh the display names
1217-
auto old_display_names = std::move(display_names);
1219+
auto had_display_names = !display_names.empty();
12181220
display_names = platf::display_names(dev_type);
12191221

1220-
// If we now have no displays, let's put the old display array back and fail
1221-
if (display_names.empty() && !old_display_names.empty()) {
1222+
// If we now have no displays, fail instead of reusing stale display names.
1223+
if (display_names.empty() && had_display_names) {
12221224
BOOST_LOG(error) << "No displays were found after reenumeration!"sv;
1223-
display_names = std::move(old_display_names);
1225+
current_display_index = -1;
12241226
return;
1225-
} else if (display_names.empty()) {
1227+
} else if (display_names.empty() && !output_name.empty()) {
12261228
display_names.emplace_back(output_name);
1229+
} else if (display_names.empty()) {
1230+
BOOST_LOG(error) << "No displays were found during enumeration!"sv;
1231+
current_display_index = -1;
1232+
return;
12271233
}
12281234

12291235
// We now have a new display name list, so reset the index back to 0
@@ -1284,6 +1290,10 @@ namespace video {
12841290
std::vector<std::string> display_names;
12851291
int display_p = -1;
12861292
refresh_displays(encoder.platform_formats->dev_type, display_names, display_p);
1293+
if (display_p < 0 || display_names.empty()) {
1294+
BOOST_LOG(error) << no_display_available_msg;
1295+
return;
1296+
}
12871297
auto disp = platf::display(encoder.platform_formats->dev_type, display_names[display_p], capture_ctxs.front().config);
12881298
if (!disp) {
12891299
return;
@@ -1912,6 +1922,13 @@ namespace video {
19121922
<< video_format.name << "]: "sv
19131923
<< av_make_error_string(err_str, AV_ERROR_MAX_STRING_SIZE, status);
19141924

1925+
if (encoder.name == "vulkan"sv) {
1926+
BOOST_LOG(error)
1927+
<< "Vulkan encoder setup failed for ["sv << video_format.name
1928+
<< "]; this GPU or driver does not expose the required Vulkan video encode capability. "
1929+
<< "Sunshine will discard this encoder and continue probing fallback encoders."sv;
1930+
}
1931+
19151932
return nullptr;
19161933
}
19171934
}
@@ -2286,6 +2303,10 @@ namespace video {
22862303
while (encode_session_ctx_queue.running()) {
22872304
// Refresh display names since a display removal might have caused the reinitialization
22882305
refresh_displays(encoder.platform_formats->dev_type, display_names, display_p);
2306+
if (display_p < 0 || display_names.empty()) {
2307+
BOOST_LOG(error) << no_display_available_msg;
2308+
return encode_e::error;
2309+
}
22892310

22902311
// Process any pending display switch with the new list of displays
22912312
if (switch_display_event->peek()) {
@@ -2491,6 +2512,11 @@ namespace video {
24912512
display = ref->display_wp->lock();
24922513
}
24932514

2515+
if (!chosen_encoder) {
2516+
BOOST_LOG(error) << no_encoder_selected_msg;
2517+
return;
2518+
}
2519+
24942520
auto &encoder = *chosen_encoder;
24952521

24962522
auto encode_device = make_encode_device(*display, encoder, config);
@@ -2533,6 +2559,11 @@ namespace video {
25332559
) {
25342560
auto idr_events = mail->event<bool>(mail::idr);
25352561

2562+
if (!chosen_encoder) {
2563+
BOOST_LOG(error) << no_encoder_selected_msg;
2564+
return;
2565+
}
2566+
25362567
idr_events->raise(true);
25372568
if (chosen_encoder->flags & PARALLEL_ENCODING) {
25382569
capture_async(std::move(mail), config, channel_data);
@@ -3013,6 +3044,7 @@ namespace video {
30133044

30143045
if (encode_device && encode_device->data) {
30153046
if (((vulkan_init_avcodec_hardware_input_buffer_fn) encode_device->data)(encode_device, &hw_device_buf)) {
3047+
BOOST_LOG(error) << "Failed to create a Vulkan device from the capture backend; aborting Vulkan encoder setup"sv;
30163048
return -1;
30173049
}
30183050
return hw_device_buf;

0 commit comments

Comments
 (0)