From 485aa2a9c78202fa4ae0374dea90a2588fff97b4 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 28 Nov 2021 01:17:38 +0100 Subject: [PATCH 1/2] swapchain: Do not increase the age of 0-age slots Slots with an age of 0 were never rendered to. This means we should not increase their age, when others are submitted or the renderer might wrongfully assume usuable contents are available in the buffer. --- src/backend/allocator/swapchain.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/backend/allocator/swapchain.rs b/src/backend/allocator/swapchain.rs index 204141a..0603cc9 100644 --- a/src/backend/allocator/swapchain.rs +++ b/src/backend/allocator/swapchain.rs @@ -166,8 +166,17 @@ where slot.0.age.store(1, Ordering::SeqCst); for other_slot in &self.slots { - if !Arc::ptr_eq(other_slot, &slot.0) { - other_slot.age.fetch_add(1, Ordering::SeqCst); + if !Arc::ptr_eq(other_slot, &slot.0) && other_slot.buffer.is_some() { + assert!(other_slot + .age + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |age| { + if age > 0 { + Some(age + 1) + } else { + Some(0) + } + }) + .is_ok()); } } } From bd305dc7ee99a9c212daeb650a1999a53f800059 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 28 Nov 2021 01:14:17 +0100 Subject: [PATCH 2/2] x11: fixup buffer age The current code always acquires the buffer it just submitted, which results in always rendering to a buffer with age "1", although its contents are older, because the currently held buffer is already submitted, just not to the swapchain. When it finally is submitted its age is again set to 1, the other gets its correct age (but too late) and the circle is repeated again. So lets fix that. --- anvil/src/x11.rs | 4 +++- src/backend/x11/mod.rs | 38 ++++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/anvil/src/x11.rs b/anvil/src/x11.rs index a595173..567eb1c 100644 --- a/anvil/src/x11.rs +++ b/anvil/src/x11.rs @@ -306,7 +306,9 @@ pub fn run_x11(log: Logger) { } // Submit the buffer - backend_data.surface.submit(); + if let Err(err) = backend_data.surface.submit() { + error!(log, "Error submitting buffer for display: {}", err); + } } Err(err) => { diff --git a/src/backend/x11/mod.rs b/src/backend/x11/mod.rs index 6329961..6c13096 100644 --- a/src/backend/x11/mod.rs +++ b/src/backend/x11/mod.rs @@ -349,8 +349,7 @@ pub struct X11Surface { format: DrmFourcc, width: u16, height: u16, - current: Option>>, - next: Option>>, + buffer: Option>>, } #[derive(Debug, thiserror::Error)] @@ -467,8 +466,7 @@ impl X11Surface { format, width: size.w, height: size.h, - current: None, - next: None, + buffer: None, resize: recv, }) } @@ -493,8 +491,8 @@ impl X11Surface { self.resize(new_size)?; } - if self.next.is_none() { - self.next = Some( + if self.buffer.is_none() { + self.buffer = Some( self.swapchain .acquire() .map_err(Into::::into)? @@ -502,7 +500,7 @@ impl X11Surface { ); } - let slot = self.next.as_ref().unwrap(); + let slot = self.buffer.as_ref().unwrap(); let age = slot.age(); match slot.userdata().get::() { Some(dmabuf) => Ok((dmabuf.clone(), age)), @@ -515,41 +513,45 @@ impl X11Surface { } /// Consume and submit the buffer to the window. - pub fn submit(&mut self) { + pub fn submit(&mut self) -> Result<(), AllocateBuffersError> { if let Some(connection) = self.connection.upgrade() { + // Get a new buffer + let mut next = self + .swapchain + .acquire() + .map_err(Into::::into)? + .ok_or(AllocateBuffersError::NoFreeSlots)?; + // Swap the buffers - if let Some(mut next) = self.next.take() { - if let Some(current) = self.current.as_mut() { - mem::swap(&mut next, current); - self.swapchain.submitted(next); - } else { - self.current = Some(next); - } + if let Some(current) = self.buffer.as_mut() { + mem::swap(&mut next, current); } if let Ok(pixmap) = PixmapWrapper::with_dmabuf( &*connection, &self.window, - self.current.as_ref().unwrap().userdata().get::().unwrap(), + next.userdata().get::().unwrap(), ) { // Now present the current buffer let _ = pixmap.present(&*connection, &self.window); } + self.swapchain.submitted(next); // Flush the connection after presenting to the window to ensure we don't run out of buffer space in the X11 connection. let _ = connection.flush(); } + Ok(()) } /// Resets the internal buffers, e.g. to reset age values pub fn reset_buffers(&mut self) { self.swapchain.reset_buffers(); - self.next = None; + self.buffer = None; } fn resize(&mut self, size: Size) -> Result<(), AllocateBuffersError> { self.swapchain.resize(size.w as u32, size.h as u32); - self.next = None; + self.buffer = None; self.width = size.w; self.height = size.h;