Added better handing for graphics bind failures
This commit is contained in:
@@ -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.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user