Merge pull request #482 from Smithay/feature/gbm_generics

gbm: Allow usage of other allocators for GbmBufferedSurface
This commit is contained in:
Victoria Brekenfeld 2022-01-26 20:41:44 +01:00 committed by GitHub
commit 7c886e05d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 27 deletions

View File

@ -264,7 +264,7 @@ pub fn run_udev(log: Logger) {
event_loop.handle().remove(udev_event_source); event_loop.handle().remove(udev_event_source);
} }
pub type RenderSurface = GbmBufferedSurface<SessionFd>; pub type RenderSurface = GbmBufferedSurface<Rc<RefCell<GbmDevice<SessionFd>>>, SessionFd>;
struct SurfaceData { struct SurfaceData {
surface: RenderSurface, surface: RenderSurface,
@ -279,7 +279,7 @@ struct BackendData {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
fps_texture: Gles2Texture, fps_texture: Gles2Texture,
renderer: Rc<RefCell<Gles2Renderer>>, renderer: Rc<RefCell<Gles2Renderer>>,
gbm: GbmDevice<SessionFd>, gbm: Rc<RefCell<GbmDevice<SessionFd>>>,
registration_token: RegistrationToken, registration_token: RegistrationToken,
event_dispatcher: Dispatcher<'static, DrmDevice<SessionFd>, AnvilState<UdevData>>, event_dispatcher: Dispatcher<'static, DrmDevice<SessionFd>, AnvilState<UdevData>>,
dev_id: u64, dev_id: u64,
@ -287,7 +287,7 @@ struct BackendData {
fn scan_connectors( fn scan_connectors(
device: &mut DrmDevice<SessionFd>, device: &mut DrmDevice<SessionFd>,
gbm: &GbmDevice<SessionFd>, gbm: &Rc<RefCell<GbmDevice<SessionFd>>>,
renderer: &mut Gles2Renderer, renderer: &mut Gles2Renderer,
output_map: &mut crate::output_map::OutputMap, output_map: &mut crate::output_map::OutputMap,
signaler: &Signaler<SessionSignal>, signaler: &Signaler<SessionSignal>,
@ -483,6 +483,7 @@ impl AnvilState<UdevData> {
} }
} }
let gbm = Rc::new(RefCell::new(gbm));
let backends = Rc::new(RefCell::new(scan_connectors( let backends = Rc::new(RefCell::new(scan_connectors(
&mut device, &mut device,
&gbm, &gbm,

View File

@ -4,12 +4,12 @@ use std::sync::Arc;
use drm::buffer::PlanarBuffer; use drm::buffer::PlanarBuffer;
use drm::control::{connector, crtc, framebuffer, plane, Device, Mode}; use drm::control::{connector, crtc, framebuffer, plane, Device, Mode};
use gbm::{BufferObject, Device as GbmDevice}; use gbm::BufferObject;
use crate::backend::allocator::{ use crate::backend::allocator::{
dmabuf::{AsDmabuf, Dmabuf}, dmabuf::{AsDmabuf, Dmabuf},
gbm::GbmConvertError, gbm::GbmConvertError,
Format, Fourcc, Modifier, Slot, Swapchain, Allocator, Format, Fourcc, Modifier, Slot, Swapchain,
}; };
use crate::backend::drm::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface}; use crate::backend::drm::{device::DevPath, surface::DrmSurfaceInternal, DrmError, DrmSurface};
use crate::backend::SwapBuffersError; use crate::backend::SwapBuffersError;
@ -18,17 +18,19 @@ 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)] #[derive(Debug)]
pub struct GbmBufferedSurface<D: AsRawFd + 'static> { pub struct GbmBufferedSurface<A: Allocator<BufferObject<()>> + 'static, D: AsRawFd + 'static> {
current_fb: Slot<BufferObject<()>>, current_fb: Slot<BufferObject<()>>,
pending_fb: Option<Slot<BufferObject<()>>>, pending_fb: Option<Slot<BufferObject<()>>>,
queued_fb: Option<Slot<BufferObject<()>>>, queued_fb: Option<Slot<BufferObject<()>>>,
next_fb: Option<Slot<BufferObject<()>>>, next_fb: Option<Slot<BufferObject<()>>>,
swapchain: Swapchain<GbmDevice<D>, BufferObject<()>>, swapchain: Swapchain<A, BufferObject<()>>,
drm: Arc<DrmSurface<D>>, drm: Arc<DrmSurface<D>>,
} }
impl<D> GbmBufferedSurface<D> impl<A, D> GbmBufferedSurface<A, D>
where where
A: Allocator<BufferObject<()>>,
A::Error: std::error::Error + Send + Sync,
D: AsRawFd + 'static, D: AsRawFd + 'static,
{ {
/// Create a new `GbmBufferedSurface` from a given compatible combination /// Create a new `GbmBufferedSurface` from a given compatible combination
@ -40,10 +42,10 @@ where
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn new<L>( pub fn new<L>(
drm: DrmSurface<D>, drm: DrmSurface<D>,
allocator: GbmDevice<D>, allocator: A,
mut renderer_formats: HashSet<Format>, mut renderer_formats: HashSet<Format>,
log: L, log: L,
) -> Result<GbmBufferedSurface<D>, Error> ) -> Result<GbmBufferedSurface<A, D>, Error<A::Error>>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -121,7 +123,7 @@ where
let mode = drm.pending_mode(); let mode = drm.pending_mode();
let mut swapchain: Swapchain<GbmDevice<D>, BufferObject<()>> = Swapchain::new( let mut swapchain: Swapchain<A, BufferObject<()>> = Swapchain::new(
allocator, allocator,
mode.size().0 as u32, mode.size().0 as u32,
mode.size().1 as u32, mode.size().1 as u32,
@ -130,7 +132,7 @@ where
); );
// Test format // Test format
let buffer = swapchain.acquire()?.unwrap(); let buffer = swapchain.acquire().map_err(Error::GbmError)?.unwrap();
let format = Format { let format = Format {
code, code,
modifier: buffer.modifier().unwrap(), // no guarantee modifier: buffer.modifier().unwrap(), // no guarantee
@ -171,9 +173,13 @@ 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, u8), Error> { pub fn next_buffer(&mut self) -> Result<(Dmabuf, u8), Error<A::Error>> {
if self.next_fb.is_none() { if self.next_fb.is_none() {
let slot = self.swapchain.acquire()?.ok_or(Error::NoFreeSlotsError)?; let slot = self
.swapchain
.acquire()
.map_err(Error::GbmError)?
.ok_or(Error::NoFreeSlotsError)?;
let maybe_buffer = slot.userdata().get::<Dmabuf>().cloned(); let maybe_buffer = slot.userdata().get::<Dmabuf>().cloned();
if maybe_buffer.is_none() { if maybe_buffer.is_none() {
@ -197,7 +203,7 @@ where
/// *Note*: This function needs to be followed up with [`GbmBufferedSurface::frame_submitted`] /// *Note*: This function needs to be followed up with [`GbmBufferedSurface::frame_submitted`]
/// 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<A::Error>> {
self.queued_fb = self.next_fb.take(); self.queued_fb = self.next_fb.take();
if self.pending_fb.is_none() && self.queued_fb.is_some() { if self.pending_fb.is_none() && self.queued_fb.is_some() {
self.submit()?; self.submit()?;
@ -210,7 +216,7 @@ where
/// *Note*: Needs to be called, after the vblank event of the matching [`DrmDevice`](super::super::DrmDevice) /// *Note*: Needs to be called, after the vblank event of the matching [`DrmDevice`](super::super::DrmDevice)
/// 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<A::Error>> {
if let Some(mut pending) = self.pending_fb.take() { if let Some(mut pending) = self.pending_fb.take() {
std::mem::swap(&mut pending, &mut self.current_fb); std::mem::swap(&mut pending, &mut self.current_fb);
if self.queued_fb.is_some() { if self.queued_fb.is_some() {
@ -221,7 +227,7 @@ where
Ok(()) Ok(())
} }
fn submit(&mut self) -> Result<(), Error> { fn submit(&mut self) -> Result<(), Error<A::Error>> {
// yes it does not look like it, but both of these lines should be safe in all cases. // 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 slot = self.queued_fb.take().unwrap();
let fb = slot.userdata().get::<FbHandle<D>>().unwrap().fb; let fb = slot.userdata().get::<FbHandle<D>>().unwrap().fb;
@ -276,13 +282,13 @@ where
/// (e.g. no suitable [`encoder`](drm::control::encoder) may be found) /// (e.g. no suitable [`encoder`](drm::control::encoder) may be found)
/// or is not compatible with the currently pending /// or is not compatible with the currently pending
/// [`Mode`](drm::control::Mode). /// [`Mode`](drm::control::Mode).
pub fn add_connector(&self, connector: connector::Handle) -> Result<(), Error> { pub fn add_connector(&self, connector: connector::Handle) -> Result<(), Error<A::Error>> {
self.drm.add_connector(connector).map_err(Error::DrmError) self.drm.add_connector(connector).map_err(Error::DrmError)
} }
/// Tries to mark a [`connector`](drm::control::connector) /// Tries to mark a [`connector`](drm::control::connector)
/// for removal on the next commit. /// for removal on the next commit.
pub fn remove_connector(&self, connector: connector::Handle) -> Result<(), Error> { pub fn remove_connector(&self, connector: connector::Handle) -> Result<(), Error<A::Error>> {
self.drm.remove_connector(connector).map_err(Error::DrmError) self.drm.remove_connector(connector).map_err(Error::DrmError)
} }
@ -292,7 +298,7 @@ where
/// (e.g. no suitable [`encoder`](drm::control::encoder) may be found) /// (e.g. no suitable [`encoder`](drm::control::encoder) may be found)
/// or is not compatible with the currently pending /// or is not compatible with the currently pending
/// [`Mode`](drm::control::Mode). /// [`Mode`](drm::control::Mode).
pub fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Error> { pub fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Error<A::Error>> {
self.drm.set_connectors(connectors).map_err(Error::DrmError) self.drm.set_connectors(connectors).map_err(Error::DrmError)
} }
@ -314,7 +320,7 @@ where
/// Fails if the mode is not compatible with the underlying /// Fails if the mode is not compatible with the underlying
/// [`crtc`](drm::control::crtc) or any of the /// [`crtc`](drm::control::crtc) or any of the
/// pending [`connector`](drm::control::connector)s. /// pending [`connector`](drm::control::connector)s.
pub fn use_mode(&mut self, mode: Mode) -> Result<(), Error> { pub fn use_mode(&mut self, mode: Mode) -> Result<(), Error<A::Error>> {
self.drm.use_mode(mode).map_err(Error::DrmError)?; self.drm.use_mode(mode).map_err(Error::DrmError)?;
let (w, h) = mode.size(); let (w, h) = mode.size();
self.swapchain.resize(w as _, h as _); self.swapchain.resize(w as _, h as _);
@ -334,9 +340,10 @@ impl<A: AsRawFd + 'static> Drop for FbHandle<A> {
} }
} }
fn attach_framebuffer<A>(drm: &Arc<DrmSurface<A>>, bo: &BufferObject<()>) -> Result<FbHandle<A>, Error> fn attach_framebuffer<E, D>(drm: &Arc<DrmSurface<D>>, bo: &BufferObject<()>) -> Result<FbHandle<D>, Error<E>>
where where
A: AsRawFd + 'static, E: std::error::Error + Send + Sync,
D: AsRawFd + 'static,
{ {
let modifier = match bo.modifier().unwrap() { let modifier = match bo.modifier().unwrap() {
Modifier::Invalid => None, Modifier::Invalid => None,
@ -385,7 +392,7 @@ where
/// Errors thrown by a [`GbmBufferedSurface`] /// Errors thrown by a [`GbmBufferedSurface`]
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error<E: std::error::Error + Send + Sync + 'static> {
/// No supported pixel format for the given plane could be determined /// No supported pixel format for the given plane could be determined
#[error("No supported plane buffer format found")] #[error("No supported plane buffer format found")]
NoSupportedPlaneFormat, NoSupportedPlaneFormat,
@ -406,14 +413,14 @@ pub enum Error {
DrmError(#[from] DrmError), DrmError(#[from] DrmError),
/// Error importing the rendered buffer to libgbm for scan-out /// Error importing the rendered buffer to libgbm for scan-out
#[error("The underlying gbm device encounted an error: {0}")] #[error("The underlying gbm device encounted an error: {0}")]
GbmError(#[from] std::io::Error), GbmError(#[source] E),
/// Error exporting as Dmabuf /// Error exporting as Dmabuf
#[error("The allocated buffer could not be exported as a dmabuf: {0}")] #[error("The allocated buffer could not be exported as a dmabuf: {0}")]
AsDmabufError(#[from] GbmConvertError), AsDmabufError(#[from] GbmConvertError),
} }
impl From<Error> for SwapBuffersError { impl<E: std::error::Error + Send + Sync + 'static> From<Error<E>> for SwapBuffersError {
fn from(err: Error) -> SwapBuffersError { fn from(err: Error<E>) -> SwapBuffersError {
match err { match err {
x @ Error::NoSupportedPlaneFormat x @ Error::NoSupportedPlaneFormat
| x @ Error::NoSupportedRendererFormat | x @ Error::NoSupportedRendererFormat