Added better handing for graphics bind failures

This commit is contained in:
2026-08-19 13:53:01 -06:00
parent bbf3cf0031
commit 4ee223fb73
4 changed files with 69 additions and 11 deletions

View File

@@ -538,16 +538,29 @@ namespace cuda {
} else if (descriptor.sequence > sequence) { } else if (descriptor.sequence > sequence) {
sequence = descriptor.sequence; sequence = descriptor.sequence;
rgb = egl::rgb_t {};
auto rgb_opt = egl::import_source(display.get(), descriptor.sd); auto rgb_opt = egl::import_source(display.get(), descriptor.sd);
if (!rgb_opt) { if (!rgb_opt) {
return -1; // The plane's current format/modifier can't be imported (e.g. a game switched to a
// 10bpc swapchain in exclusive fullscreen that this driver won't bind to a GL texture).
// Encode a blank frame instead of dropping the client, and only log once per failure
// streak to avoid flooding the log every frame.
if (!import_failed_last_frame) {
BOOST_LOG(warning) << "Skipping frame(s): plane format (fourcc: "sv << util::hex(descriptor.sd.fourcc).to_string_view()
<< ") failed to import; will resume automatically if the format changes back"sv;
import_failed_last_frame = true;
}
rgb = egl::create_blank(img);
} else {
if (import_failed_last_frame) {
BOOST_LOG(info) << "Resumed capture after plane format import failure"sv;
import_failed_last_frame = false;
} }
rgb = std::move(*rgb_opt); rgb = std::move(*rgb_opt);
} }
}
auto fmt_desc = av_pix_fmt_desc_get(sw_format); auto fmt_desc = av_pix_fmt_desc_get(sw_format);
@@ -640,6 +653,8 @@ namespace cuda {
int offset_y; ///< Vertical offset in physical pixels. int offset_y; ///< Vertical offset in physical pixels.
bool is_yuv444; ///< Whether the CUDA converter outputs YUV 4:4:4. bool is_yuv444; ///< Whether the CUDA converter outputs YUV 4:4:4.
bool import_failed_last_frame = false; ///< Whether the previous frame's plane import failed, to avoid log spam.
}; };
/** /**

View File

@@ -655,10 +655,23 @@ namespace egl {
gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]); gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]);
if (!gl::egl_image_target_texture_2d()) { if (!gl::egl_image_target_texture_2d()) {
BOOST_LOG(error) << "glEGLImageTargetTexture2DOES is not available; cannot import RGB DMA-BUF"sv; BOOST_LOG(error) << "glEGLImageTargetTexture2DOES is not available; cannot import RGB DMA-BUF"sv;
gl::ctx.BindTexture(GL_TEXTURE_2D, 0);
return std::nullopt; return std::nullopt;
} }
gl::egl_image_target_texture_2d()(GL_TEXTURE_2D, rgb->xrgb8); gl::egl_image_target_texture_2d()(GL_TEXTURE_2D, rgb->xrgb8);
// Some drivers accept an EGLImage of a given DRM format/modifier from eglCreateImage()
// but then reject binding it to a GL texture, e.g. Mesa/RADV rejecting a 10bpc format
// like DRM_FORMAT_XBGR2101010. When that happens, the texture is left with stale or
// incomplete contents, so this must be treated as an import failure rather than
// silently streaming whatever ends up in the texture.
if (auto err = gl::ctx.GetError(); err != GL_NO_ERROR) {
BOOST_LOG(error) << "Failed to bind EGLImage (DRM fourcc: "sv << util::hex(xrgb.fourcc).to_string_view()
<< ") to GL texture: "sv << util::hex(err).to_string_view();
gl::ctx.BindTexture(GL_TEXTURE_2D, 0);
return std::nullopt;
}
gl::ctx.BindTexture(GL_TEXTURE_2D, 0); gl::ctx.BindTexture(GL_TEXTURE_2D, 0);
gl_drain_errors; gl_drain_errors;

View File

@@ -1668,7 +1668,21 @@ namespace platf {
auto rgb_opt = egl::import_source(display.get(), sd); auto rgb_opt = egl::import_source(display.get(), sd);
if (!rgb_opt) { if (!rgb_opt) {
return capture_e::error; // The plane's current format/modifier can't be imported (e.g. a game switched to a
// 10bpc swapchain in exclusive fullscreen that this driver won't bind to a GL texture).
// Skip this frame rather than tearing down the whole capture thread for every client,
// and only log once per failure streak to avoid flooding the log every frame.
if (!import_failed_last_frame) {
BOOST_LOG(warning) << "Skipping frame(s): plane format (fourcc: "sv << util::hex(sd.fourcc).to_string_view()
<< ") failed to import; will resume automatically if the format changes back"sv;
import_failed_last_frame = true;
}
return capture_e::timeout;
}
if (import_failed_last_frame) {
BOOST_LOG(info) << "Resumed capture after plane format import failure"sv;
import_failed_last_frame = false;
} }
auto &rgb = *rgb_opt; auto &rgb = *rgb_opt;
@@ -1726,6 +1740,7 @@ namespace platf {
gbm::gbm_t gbm; ///< GBM device used for buffer allocation. gbm::gbm_t gbm; ///< GBM device used for buffer allocation.
egl::display_t display; ///< EGL display created from the GBM device. egl::display_t display; ///< EGL display created from the GBM device.
egl::ctx_t ctx; ///< EGL context used to copy KMS frames into RAM. egl::ctx_t ctx; ///< EGL context used to copy KMS frames into RAM.
bool import_failed_last_frame = false; ///< Whether the previous frame's plane import failed, to avoid log spam.
}; };
/** /**

View File

@@ -558,16 +558,29 @@ namespace va {
} else if (descriptor.sequence > sequence) { } else if (descriptor.sequence > sequence) {
sequence = descriptor.sequence; sequence = descriptor.sequence;
rgb = egl::rgb_t {};
auto rgb_opt = egl::import_source(display.get(), descriptor.sd); auto rgb_opt = egl::import_source(display.get(), descriptor.sd);
if (!rgb_opt) { if (!rgb_opt) {
return -1; // The plane's current format/modifier can't be imported (e.g. a game switched to a
// 10bpc swapchain in exclusive fullscreen that this driver won't bind to a GL texture).
// Encode a blank frame instead of dropping the client, and only log once per failure
// streak to avoid flooding the log every frame.
if (!import_failed_last_frame) {
BOOST_LOG(warning) << "Skipping frame(s): plane format (fourcc: "sv << util::hex(descriptor.sd.fourcc).to_string_view()
<< ") failed to import; will resume automatically if the format changes back"sv;
import_failed_last_frame = true;
}
rgb = egl::create_blank(img);
} else {
if (import_failed_last_frame) {
BOOST_LOG(info) << "Resumed capture after plane format import failure"sv;
import_failed_last_frame = false;
} }
rgb = std::move(*rgb_opt); rgb = std::move(*rgb_opt);
} }
}
sws.load_vram(descriptor, offset_x, offset_y, rgb->tex[0], false); sws.load_vram(descriptor, offset_x, offset_y, rgb->tex[0], false);
@@ -603,6 +616,8 @@ namespace va {
int offset_x; ///< Horizontal offset in physical pixels. int offset_x; ///< Horizontal offset in physical pixels.
int offset_y; ///< Vertical offset in physical pixels. int offset_y; ///< Vertical offset in physical pixels.
bool import_failed_last_frame = false; ///< Whether the previous frame's plane import failed, to avoid log spam.
}; };
/** /**