gbm: Refactor: remove internal `Buffers` struct
This commit is contained in:
parent
9584219ffa
commit
643ff5395d
|
@ -17,22 +17,16 @@ use crate::backend::SwapBuffersError;
|
||||||
use slog::{debug, error, o, trace, warn};
|
use slog::{debug, error, o, trace, warn};
|
||||||
|
|
||||||
/// Simplified abstraction of a swapchain for gbm-buffers displayed on a [`DrmSurface`].
|
/// Simplified abstraction of a swapchain for gbm-buffers displayed on a [`DrmSurface`].
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct GbmBufferedSurface<D: AsRawFd + 'static> {
|
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<()>>,
|
swapchain: Swapchain<GbmDevice<D>, BufferObject<()>>,
|
||||||
drm: Arc<DrmSurface<D>>,
|
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>
|
impl<D> GbmBufferedSurface<D>
|
||||||
where
|
where
|
||||||
D: AsRawFd + 'static,
|
D: AsRawFd + 'static,
|
||||||
|
@ -154,9 +148,11 @@ where
|
||||||
match drm.test_buffer(handle, &mode, true) {
|
match drm.test_buffer(handle, &mode, true) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
debug!(logger, "Choosen format: {:?}", format);
|
debug!(logger, "Choosen format: {:?}", format);
|
||||||
let buffers = Buffers::new(drm.clone(), buffer);
|
|
||||||
Ok(GbmBufferedSurface {
|
Ok(GbmBufferedSurface {
|
||||||
buffers,
|
current_fb: buffer,
|
||||||
|
pending_fb: None,
|
||||||
|
queued_fb: None,
|
||||||
|
next_fb: None,
|
||||||
swapchain,
|
swapchain,
|
||||||
drm,
|
drm,
|
||||||
})
|
})
|
||||||
|
@ -176,7 +172,24 @@ where
|
||||||
/// *Note*: This function can be called multiple times and
|
/// *Note*: This function can be called multiple times and
|
||||||
/// will return the same buffer until it is queued (see [`GbmBufferedSurface::queue_buffer`]).
|
/// will return the same buffer until it is queued (see [`GbmBufferedSurface::queue_buffer`]).
|
||||||
pub fn next_buffer(&mut self) -> Result<Dmabuf, Error> {
|
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.
|
/// Queues the current buffer for rendering.
|
||||||
|
@ -185,7 +198,11 @@ where
|
||||||
/// when a vblank event is received, that denotes successful scanout of the buffer.
|
/// when a vblank event is received, that denotes successful scanout of the buffer.
|
||||||
/// Otherwise the underlying swapchain will eventually run out of buffers.
|
/// Otherwise the underlying swapchain will eventually run out of buffers.
|
||||||
pub fn queue_buffer(&mut self) -> Result<(), Error> {
|
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.
|
/// Marks the current frame as submitted.
|
||||||
|
@ -194,7 +211,30 @@ where
|
||||||
/// was received after calling [`GbmBufferedSurface::queue_buffer`] on this surface.
|
/// was received after calling [`GbmBufferedSurface::queue_buffer`] on this surface.
|
||||||
/// Otherwise the underlying swapchain will run out of buffers eventually.
|
/// Otherwise the underlying swapchain will run out of buffers eventually.
|
||||||
pub fn frame_submitted(&mut self) -> Result<(), Error> {
|
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
|
/// 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>
|
fn attach_framebuffer<A>(drm: &Arc<DrmSurface<A>>, bo: &BufferObject<()>) -> Result<FbHandle<A>, Error>
|
||||||
where
|
where
|
||||||
A: AsRawFd + 'static,
|
A: AsRawFd + 'static,
|
||||||
|
|
Loading…
Reference in New Issue