1
0
Fork 0
forked from wry/wry

metal: handle gpu reset

Unfortunately this doesn't seem to work on amdgpu [1]. I've tested that
it works on i915.

[1] https://gitlab.freedesktop.org/drm/amd/-/issues/1749
This commit is contained in:
Julian Orth 2022-05-06 13:09:29 +02:00
parent 4584dee160
commit d2913449ea
21 changed files with 377 additions and 120 deletions

View file

@ -3,9 +3,14 @@ use {
egl::{
display::EglDisplay,
sys::{eglDestroyContext, eglMakeCurrent, EGLContext, EGLSurface, EGL_FALSE, EGL_TRUE},
PROCS,
},
ext::GlExt,
RenderError,
ext::{DisplayExt, GlExt},
sys::{
GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB,
GL_UNKNOWN_CONTEXT_RESET_ARB,
},
RenderError, ResetStatus,
},
std::rc::Rc,
};
@ -31,6 +36,27 @@ impl Drop for EglContext {
static mut CURRENT: EGLContext = EGLContext::none();
impl EglContext {
pub fn reset_status(&self) -> Option<ResetStatus> {
if !self
.dpy
.exts
.contains(DisplayExt::EXT_CREATE_CONTEXT_ROBUSTNESS)
{
return None;
}
let status = self.with_current(|| unsafe {
let status = match PROCS.glGetGraphicsResetStatusKHR() {
0 => return Ok(None),
GL_GUILTY_CONTEXT_RESET_ARB => ResetStatus::Guilty,
GL_INNOCENT_CONTEXT_RESET_ARB => ResetStatus::Innocent,
GL_UNKNOWN_CONTEXT_RESET_ARB => ResetStatus::Unknown,
n => ResetStatus::Other(n),
};
Ok(Some(status))
});
status.unwrap_or_default()
}
#[inline]
pub fn with_current<T, F: FnOnce() -> Result<T, RenderError>>(
&self,

View file

@ -23,7 +23,10 @@ use {
PROCS,
},
ext::{get_display_ext, get_gl_ext, DisplayExt, GlExt},
sys::{eglInitialize, EGL_PLATFORM_GBM_KHR},
sys::{
eglInitialize, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
EGL_LOSE_CONTEXT_ON_RESET_EXT, EGL_PLATFORM_GBM_KHR,
},
RenderError,
},
video::{dmabuf::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER},
@ -104,7 +107,17 @@ impl EglDisplay {
}
pub fn create_context(self: &Rc<Self>) -> Result<Rc<EglContext>, RenderError> {
let attrib = [EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE];
let mut attrib = vec![EGL_CONTEXT_CLIENT_VERSION, 2];
if self
.exts
.contains(DisplayExt::EXT_CREATE_CONTEXT_ROBUSTNESS)
{
attrib.push(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
attrib.push(EGL_LOSE_CONTEXT_ON_RESET_EXT);
} else {
log::warn!("EGL display does not support gpu reset notifications");
}
attrib.push(EGL_NONE);
unsafe {
let ctx = eglCreateContext(
self.dpy,

View file

@ -1,4 +1,4 @@
use uapi::c;
use {crate::render::sys::GLenum, uapi::c};
pub type EGLint = i32;
pub type EGLenum = c::c_uint;
@ -51,6 +51,12 @@ pub const EGL_BAD_DEVICE_EXT: EGLint = 0x322B;
pub const EGL_OPENGL_ES_API: EGLenum = 0x30A0;
pub const EGL_PLATFORM_GBM_KHR: EGLint = 0x31D7;
pub const EGL_CONTEXT_CLIENT_VERSION: EGLint = 0x3098;
pub const EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: EGLint = 0x3138;
pub const EGL_LOSE_CONTEXT_ON_RESET_EXT: EGLint = 0x31BF;
pub const GL_GUILTY_CONTEXT_RESET_ARB: GLenum = 0x8253;
pub const GL_INNOCENT_CONTEXT_RESET_ARB: GLenum = 0x8254;
pub const GL_UNKNOWN_CONTEXT_RESET_ARB: GLenum = 0x8255;
pub const EGL_WIDTH: EGLint = 0x3057;
pub const EGL_HEIGHT: EGLint = 0x3056;

View file

@ -76,6 +76,7 @@ bitflags::bitflags! {
const MESA_CONFIGLESS_CONTEXT = 1 << 4;
const KHR_SURFACELESS_CONTEXT = 1 << 5;
const IMG_CONTEXT_PRIORITY = 1 << 6;
const EXT_CREATE_CONTEXT_ROBUSTNESS = 1 << 7;
}
}
@ -103,6 +104,10 @@ pub(super) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
DisplayExt::KHR_SURFACELESS_CONTEXT,
),
("EGL_IMG_context_priority", DisplayExt::IMG_CONTEXT_PRIORITY),
(
"EGL_EXT_create_context_robustness",
DisplayExt::EXT_CREATE_CONTEXT_ROBUSTNESS,
),
];
match get_dpy_extensions(dpy) {
Some(exts) => get_typed_ext(&exts, DisplayExt::empty(), &map),

View file

@ -66,7 +66,19 @@ impl Debug for RenderContext {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ResetStatus {
Guilty,
Innocent,
Unknown,
Other(u32),
}
impl RenderContext {
pub fn reset_status(&self) -> Option<ResetStatus> {
self.ctx.reset_status()
}
pub fn from_drm_device(drm: &Drm) -> Result<Self, RenderError> {
let nodes = drm.get_nodes()?;
let node = match nodes

View file

@ -198,7 +198,7 @@ impl Renderer<'_> {
std::slice::from_ref(&pos.at_point(x, y)),
&Color::from_rgba_straight(20, 20, 20, 255),
);
if let Some(tex) = placeholder.texture() {
if let Some(tex) = placeholder.texture.get() {
let x = x + (pos.width() - tex.width()) / 2;
let y = y + (pos.height() - tex.height()) / 2;
self.render_texture(&tex, x, y, &ARGB8888);