gbm: Refactor: remove internal `Buffers` struct

This commit is contained in:
Victor Brekenfeld 2021-11-23 17:18:28 +01:00
parent 9584219ffa
commit 643ff5395d
1 changed files with 56 additions and 109 deletions

View File

@ -17,22 +17,16 @@ use crate::backend::SwapBuffersError;
use slog::{debug, error, o, trace, warn};
/// Simplified abstraction of a swapchain for gbm-buffers displayed on a [`DrmSurface`].
#[derive(Debug)]
pub struct GbmBufferedSurface<D: AsRawFd + 'static> {
buffers: Buffers<D>,
current_fb: Slot<BufferObject<()>>,
pending_fb: Option<Slot<BufferObject<()>>>,
queued_fb: Option<Slot<BufferObject<()>>>,
next_fb: Option<Slot<BufferObject<()>>>,
swapchain: Swapchain<GbmDevice<D>, BufferObject<()>>,
drm: Arc<DrmSurface<D>>,
}
// TODO: Replace with #[derive(Debug)] once gbm::BufferObject implements debug
impl<D: std::fmt::Debug + AsRawFd + 'static> std::fmt::Debug for GbmBufferedSurface<D> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GbmBufferedSurface")
.field("buffers", &self.buffers)
.field("drm", &self.drm)
.finish_non_exhaustive()
}
}
impl<D> GbmBufferedSurface<D>
where
D: AsRawFd + 'static,
@ -154,9 +148,11 @@ where
match drm.test_buffer(handle, &mode, true) {
Ok(_) => {
debug!(logger, "Choosen format: {:?}", format);
let buffers = Buffers::new(drm.clone(), buffer);
Ok(GbmBufferedSurface {
buffers,
current_fb: buffer,
pending_fb: None,
queued_fb: None,
next_fb: None,
swapchain,
drm,
})
@ -176,7 +172,24 @@ where
/// *Note*: This function can be called multiple times and
/// will return the same buffer until it is queued (see [`GbmBufferedSurface::queue_buffer`]).
pub fn next_buffer(&mut self) -> Result<Dmabuf, Error> {
self.buffers.next(&mut self.swapchain)
if self.next_fb.is_none() {
let slot = self.swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?;
let maybe_buffer = slot.userdata().get::<Dmabuf>().cloned();
if maybe_buffer.is_none() {
let dmabuf = slot.export().map_err(Error::AsDmabufError)?;
let fb_handle = attach_framebuffer(&self.drm, &*slot)?;
let userdata = slot.userdata();
userdata.insert_if_missing(|| dmabuf);
userdata.insert_if_missing(|| fb_handle);
}
self.next_fb = Some(slot);
}
let slot = self.next_fb.as_ref().unwrap();
Ok(slot.userdata().get::<Dmabuf>().unwrap().clone())
}
/// Queues the current buffer for rendering.
@ -185,7 +198,11 @@ where
/// when a vblank event is received, that denotes successful scanout of the buffer.
/// Otherwise the underlying swapchain will eventually run out of buffers.
pub fn queue_buffer(&mut self) -> Result<(), Error> {
self.buffers.queue()
self.queued_fb = self.next_fb.take();
if self.pending_fb.is_none() && self.queued_fb.is_some() {
self.submit()?;
}
Ok(())
}
/// Marks the current frame as submitted.
@ -194,7 +211,30 @@ where
/// was received after calling [`GbmBufferedSurface::queue_buffer`] on this surface.
/// Otherwise the underlying swapchain will run out of buffers eventually.
pub fn frame_submitted(&mut self) -> Result<(), Error> {
self.buffers.submitted()
if let Some(mut pending) = self.pending_fb.take() {
std::mem::swap(&mut pending, &mut self.current_fb);
if self.queued_fb.is_some() {
self.submit()?;
}
}
Ok(())
}
fn submit(&mut self) -> Result<(), Error> {
// yes it does not look like it, but both of these lines should be safe in all cases.
let slot = self.queued_fb.take().unwrap();
let fb = slot.userdata().get::<FbHandle<D>>().unwrap().fb;
let flip = if self.drm.commit_pending() {
self.drm.commit([(fb, self.drm.plane())].iter(), true)
} else {
self.drm.page_flip([(fb, self.drm.plane())].iter(), true)
};
if flip.is_ok() {
self.pending_fb = Some(slot);
}
flip.map_err(Error::DrmError)
}
/// Returns the underlying [`crtc`](drm::control::crtc) of this surface
@ -285,99 +325,6 @@ impl<A: AsRawFd + 'static> Drop for FbHandle<A> {
}
}
struct Buffers<D: AsRawFd + 'static> {
drm: Arc<DrmSurface<D>>,
_current_fb: Slot<BufferObject<()>>,
pending_fb: Option<Slot<BufferObject<()>>>,
queued_fb: Option<Slot<BufferObject<()>>>,
next_fb: Option<Slot<BufferObject<()>>>,
}
// TODO: Replace with #[derive(Debug)] once gbm::BufferObject implements debug
impl<D: std::fmt::Debug + AsRawFd + 'static> std::fmt::Debug for Buffers<D> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Buffers")
.field("drm", &self.drm)
.finish_non_exhaustive()
}
}
impl<D> Buffers<D>
where
D: AsRawFd + 'static,
{
pub fn new(drm: Arc<DrmSurface<D>>, slot: Slot<BufferObject<()>>) -> Buffers<D> {
Buffers {
drm,
_current_fb: slot,
pending_fb: None,
queued_fb: None,
next_fb: None,
}
}
pub fn next(
&mut self,
swapchain: &mut Swapchain<GbmDevice<D>, BufferObject<()>>,
) -> Result<Dmabuf, Error> {
if self.next_fb.is_none() {
let slot = swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?;
let maybe_buffer = slot.userdata().get::<Dmabuf>().clone();
if maybe_buffer.is_none() {
let dmabuf = slot.export().map_err(Error::AsDmabufError)?;
let fb_handle = attach_framebuffer(&self.drm, &*slot)?;
let userdata = slot.userdata();
userdata.insert_if_missing(|| dmabuf);
userdata.insert_if_missing(|| fb_handle);
}
self.next_fb = Some(slot);
}
let slot = self.next_fb.as_ref().unwrap();
Ok(slot.userdata().get::<Dmabuf>().unwrap().clone())
}
pub fn queue(&mut self) -> Result<(), Error> {
self.queued_fb = self.next_fb.take();
if self.pending_fb.is_none() && self.queued_fb.is_some() {
self.submit()
} else {
Ok(())
}
}
pub fn submitted(&mut self) -> Result<(), Error> {
if self.pending_fb.is_none() {
return Ok(());
}
self._current_fb = self.pending_fb.take().unwrap();
if self.queued_fb.is_some() {
self.submit()
} else {
Ok(())
}
}
fn submit(&mut self) -> Result<(), Error> {
// yes it does not look like it, but both of these lines should be safe in all cases.
let slot = self.queued_fb.take().unwrap();
let fb = slot.userdata().get::<FbHandle<D>>().unwrap().fb;
let flip = if self.drm.commit_pending() {
self.drm.commit([(fb, self.drm.plane())].iter(), true)
} else {
self.drm.page_flip([(fb, self.drm.plane())].iter(), true)
};
if flip.is_ok() {
self.pending_fb = Some(slot);
}
flip.map_err(Error::DrmError)
}
}
fn attach_framebuffer<A>(drm: &Arc<DrmSurface<A>>, bo: &BufferObject<()>) -> Result<FbHandle<A>, Error>
where
A: AsRawFd + 'static,