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:
parent
4584dee160
commit
d2913449ea
21 changed files with 377 additions and 120 deletions
|
|
@ -1,3 +1,5 @@
|
|||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
|
|
@ -16,6 +18,9 @@ use {
|
|||
std::{cell::Cell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
use crate::utils::errorfmt::ErrorFmt;
|
||||
use crate::video::dmabuf::DmaBuf;
|
||||
use crate::wire::jay_screenshot::Dmabuf;
|
||||
|
||||
pub enum WlBufferStorage {
|
||||
Shm { mem: ClientMemOffset, stride: i32 },
|
||||
|
|
@ -28,7 +33,9 @@ pub struct WlBuffer {
|
|||
pub client: Rc<Client>,
|
||||
pub rect: Rect,
|
||||
pub format: &'static Format,
|
||||
pub storage: WlBufferStorage,
|
||||
dmabuf: Option<DmaBuf>,
|
||||
render_ctx_version: Cell<u32>,
|
||||
pub storage: RefCell<Option<WlBufferStorage>>,
|
||||
pub texture: CloneCell<Option<Rc<Texture>>>,
|
||||
pub famebuffer: CloneCell<Option<Rc<Framebuffer>>>,
|
||||
width: i32,
|
||||
|
|
@ -46,6 +53,7 @@ impl WlBuffer {
|
|||
id: WlBufferId,
|
||||
client: &Rc<Client>,
|
||||
format: &'static Format,
|
||||
dmabuf: DmaBuf,
|
||||
img: &Rc<Image>,
|
||||
) -> Self {
|
||||
let width = img.width();
|
||||
|
|
@ -60,7 +68,9 @@ impl WlBuffer {
|
|||
height,
|
||||
texture: CloneCell::new(None),
|
||||
famebuffer: Default::default(),
|
||||
storage: WlBufferStorage::Dmabuf(img.clone()),
|
||||
dmabuf: Some(dmabuf),
|
||||
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
|
||||
storage: RefCell::new(Some(WlBufferStorage::Dmabuf(img.clone()))),
|
||||
tracker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +102,9 @@ impl WlBuffer {
|
|||
client: client.clone(),
|
||||
rect: Rect::new_sized(0, 0, width, height).unwrap(),
|
||||
format,
|
||||
storage: WlBufferStorage::Shm { mem, stride },
|
||||
dmabuf: None,
|
||||
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
|
||||
storage: RefCell::new(Some(WlBufferStorage::Shm { mem, stride })),
|
||||
width,
|
||||
height,
|
||||
texture: CloneCell::new(None),
|
||||
|
|
@ -101,8 +113,43 @@ impl WlBuffer {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn handle_gfx_context_change(&self) {
|
||||
let ctx_version = self.client.state.render_ctx_version.get();
|
||||
if self.render_ctx_version.replace(ctx_version) == ctx_version {
|
||||
return;
|
||||
}
|
||||
self.texture.set(None);
|
||||
self.famebuffer.set(None);
|
||||
let mut storage = self.storage.borrow_mut();
|
||||
if let Some(storage) = &mut *storage {
|
||||
if let WlBufferStorage::Shm { .. } = storage {
|
||||
return;
|
||||
}
|
||||
}
|
||||
*storage = None;
|
||||
let ctx = match self.client.state.render_ctx.get() {
|
||||
Some(ctx) => ctx,
|
||||
_ => return,
|
||||
};
|
||||
if let Some(dmabuf) = &self.dmabuf {
|
||||
let image = match ctx.dmabuf_img(dmabuf) {
|
||||
Ok(image) => image,
|
||||
Err(e) => {
|
||||
log::error!("Cannot re-import wl_buffer after graphics context reset: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
};
|
||||
*storage = Some(WlBufferStorage::Dmabuf(image));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_texture(&self) -> Result<(), WlBufferError> {
|
||||
match &self.storage {
|
||||
let storage = self.storage.borrow_mut();
|
||||
let storage = match storage.deref() {
|
||||
Some(s) => s,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
match storage {
|
||||
WlBufferStorage::Shm { mem, stride } => {
|
||||
self.texture.set(None);
|
||||
if let Some(ctx) = self.client.state.render_ctx.get() {
|
||||
|
|
@ -122,7 +169,12 @@ impl WlBuffer {
|
|||
}
|
||||
|
||||
pub fn update_framebuffer(&self) -> Result<(), WlBufferError> {
|
||||
match &self.storage {
|
||||
let storage = self.storage.borrow_mut();
|
||||
let storage = match storage.deref() {
|
||||
Some(s) => s,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
match storage {
|
||||
WlBufferStorage::Shm { .. } => {
|
||||
// nothing
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ impl WlDrm {
|
|||
}
|
||||
}
|
||||
let img = ctx.dmabuf_img(&dmabuf)?;
|
||||
let buffer = Rc::new(WlBuffer::new_dmabuf(req.id, &self.client, format, &img));
|
||||
let buffer = Rc::new(WlBuffer::new_dmabuf(req.id, &self.client, format, dmabuf, &img));
|
||||
track!(self.client, buffer);
|
||||
self.client.add_client_obj(&buffer)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ impl WlOutputGlobal {
|
|||
continue;
|
||||
}
|
||||
let rect = capture.rect;
|
||||
if let WlBufferStorage::Shm { mem, .. } = &wl_buffer.storage {
|
||||
if let Some(WlBufferStorage::Shm { mem, .. }) = wl_buffer.storage.borrow_mut().deref() {
|
||||
let res = mem.access(|mem| {
|
||||
fb.copy_to_shm(
|
||||
rect.x1(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::ops::Deref;
|
||||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
|
|
@ -114,7 +115,7 @@ impl ZwlrScreencopyFrameV1 {
|
|||
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferFormat);
|
||||
}
|
||||
buffer.update_framebuffer()?;
|
||||
if let WlBufferStorage::Shm { stride, .. } = &buffer.storage {
|
||||
if let Some(WlBufferStorage::Shm { stride, .. }) = buffer.storage.borrow_mut().deref() {
|
||||
if *stride != self.rect.width() * 4 {
|
||||
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ impl ZwpLinuxBufferParamsV1 {
|
|||
buffer_id,
|
||||
&self.parent.client,
|
||||
format.format,
|
||||
dmabuf,
|
||||
&img,
|
||||
));
|
||||
track!(self.parent.client, buffer);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue