allocator/gbm: Allow customizing usage flags

This commit is contained in:
Victoria Brekenfeld 2023-02-08 17:42:14 +01:00
parent d2b7e33af4
commit cc3ba5aefc
7 changed files with 136 additions and 31 deletions

View file

@ -81,6 +81,7 @@ backend_x11 = ["x11rb", "x11rb/dri3", "x11rb/xfixes", "x11rb/present", "x11rb_ev
backend_drm = ["drm", "drm-ffi"]
backend_gbm = ["gbm", "cc", "pkg-config"]
backend_gbm_has_fd_for_plane = []
backend_gbm_has_create_with_modifiers2 = []
backend_egl = ["gl_generator", "libloading"]
backend_libinput = ["input"]
backend_session = []

View file

@ -33,6 +33,7 @@ use smithay::{
};
use smithay::{
backend::{
allocator::gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
drm::{
DrmDevice, DrmDeviceFd, DrmError, DrmEvent, DrmEventMetadata, DrmNode, GbmBufferedSurface,
NodeType,
@ -70,7 +71,6 @@ use smithay::{
Device as ControlDevice,
},
},
gbm::Device as GbmDevice,
input::Libinput,
nix::{fcntl::OFlag, sys::stat::dev_t},
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback,
@ -366,7 +366,7 @@ pub fn run_udev(log: Logger) {
}
}
pub type RenderSurface = GbmBufferedSurface<GbmDevice<DrmDeviceFd>, Option<OutputPresentationFeedback>>;
pub type RenderSurface = GbmBufferedSurface<GbmAllocator<DrmDeviceFd>, Option<OutputPresentationFeedback>>;
struct SurfaceData {
dh: DisplayHandle,
@ -469,8 +469,12 @@ fn scan_connectors(
}
};
let gbm_surface =
match GbmBufferedSurface::new(surface, gbm.clone(), formats.clone(), logger.clone()) {
let gbm_surface = match GbmBufferedSurface::new(
surface,
GbmAllocator::new(gbm.clone(), GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT),
formats.clone(),
logger.clone(),
) {
Ok(renderer) => renderer,
Err(err) => {
warn!(logger, "Failed to create rendering surface: {}", err);

View file

@ -16,7 +16,10 @@ use smithay::backend::renderer::ImportMem;
#[cfg(feature = "egl")]
use smithay::{
backend::{
allocator::dmabuf::Dmabuf,
allocator::{
dmabuf::Dmabuf,
gbm::{GbmAllocator, GbmBufferFlags},
},
renderer::{ImportDma, ImportEgl},
},
delegate_dmabuf,
@ -112,7 +115,7 @@ pub fn run_x11(log: Logger) {
let surface = handle
.create_surface(
&window,
device,
GbmAllocator::new(device, GbmBufferFlags::RENDERING),
context
.dmabuf_render_formats()
.iter()

View file

@ -89,10 +89,42 @@ fn test_gbm_bo_fd_for_plane() {
}
}
#[cfg(all(
feature = "backend_gbm",
not(feature = "backend_gbm_has_create_with_modifiers2")
))]
fn test_gbm_bo_create_with_modifiers2() {
let gbm = match pkg_config::probe_library("gbm") {
Ok(lib) => lib,
Err(_) => {
println!(
"cargo:warning=failed to find gbm, assuming gbm_bo_create_with_modifiers2 is unavailable"
);
return;
}
};
let has_gbm_bo_create_with_modifiers2 = cc::Build::new()
.file("test_gbm_bo_create_with_modifiers2.c")
.includes(gbm.include_paths)
.warnings_into_errors(true)
.try_compile("test_gbm_bo_create_with_modifiers2")
.is_ok();
if has_gbm_bo_create_with_modifiers2 {
println!("cargo:rustc-cfg=feature=\"backend_gbm_has_create_with_modifiers2\"");
}
}
fn main() {
#[cfg(any(feature = "backend_egl", feature = "renderer_gl"))]
gl_generate();
#[cfg(all(feature = "backend_gbm", not(feature = "backend_gbm_has_fd_for_plane")))]
test_gbm_bo_fd_for_plane();
#[cfg(all(
feature = "backend_gbm",
not(feature = "backend_gbm_has_create_with_modifiers2")
))]
test_gbm_bo_create_with_modifiers2();
}

View file

@ -10,9 +10,82 @@ use super::{
};
use crate::utils::{Buffer as BufferCoords, Size};
pub use gbm::{BufferObject as GbmBuffer, BufferObjectFlags as GbmBufferFlags, Device as GbmDevice};
use std::os::unix::io::{AsFd, AsRawFd};
use std::{
convert::{AsMut, AsRef},
os::unix::io::{AsFd, AsRawFd, BorrowedFd},
};
impl<A: AsFd + 'static> Allocator for GbmDevice<A> {
/// Light wrapper around an [`GbmDevice`] to implement the [`Allocator`]-trait
#[derive(Debug, Clone)]
pub struct GbmAllocator<A: AsFd + 'static> {
device: GbmDevice<A>,
default_flags: GbmBufferFlags,
}
impl<A: AsFd + 'static> AsRef<GbmDevice<A>> for GbmAllocator<A> {
fn as_ref(&self) -> &GbmDevice<A> {
&self.device
}
}
impl<A: AsFd + 'static> AsMut<GbmDevice<A>> for GbmAllocator<A> {
fn as_mut(&mut self) -> &mut GbmDevice<A> {
&mut self.device
}
}
impl<A: AsFd + 'static> AsFd for GbmAllocator<A> {
fn as_fd(&self) -> BorrowedFd<'_> {
self.device.as_fd()
}
}
impl<A: AsFd + 'static> GbmAllocator<A> {
/// Create a new [`GbmAllocator`] from a [`GbmDevice`] with some default usage flags,
/// to be used when [`Allocator::create_buffer`] is invoked.
pub fn new(device: GbmDevice<A>, default_flags: GbmBufferFlags) -> GbmAllocator<A> {
GbmAllocator {
device,
default_flags,
}
}
/// Alternative to [`Allocator::create_buffer`], if you need a one-off buffer with
/// a different set of usage flags.
fn create_buffer_with_flags(
&mut self,
width: u32,
height: u32,
fourcc: Fourcc,
modifiers: &[Modifier],
flags: GbmBufferFlags,
) -> Result<GbmBuffer<()>, std::io::Error> {
#[cfg(feature = "backend_gbm_has_create_with_modifiers2")]
let result = self.device.create_buffer_object_with_modifiers2(
width,
height,
fourcc,
modifiers.iter().copied(),
flags,
);
#[cfg(not(feature = "backend_gbm_has_create_with_modifiers2"))]
let result =
self.create_buffer_object_with_modifiers(width, height, fourcc, modifiers.iter().copied());
match result {
Ok(bo) => Ok(bo),
Err(err) => {
if modifiers.contains(&Modifier::Invalid) || modifiers.contains(&Modifier::Linear) {
self.device.create_buffer_object(width, height, fourcc, flags)
} else {
Err(err)
}
}
}
}
}
impl<A: AsFd + 'static> Allocator for GbmAllocator<A> {
type Buffer = GbmBuffer<()>;
type Error = std::io::Error;
@ -23,20 +96,7 @@ impl<A: AsFd + 'static> Allocator for GbmDevice<A> {
fourcc: Fourcc,
modifiers: &[Modifier],
) -> Result<GbmBuffer<()>, Self::Error> {
match self.create_buffer_object_with_modifiers(width, height, fourcc, modifiers.iter().copied()) {
Ok(bo) => Ok(bo),
Err(err) => {
if modifiers.contains(&Modifier::Invalid) || modifiers.contains(&Modifier::Linear) {
let mut usage = GbmBufferFlags::SCANOUT | GbmBufferFlags::RENDERING;
if !modifiers.contains(&Modifier::Invalid) {
usage |= GbmBufferFlags::LINEAR;
}
self.create_buffer_object(width, height, fourcc, usage)
} else {
Err(err)
}
}
}
self.create_buffer_with_flags(width, height, fourcc, modifiers, self.default_flags)
}
}

View file

@ -14,8 +14,8 @@
//! ```rust,no_run
//! # use std::{sync::{Arc, Mutex}, error::Error};
//! # use smithay::backend::x11::{X11Backend, X11Surface, WindowBuilder};
//! use smithay::backend::allocator::gbm::{GbmAllocator, GbmDevice, GbmBufferFlags};
//! use smithay::backend::egl::{EGLDisplay, EGLContext};
//! use smithay::reexports::gbm;
//! use smithay::utils::DeviceFd;
//! use std::collections::HashSet;
//!
@ -40,7 +40,7 @@
//! // Get the DRM node used by the X server for direct rendering.
//! let (_drm_node, fd) = x_handle.drm_node()?;
//! // Create the gbm device for allocating buffers
//! let device = gbm::Device::new(DeviceFd::from(fd))?;
//! let device = GbmDevice::new(DeviceFd::from(fd))?;
//! // Initialize EGL to retrieve the support modifier list
//! let egl = unsafe { EGLDisplay::new(device.clone(), logger.clone()).expect("Failed to create EGLDisplay") };
//! let context = EGLContext::new(&egl, logger).expect("Failed to create EGLContext");
@ -48,7 +48,7 @@
//!
//! // Finally create the X11 surface, you will use this to obtain buffers that will be presented to the
//! // window.
//! let surface = x_handle.create_surface(&window, device, modifiers.into_iter());
//! let surface = x_handle.create_surface(&window, GbmAllocator::new(device, GbmBufferFlags::RENDERING), modifiers.into_iter());
//!
//! // Insert the backend into the event loop to receive events.
//! handle.insert_source(backend, |event, _window, state| {

View file

@ -0,0 +1,5 @@
#include <gbm.h>
void test() {
gbm_bo_create_with_modifiers2(NULL, 0, 0, 0, NULL, 0, 0);
}