render: propagate errors
This commit is contained in:
parent
d9fa3f6732
commit
1b4492c670
14 changed files with 169 additions and 105 deletions
|
|
@ -114,6 +114,14 @@ pub enum MetalError {
|
|||
MissingDevModifier(&'static str),
|
||||
#[error("Device GFX API cannot read any buffers writable by the render GFX API (format {0})")]
|
||||
MissingRenderModifier(&'static str),
|
||||
#[error("Could not render the frame")]
|
||||
RenderFrame(#[source] GfxError),
|
||||
#[error("Could not copy frame to output device")]
|
||||
CopyToOutput(#[source] GfxError),
|
||||
#[error("Could not perform atomic commit")]
|
||||
Commit(#[source] DrmError),
|
||||
#[error("Could not clear framebuffer")]
|
||||
Clear(#[source] GfxError),
|
||||
}
|
||||
|
||||
pub struct MetalBackend {
|
||||
|
|
|
|||
|
|
@ -376,7 +376,9 @@ impl MetalConnector {
|
|||
async fn present_loop(self: Rc<Self>) {
|
||||
loop {
|
||||
self.present_trigger.triggered().await;
|
||||
let _ = self.present(true);
|
||||
if let Err(e) = self.present(true) {
|
||||
log::error!("Could not present: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -585,7 +587,7 @@ impl MetalConnector {
|
|||
plane: &Rc<MetalPlane>,
|
||||
output: &OutputNode,
|
||||
try_direct_scanout: bool,
|
||||
) -> PresentFb {
|
||||
) -> Result<PresentFb, MetalError> {
|
||||
self.trim_scanout_cache();
|
||||
let buffer_fb = buffer.render_fb();
|
||||
let render_hw_cursor = !self.cursor_enabled.get();
|
||||
|
|
@ -630,23 +632,23 @@ impl MetalConnector {
|
|||
}
|
||||
let fb = match &direct_scanout_data {
|
||||
None => {
|
||||
buffer_fb
|
||||
.perform_render_pass(pass)
|
||||
.map_err(MetalError::RenderFrame)?;
|
||||
buffer.copy_to_dev()?;
|
||||
self.next_buffer.fetch_add(1);
|
||||
buffer_fb.perform_render_pass(pass);
|
||||
if let Some(tex) = &buffer.dev_tex {
|
||||
buffer.dev_fb.copy_texture(tex, 0, 0);
|
||||
}
|
||||
output.perform_screencopies(&buffer.render_tex, !render_hw_cursor, 0, 0, None);
|
||||
buffer.drm.clone()
|
||||
}
|
||||
Some(dsd) => dsd.fb.clone(),
|
||||
};
|
||||
PresentFb {
|
||||
Ok(PresentFb {
|
||||
fb,
|
||||
direct_scanout_data,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn present(&self, try_direct_scanout: bool) -> Result<(), ()> {
|
||||
pub fn present(&self, try_direct_scanout: bool) -> Result<(), MetalError> {
|
||||
let crtc = match self.crtc.get() {
|
||||
Some(crtc) => crtc,
|
||||
_ => return Ok(()),
|
||||
|
|
@ -676,7 +678,7 @@ impl MetalConnector {
|
|||
let buffer = &buffers[self.next_buffer.get() % buffers.len()];
|
||||
let mut rr = self.render_result.borrow_mut();
|
||||
let fb =
|
||||
self.prepare_present_fb(&mut rr, buffer, &plane, &node, try_direct_scanout);
|
||||
self.prepare_present_fb(&mut rr, buffer, &plane, &node, try_direct_scanout)?;
|
||||
rr.dispatch_frame_requests();
|
||||
let (crtc_x, crtc_y, crtc_w, crtc_h, src_width, src_height) =
|
||||
match &fb.direct_scanout_data {
|
||||
|
|
@ -721,9 +723,7 @@ impl MetalConnector {
|
|||
let buffers = self.cursor_buffers.get().unwrap();
|
||||
let buffer = &buffers[front_buffer % buffers.len()];
|
||||
if cursor_swap_buffer {
|
||||
if let Some(tex) = &buffer.dev_tex {
|
||||
buffer.dev_fb.copy_texture(tex, 0, 0);
|
||||
}
|
||||
buffer.copy_to_dev()?;
|
||||
}
|
||||
let (width, height) = buffer.dev_fb.physical_size();
|
||||
changes.change_object(plane.id, |c| {
|
||||
|
|
@ -746,32 +746,28 @@ impl MetalConnector {
|
|||
}
|
||||
}
|
||||
if let Err(e) = changes.commit(DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, 0) {
|
||||
match e {
|
||||
DrmError::Atomic(OsError(c::EACCES)) => {
|
||||
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
|
||||
}
|
||||
_ => 'handle_failure: {
|
||||
if let Some(fb) = &new_fb {
|
||||
if let Some(dsd) = &fb.direct_scanout_data {
|
||||
if self.present(false).is_ok() {
|
||||
let mut cache = self.scanout_buffers.borrow_mut();
|
||||
if let Some(buffer) = cache.remove(&dsd.dma_buf_id) {
|
||||
cache.insert(
|
||||
dsd.dma_buf_id,
|
||||
DirectScanoutCache {
|
||||
tex: buffer.tex,
|
||||
fb: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
break 'handle_failure;
|
||||
}
|
||||
if let DrmError::Atomic(OsError(c::EACCES)) = e {
|
||||
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(fb) = &new_fb {
|
||||
if let Some(dsd) = &fb.direct_scanout_data {
|
||||
if self.present(false).is_ok() {
|
||||
let mut cache = self.scanout_buffers.borrow_mut();
|
||||
if let Some(buffer) = cache.remove(&dsd.dma_buf_id) {
|
||||
cache.insert(
|
||||
dsd.dma_buf_id,
|
||||
DirectScanoutCache {
|
||||
tex: buffer.tex,
|
||||
fb: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
log::error!("Could not set plane framebuffer: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
Err(())
|
||||
Err(MetalError::Commit(e))
|
||||
} else {
|
||||
if let Some(fb) = new_fb {
|
||||
self.next_framebuffer.set(Some(fb));
|
||||
|
|
@ -2160,7 +2156,7 @@ impl MetalBackend {
|
|||
Ok(fb) => fb,
|
||||
Err(e) => return Err(MetalError::ImportFb(e)),
|
||||
};
|
||||
dev_fb.clear();
|
||||
dev_fb.clear().map_err(MetalError::Clear)?;
|
||||
let (dev_tex, render_tex, render_fb) = if dev.id == render_ctx.dev_id {
|
||||
let render_tex = match dev_img.to_texture() {
|
||||
Ok(fb) => fb,
|
||||
|
|
@ -2209,7 +2205,7 @@ impl MetalBackend {
|
|||
Ok(fb) => fb,
|
||||
Err(e) => return Err(MetalError::ImportFb(e)),
|
||||
};
|
||||
render_fb.clear();
|
||||
render_fb.clear().map_err(MetalError::Clear)?;
|
||||
let render_tex = match render_img.to_texture() {
|
||||
Ok(fb) => fb,
|
||||
Err(e) => return Err(MetalError::ImportTexture(e)),
|
||||
|
|
@ -2429,6 +2425,15 @@ impl RenderBuffer {
|
|||
.clone()
|
||||
.unwrap_or_else(|| self.dev_fb.clone())
|
||||
}
|
||||
|
||||
fn copy_to_dev(&self) -> Result<(), MetalError> {
|
||||
let Some(tex) = &self.dev_tex else {
|
||||
return Ok(());
|
||||
};
|
||||
self.dev_fb
|
||||
.copy_texture(tex, 0, 0)
|
||||
.map_err(MetalError::CopyToOutput)
|
||||
}
|
||||
}
|
||||
|
||||
fn modes_equal(a: &DrmModeInfo, b: &DrmModeInfo) -> bool {
|
||||
|
|
|
|||
|
|
@ -738,13 +738,17 @@ impl XBackend {
|
|||
image.last_serial.set(serial);
|
||||
|
||||
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
||||
self.state.present_output(
|
||||
let res = self.state.present_output(
|
||||
&node,
|
||||
&image.fb.get(),
|
||||
&image.tex.get(),
|
||||
&mut self.render_result.borrow_mut(),
|
||||
true,
|
||||
);
|
||||
if let Err(e) = res {
|
||||
log::error!("Could not render screen: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let pp = PresentPixmap {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ pub trait GfxFramebuffer: Debug {
|
|||
|
||||
fn physical_size(&self) -> (i32, i32);
|
||||
|
||||
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>);
|
||||
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), GfxError>;
|
||||
|
||||
fn copy_to_shm(
|
||||
self: Rc<Self>,
|
||||
|
|
@ -206,13 +206,13 @@ pub trait GfxFramebuffer: Debug {
|
|||
}
|
||||
|
||||
impl dyn GfxFramebuffer {
|
||||
pub fn clear(&self) {
|
||||
self.clear_with(0.0, 0.0, 0.0, 0.0);
|
||||
pub fn clear(&self) -> Result<(), GfxError> {
|
||||
self.clear_with(0.0, 0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
pub fn clear_with(&self, r: f32, g: f32, b: f32, a: f32) {
|
||||
pub fn clear_with(&self, r: f32, g: f32, b: f32, a: f32) -> Result<(), GfxError> {
|
||||
let ops = self.take_render_ops();
|
||||
self.render(ops, Some(&Color { r, g, b, a }));
|
||||
self.render(ops, Some(&Color { r, g, b, a }))
|
||||
}
|
||||
|
||||
pub fn logical_size(&self, transform: Transform) -> (i32, i32) {
|
||||
|
|
@ -237,13 +237,18 @@ impl dyn GfxFramebuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn copy_texture(&self, texture: &Rc<dyn GfxTexture>, x: i32, y: i32) {
|
||||
pub fn copy_texture(
|
||||
&self,
|
||||
texture: &Rc<dyn GfxTexture>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) -> Result<(), GfxError> {
|
||||
let mut ops = self.take_render_ops();
|
||||
let scale = Scale::from_int(1);
|
||||
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
|
||||
renderer.render_texture(texture, x, y, None, None, scale, None, None);
|
||||
let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT);
|
||||
self.render(ops, clear);
|
||||
self.render(ops, clear)
|
||||
}
|
||||
|
||||
pub fn render_custom(
|
||||
|
|
@ -251,11 +256,11 @@ impl dyn GfxFramebuffer {
|
|||
scale: Scale,
|
||||
clear: Option<&Color>,
|
||||
f: &mut dyn FnMut(&mut RendererBase),
|
||||
) {
|
||||
) -> Result<(), GfxError> {
|
||||
let mut ops = self.take_render_ops();
|
||||
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
|
||||
f(&mut renderer);
|
||||
self.render(ops, clear);
|
||||
self.render(ops, clear)
|
||||
}
|
||||
|
||||
pub fn create_render_pass(
|
||||
|
|
@ -326,7 +331,7 @@ impl dyn GfxFramebuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn perform_render_pass(&self, pass: GfxRenderPass) {
|
||||
pub fn perform_render_pass(&self, pass: GfxRenderPass) -> Result<(), GfxError> {
|
||||
self.render(pass.ops, pass.clear.as_ref())
|
||||
}
|
||||
|
||||
|
|
@ -338,7 +343,7 @@ impl dyn GfxFramebuffer {
|
|||
result: Option<&mut RenderResult>,
|
||||
scale: Scale,
|
||||
render_hardware_cursor: bool,
|
||||
) {
|
||||
) -> Result<(), GfxError> {
|
||||
self.render_node(
|
||||
node,
|
||||
state,
|
||||
|
|
@ -361,7 +366,7 @@ impl dyn GfxFramebuffer {
|
|||
render_hardware_cursor: bool,
|
||||
black_background: bool,
|
||||
transform: Transform,
|
||||
) {
|
||||
) -> Result<(), GfxError> {
|
||||
let pass = self.create_render_pass(
|
||||
node,
|
||||
state,
|
||||
|
|
@ -372,7 +377,7 @@ impl dyn GfxFramebuffer {
|
|||
black_background,
|
||||
transform,
|
||||
);
|
||||
self.perform_render_pass(pass);
|
||||
self.perform_render_pass(pass)
|
||||
}
|
||||
|
||||
pub fn render_hardware_cursor(
|
||||
|
|
@ -381,7 +386,7 @@ impl dyn GfxFramebuffer {
|
|||
state: &State,
|
||||
scale: Scale,
|
||||
transform: Transform,
|
||||
) {
|
||||
) -> Result<(), GfxError> {
|
||||
let mut ops = self.take_render_ops();
|
||||
let mut renderer = Renderer {
|
||||
base: self.renderer_base(&mut ops, scale, transform),
|
||||
|
|
@ -394,7 +399,7 @@ impl dyn GfxFramebuffer {
|
|||
},
|
||||
};
|
||||
cursor.render_hardware_cursor(&mut renderer);
|
||||
self.render(ops, Some(&Color::TRANSPARENT));
|
||||
self.render(ops, Some(&Color::TRANSPARENT))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use {
|
|||
renderer::context::GlRenderContext,
|
||||
run_ops,
|
||||
sys::{GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||
RenderError,
|
||||
},
|
||||
theme::Color,
|
||||
},
|
||||
|
|
@ -64,9 +65,9 @@ impl Framebuffer {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) {
|
||||
pub fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), RenderError> {
|
||||
let gles = self.ctx.ctx.dpy.gles;
|
||||
let _ = self.ctx.ctx.with_current(|| {
|
||||
let res = self.ctx.ctx.with_current(|| {
|
||||
unsafe {
|
||||
(gles.glBindFramebuffer)(GL_FRAMEBUFFER, self.gl.fbo);
|
||||
(gles.glViewport)(0, 0, self.gl.width, self.gl.height);
|
||||
|
|
@ -83,6 +84,7 @@ impl Framebuffer {
|
|||
Ok(())
|
||||
});
|
||||
*self.ctx.gfx_ops.borrow_mut() = ops;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,8 +103,8 @@ impl GfxFramebuffer for Framebuffer {
|
|||
(self.gl.width, self.gl.height)
|
||||
}
|
||||
|
||||
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) {
|
||||
self.render(ops, clear);
|
||||
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), GfxError> {
|
||||
self.render(ops, clear).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn copy_to_shm(
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ pub enum VulkanError {
|
|||
height: i32,
|
||||
stride: i32,
|
||||
},
|
||||
#[error(transparent)]
|
||||
GfxError(GfxError),
|
||||
}
|
||||
|
||||
impl From<VulkanError> for GfxError {
|
||||
|
|
|
|||
|
|
@ -525,8 +525,10 @@ impl GfxFramebuffer for VulkanImage {
|
|||
(self.width as _, self.height as _)
|
||||
}
|
||||
|
||||
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) {
|
||||
self.renderer.execute(self, &ops, clear).unwrap();
|
||||
fn render(&self, ops: Vec<GfxApiOpt>, clear: Option<&Color>) -> Result<(), GfxError> {
|
||||
self.renderer
|
||||
.execute(self, &ops, clear)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn copy_to_shm(
|
||||
|
|
|
|||
|
|
@ -698,7 +698,9 @@ impl VulkanRenderer {
|
|||
&[],
|
||||
true,
|
||||
)?;
|
||||
(&*tmp_tex as &dyn GfxFramebuffer).copy_texture(&(tex.clone() as _), x, y);
|
||||
(&*tmp_tex as &dyn GfxFramebuffer)
|
||||
.copy_texture(&(tex.clone() as _), x, y)
|
||||
.map_err(VulkanError::GfxError)?;
|
||||
self.read_all_pixels(&tmp_tex, stride, dst)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ impl JayScreencast {
|
|||
let mut buffer = self.buffers.borrow_mut();
|
||||
for (idx, buffer) in buffer.deref_mut().iter_mut().enumerate() {
|
||||
if buffer.free {
|
||||
self.client.state.perform_screencopy(
|
||||
let res = self.client.state.perform_screencopy(
|
||||
texture,
|
||||
&buffer.fb,
|
||||
on.global.pos.get(),
|
||||
|
|
@ -183,12 +183,20 @@ impl JayScreencast {
|
|||
size,
|
||||
on.global.persistent.transform.get(),
|
||||
);
|
||||
self.client.event(Ready {
|
||||
self_id: self.id,
|
||||
idx: idx as _,
|
||||
});
|
||||
buffer.free = false;
|
||||
return;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
self.client.event(Ready {
|
||||
self_id: self.id,
|
||||
idx: idx as _,
|
||||
});
|
||||
buffer.free = false;
|
||||
return;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not perform screencopy: {}", ErrorFmt(e));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.missed_frame.set(true);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use {
|
|||
buffd::{MsgParser, MsgParserError},
|
||||
clonecell::CloneCell,
|
||||
copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt,
|
||||
linkedlist::LinkedList,
|
||||
transform_ext::TransformExt,
|
||||
},
|
||||
|
|
@ -243,7 +244,7 @@ impl WlOutputGlobal {
|
|||
if let Some(WlBufferStorage::Shm { mem, stride }) =
|
||||
wl_buffer.storage.borrow_mut().deref()
|
||||
{
|
||||
self.state.perform_shm_screencopy(
|
||||
let res = self.state.perform_shm_screencopy(
|
||||
tex,
|
||||
self.pos.get(),
|
||||
x_off,
|
||||
|
|
@ -255,6 +256,11 @@ impl WlOutputGlobal {
|
|||
wl_buffer.format,
|
||||
Transform::None,
|
||||
);
|
||||
if let Err(e) = res {
|
||||
log::warn!("Could not perform shm screencopy: {}", ErrorFmt(e));
|
||||
capture.send_failed();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
let fb = match wl_buffer.famebuffer.get() {
|
||||
Some(fb) => fb,
|
||||
|
|
@ -264,7 +270,7 @@ impl WlOutputGlobal {
|
|||
continue;
|
||||
}
|
||||
};
|
||||
self.state.perform_screencopy(
|
||||
let res = self.state.perform_screencopy(
|
||||
tex,
|
||||
&fb,
|
||||
self.pos.get(),
|
||||
|
|
@ -274,6 +280,11 @@ impl WlOutputGlobal {
|
|||
size,
|
||||
Transform::None,
|
||||
);
|
||||
if let Err(e) = res {
|
||||
log::warn!("Could not perform screencopy: {}", ErrorFmt(e));
|
||||
capture.send_failed();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if capture.with_damage.get() {
|
||||
capture.send_damage();
|
||||
|
|
|
|||
|
|
@ -299,13 +299,20 @@ impl WlSeatGlobal {
|
|||
if extents.intersects(&Rect::new_sized(-x_rel, -y_rel, width, height).unwrap()) {
|
||||
if render {
|
||||
let buffer = hc.get_buffer();
|
||||
buffer.render_hardware_cursor(
|
||||
let res = buffer.render_hardware_cursor(
|
||||
cursor.deref(),
|
||||
&self.state,
|
||||
scale,
|
||||
transform,
|
||||
);
|
||||
hc.swap_buffer();
|
||||
match res {
|
||||
Ok(_) => {
|
||||
hc.swap_buffer();
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not render hardware cursor: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
hc.set_enabled(true);
|
||||
let mode = output.global.mode.get();
|
||||
|
|
|
|||
|
|
@ -628,6 +628,19 @@ impl WindowData {
|
|||
}
|
||||
return;
|
||||
};
|
||||
|
||||
let res = buf
|
||||
.fb
|
||||
.render_custom(self.scale.get(), Some(&Color::from_gray(0)), &mut |r| {
|
||||
if let Some(content) = self.content.get() {
|
||||
content.render_at(r, 0.0, 0.0)
|
||||
}
|
||||
});
|
||||
if let Err(e) = res {
|
||||
log::error!("Could not render frame: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
|
||||
self.frame_missed.set(false);
|
||||
|
||||
self.surface.frame({
|
||||
|
|
@ -643,13 +656,6 @@ impl WindowData {
|
|||
self.have_frame.set(false);
|
||||
buf.free.set(false);
|
||||
|
||||
buf.fb
|
||||
.render_custom(self.scale.get(), Some(&Color::from_gray(0)), &mut |r| {
|
||||
if let Some(content) = self.content.get() {
|
||||
content.render_at(r, 0.0, 0.0)
|
||||
}
|
||||
});
|
||||
|
||||
self.surface.attach(&buf.wl);
|
||||
self.surface.commit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
|
|||
true,
|
||||
false,
|
||||
Transform::None,
|
||||
);
|
||||
)?;
|
||||
let drm = gbm.drm.dup_render()?.fd().clone();
|
||||
Ok(Screenshot { drm, bo })
|
||||
}
|
||||
|
|
|
|||
54
src/state.rs
54
src/state.rs
|
|
@ -81,6 +81,7 @@ use {
|
|||
sync::Arc,
|
||||
time::Duration,
|
||||
},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct State {
|
||||
|
|
@ -769,7 +770,7 @@ impl State {
|
|||
tex: &Rc<dyn GfxTexture>,
|
||||
rr: &mut RenderResult,
|
||||
render_hw_cursor: bool,
|
||||
) {
|
||||
) -> Result<(), GfxError> {
|
||||
fb.render_output(
|
||||
output,
|
||||
self,
|
||||
|
|
@ -777,9 +778,10 @@ impl State {
|
|||
Some(rr),
|
||||
output.global.persistent.scale.get(),
|
||||
render_hw_cursor,
|
||||
);
|
||||
)?;
|
||||
output.perform_screencopies(tex, !render_hw_cursor, 0, 0, None);
|
||||
rr.dispatch_frame_requests();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn perform_screencopy(
|
||||
|
|
@ -792,7 +794,7 @@ impl State {
|
|||
y_off: i32,
|
||||
size: Option<(i32, i32)>,
|
||||
transform: Transform,
|
||||
) {
|
||||
) -> Result<(), GfxError> {
|
||||
let mut ops = target.take_render_ops();
|
||||
let mut renderer = Renderer {
|
||||
base: target.renderer_base(&mut ops, Scale::from_int(1), Transform::None),
|
||||
|
|
@ -828,7 +830,7 @@ impl State {
|
|||
}
|
||||
}
|
||||
}
|
||||
target.render(ops, Some(&Color::SOLID_BLACK));
|
||||
target.render(ops, Some(&Color::SOLID_BLACK))
|
||||
}
|
||||
|
||||
fn have_hardware_cursor(&self) -> bool {
|
||||
|
|
@ -854,7 +856,7 @@ impl State {
|
|||
stride: i32,
|
||||
format: &'static Format,
|
||||
transform: Transform,
|
||||
) {
|
||||
) -> Result<(), ShmScreencopyError> {
|
||||
let (src_width, src_height) = src.size();
|
||||
let mut needs_copy = capture.rect.x1() < x_off
|
||||
|| capture.rect.x2() > x_off + src_width
|
||||
|
|
@ -869,20 +871,11 @@ impl State {
|
|||
}
|
||||
let acc = if needs_copy {
|
||||
let Some(ctx) = self.render_ctx.get() else {
|
||||
log::warn!("Cannot perform shm screencopy because there is no render context");
|
||||
return;
|
||||
return Err(ShmScreencopyError::NoRenderContext);
|
||||
};
|
||||
let fb =
|
||||
match ctx.create_fb(capture.rect.width(), capture.rect.height(), stride, format) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
"Could not create temporary fb for screencopy: {}",
|
||||
ErrorFmt(e)
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let fb = ctx
|
||||
.create_fb(capture.rect.width(), capture.rect.height(), stride, format)
|
||||
.map_err(ShmScreencopyError::CreateTemporaryFb)?;
|
||||
self.perform_screencopy(
|
||||
src,
|
||||
&fb,
|
||||
|
|
@ -892,7 +885,8 @@ impl State {
|
|||
y_off - capture.rect.y1(),
|
||||
size,
|
||||
transform,
|
||||
);
|
||||
)
|
||||
.map_err(ShmScreencopyError::CopyToTemporary)?;
|
||||
mem.access(|mem| {
|
||||
fb.copy_to_shm(
|
||||
0,
|
||||
|
|
@ -917,16 +911,12 @@ impl State {
|
|||
)
|
||||
})
|
||||
};
|
||||
let res = match acc {
|
||||
Ok(res) => res,
|
||||
match acc {
|
||||
Ok(res) => res.map_err(ShmScreencopyError::ReadPixels),
|
||||
Err(e) => {
|
||||
capture.client.error(e);
|
||||
return;
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
if let Err(e) = res {
|
||||
log::warn!("Could not read texture to memory: {}", ErrorFmt(e));
|
||||
capture.send_failed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -937,3 +927,15 @@ impl State {
|
|||
seat
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ShmScreencopyError {
|
||||
#[error("There is no render context")]
|
||||
NoRenderContext,
|
||||
#[error("Could not create a bridge framebuffer")]
|
||||
CreateTemporaryFb(#[source] GfxError),
|
||||
#[error("Could not copy texture to bridge framebuffer")]
|
||||
CopyToTemporary(#[source] GfxError),
|
||||
#[error("Could not read pixels from texture")]
|
||||
ReadPixels(#[source] GfxError),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue