Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/software renderer #1228

Merged
merged 8 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ cursor-icon = "1.0.0"
cgmath = "0.18.0"
downcast-rs = "1.2.0"
drm-fourcc = "^2.2.0"
drm = { version = "0.11.0", optional = true }
drm-ffi = { version = "0.7.0", optional = true }
drm = { version = "0.11.1", optional = true }
drm-ffi = { version = "0.7.1", optional = true }
errno = "0.3.5"
gbm = { version = "0.14.0", optional = true, default-features = false, features = ["drm-support"] }
glow = { version = "0.12", optional = true }
Expand Down Expand Up @@ -67,6 +67,8 @@ scan_fmt = { version = "0.2.3", default-features = false }
encoding_rs = { version = "0.8.33", optional = true }
profiling = "1.0"
smallvec = "1.11"
pixman = { version = "0.1.0", features = ["drm-fourcc"], optional = true }


[dev-dependencies]
clap = { version = "4", features = ["derive"] }
Expand Down Expand Up @@ -97,13 +99,14 @@ desktop = []
renderer_gl = ["gl_generator", "backend_egl"]
renderer_glow = ["renderer_gl", "glow"]
renderer_multi = ["backend_drm"]
renderer_pixman = ["pixman"]
renderer_test = []
use_system_lib = ["wayland_frontend", "wayland-backend/server_system", "wayland-sys", "gbm?/import-wayland"]
use_bindgen = ["drm-ffi/use_bindgen", "gbm/use_bindgen", "input/gen"]
wayland_frontend = ["wayland-server", "wayland-protocols", "wayland-protocols-wlr", "wayland-protocols-misc", "tempfile"]
x11rb_event_source = ["x11rb"]
xwayland = ["encoding_rs", "wayland_frontend", "x11rb/composite", "x11rb/xfixes", "x11rb_event_source", "scopeguard"]
test_all_features = ["default", "use_system_lib", "renderer_glow", "renderer_test"]
test_all_features = ["default", "use_system_lib", "renderer_glow", "renderer_test", "renderer_pixman"]

[[example]]
name = "minimal"
Expand Down
14 changes: 10 additions & 4 deletions anvil/src/input_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,11 @@ impl<Backend: crate::state::Backend> AnvilState<Backend> {
Transform::Normal => Transform::_90,
Transform::_90 => Transform::_180,
Transform::_180 => Transform::_270,
Transform::_270 => Transform::Normal,
_ => Transform::Normal,
Transform::_270 => Transform::Flipped,
Transform::Flipped => Transform::Flipped90,
Transform::Flipped90 => Transform::Flipped180,
Transform::Flipped180 => Transform::Flipped270,
Transform::Flipped270 => Transform::Normal,
};
output.change_current_state(None, Some(new_transform), None, None);
crate::shell::fixup_positions(&mut self.space, self.pointer.current_location());
Expand Down Expand Up @@ -670,8 +673,11 @@ impl AnvilState<UdevData> {
Transform::Normal => Transform::_90,
Transform::_90 => Transform::_180,
Transform::_180 => Transform::_270,
Transform::_270 => Transform::Normal,
_ => Transform::Normal,
Transform::_270 => Transform::Flipped,
Transform::Flipped => Transform::Flipped90,
Transform::Flipped90 => Transform::Flipped180,
Transform::Flipped180 => Transform::Flipped270,
Transform::Flipped270 => Transform::Normal,
};
output.change_current_state(None, Some(new_transform), None, None);
crate::shell::fixup_positions(&mut self.space, self.pointer.current_location());
Expand Down
10 changes: 5 additions & 5 deletions anvil/src/udev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use smithay::{
Allocator, Fourcc,
},
drm::{
compositor::DrmCompositor, CreateDrmNodeError, DrmDevice, DrmDeviceFd, DrmError, DrmEvent,
DrmEventMetadata, DrmNode, DrmSurface, GbmBufferedSurface, NodeType,
compositor::DrmCompositor, CreateDrmNodeError, DrmAccessError, DrmDevice, DrmDeviceFd, DrmError,
DrmEvent, DrmEventMetadata, DrmNode, DrmSurface, GbmBufferedSurface, NodeType,
},
egl::{self, context::ContextPriority, EGLDevice, EGLDisplay},
libinput::{LibinputInputBackend, LibinputSessionInterface},
Expand Down Expand Up @@ -1293,10 +1293,10 @@ impl AnvilState<UdevData> {
}
SwapBuffersError::TemporaryFailure(err) => matches!(
err.downcast_ref::<DrmError>(),
Some(DrmError::Access {
Some(DrmError::Access(DrmAccessError {
source,
..
}) if source.kind() == io::ErrorKind::PermissionDenied
})) if source.kind() == io::ErrorKind::PermissionDenied
),
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
}
Expand Down Expand Up @@ -1486,7 +1486,7 @@ impl AnvilState<UdevData> {
SwapBuffersError::AlreadySwapped => false,
SwapBuffersError::TemporaryFailure(err) => match err.downcast_ref::<DrmError>() {
Some(DrmError::DeviceInactive) => true,
Some(DrmError::Access { source, .. }) => {
Some(DrmError::Access(DrmAccessError { source, .. })) => {
source.kind() == io::ErrorKind::PermissionDenied
}
_ => false,
Expand Down
8 changes: 4 additions & 4 deletions examples/buffer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ use smithay::{
backend::{
allocator::{
dmabuf::{AnyError, Dmabuf, DmabufAllocator},
dumb::DumbAllocator,
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
vulkan::{ImageUsageFlags, VulkanAllocator},
Allocator, Fourcc, Modifier,
},
drm::{DrmDevice, DrmDeviceFd, DrmNode},
drm::{DrmDeviceFd, DrmNode},
egl::{EGLContext, EGLDevice, EGLDisplay},
renderer::{
gles::{GlesRenderbuffer, GlesRenderer},
Expand Down Expand Up @@ -173,9 +174,8 @@ fn buffer_test(args: TestArgs) {
let mut allocator = match args.allocator {
AllocatorType::DumbBuffer => {
let fd = open_device(&path);
Box::new(DmabufAllocator(
DrmDevice::new(fd, false).expect("Failed to init drm device").0,
)) as Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>
let dumb_allocator = DumbAllocator::new(fd);
Box::new(DmabufAllocator(dumb_allocator)) as Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>
}
AllocatorType::Gbm => {
let fd = open_device(&path);
Expand Down
147 changes: 147 additions & 0 deletions src/backend/allocator/dmabuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use calloop::generic::Generic;
use calloop::{EventSource, Interest, Mode, PostAction};
use rustix::ioctl::{Setter, WriteOpcode};

use super::{Allocator, Buffer, Format, Fourcc, Modifier};
use crate::utils::{Buffer as BufferCoords, Size};
Expand Down Expand Up @@ -245,6 +246,152 @@ impl Dmabuf {
let blocker = DmabufBlocker(source.signal.clone());
Ok((blocker, source))
}

/// Map the plane at specified index with the specified mode
///
/// Returns `Err` if the plane with the specified index does not exist or
/// mmap failed
pub fn map_plane(
&self,
idx: usize,
mode: DmabufMappingMode,
) -> Result<DmabufMapping, DmabufMappingFailed> {
let plane = self
.0
.planes
.get(idx)
.ok_or(DmabufMappingFailed::PlaneIndexOutOfBound)?;

let size = rustix::fs::seek(&plane.fd, rustix::fs::SeekFrom::End(0)).map_err(std::io::Error::from)?;
rustix::fs::seek(&plane.fd, rustix::fs::SeekFrom::Start(0)).map_err(std::io::Error::from)?;

let len = (size - plane.offset as u64) as usize;
let ptr = unsafe {
rustix::mm::mmap(
std::ptr::null_mut(),
len,
mode.into(),
rustix::mm::MapFlags::SHARED,
&plane.fd,
plane.offset as u64,
)
}
.map_err(std::io::Error::from)?;
Ok(DmabufMapping { len, ptr })
}

/// Synchronize access for the plane at the specified index
///
/// Returns `Err` if the plane with the specified index does not exist or
/// the dmabuf_sync ioctl failed
pub fn sync_plane(&self, idx: usize, flags: DmabufSyncFlags) -> Result<(), DmabufSyncFailed> {
let plane = self
.0
.planes
.get(idx)
.ok_or(DmabufSyncFailed::PlaneIndexOutOfBound)?;
unsafe { rustix::ioctl::ioctl(&plane.fd, Setter::<DmaBufSync, _>::new(dma_buf_sync { flags })) }
.map_err(std::io::Error::from)?;
Ok(())
}
}

bitflags::bitflags! {
/// Modes of mapping a dmabuf plane
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DmabufMappingMode: u32 {
/// Map the dmabuf readable
const READ = 0b00000001;
/// Map the dmabuf writable
const WRITE = 0b00000010;
}
}

impl From<DmabufMappingMode> for rustix::mm::ProtFlags {
fn from(mode: DmabufMappingMode) -> Self {
let mut flags = rustix::mm::ProtFlags::empty();

if mode.contains(DmabufMappingMode::READ) {
flags |= rustix::mm::ProtFlags::READ;
}

if mode.contains(DmabufMappingMode::WRITE) {
flags |= rustix::mm::ProtFlags::WRITE;
}

flags
}
}

/// Dmabuf mapping errors
#[derive(Debug, thiserror::Error)]
#[error("Mapping the dmabuf failed")]
pub enum DmabufMappingFailed {
/// The supplied index for the plane is out of bounds
#[error("The supplied index for the plane is out of bounds")]
PlaneIndexOutOfBound,
/// Io error during map operation
Io(#[from] std::io::Error),
}

/// Dmabuf sync errors
#[derive(Debug, thiserror::Error)]
#[error("Sync of the dmabuf failed")]
pub enum DmabufSyncFailed {
/// The supplied index for the plane is out of bounds
#[error("The supplied index for the plane is out of bounds")]
PlaneIndexOutOfBound,
/// Io error during sync operation
Io(#[from] std::io::Error),
}

bitflags::bitflags! {
/// Flags for the [`Dmabuf::sync_plane`](Dmabuf::sync_plane) operation
#[derive(Copy, Clone)]
pub struct DmabufSyncFlags: std::ffi::c_ulonglong {
/// Read from the dmabuf
const READ = 1 << 0;
/// Write to the dmabuf
#[allow(clippy::identity_op)]
const WRITE = 2 << 0;
/// Start of read/write
const START = 0 << 2;
/// End of read/write
const END = 1 << 2;
}
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct dma_buf_sync {
flags: DmabufSyncFlags,
}

type DmaBufSync = WriteOpcode<b'b', 0, dma_buf_sync>;

/// A mapping into a [`Dmabuf`]
#[derive(Debug)]
pub struct DmabufMapping {
ptr: *mut std::ffi::c_void,
len: usize,
}

impl DmabufMapping {
/// Access the raw pointer of the mapping
pub fn ptr(&self) -> *mut std::ffi::c_void {
self.ptr
}

/// Access the length of the mapping
pub fn length(&self) -> usize {
self.len
}
}

impl Drop for DmabufMapping {
fn drop(&mut self) {
let _ = unsafe { rustix::mm::munmap(self.ptr, self.len) };
}
}

impl WeakDmabuf {
Expand Down
27 changes: 19 additions & 8 deletions src/backend/allocator/dumb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use tracing::instrument;

use super::dmabuf::{AsDmabuf, Dmabuf, DmabufFlags};
use super::{format::get_bpp, Allocator, Buffer, Format, Fourcc, Modifier};
use crate::backend::drm::device::{DrmDevice, DrmDeviceInternal};
use crate::backend::drm::DrmDeviceFd;
use crate::utils::{Buffer as BufferCoords, Size};

Expand All @@ -29,7 +28,20 @@ impl fmt::Debug for DumbBuffer {
}
}

impl Allocator for DrmDevice {
/// Light wrapper around an [`DrmDeviceFd`] to implement the [`Allocator`]-trait
#[derive(Debug)]
pub struct DumbAllocator {
fd: DrmDeviceFd,
}

impl DumbAllocator {
/// Create a new [`DumbAllocator`] from a [`DrmDeviceFd`].
pub fn new(fd: DrmDeviceFd) -> Self {
DumbAllocator { fd }
}
}

impl Allocator for DumbAllocator {
type Buffer = DumbBuffer;
type Error = io::Error;

Expand All @@ -50,17 +62,14 @@ impl Allocator for DrmDevice {
return Err(rustix::io::Errno::INVAL.into());
}

let handle = self.create_dumb_buffer(
let handle = self.fd.create_dumb_buffer(
(width, height),
fourcc,
get_bpp(fourcc).ok_or(rustix::io::Errno::INVAL)? as u32,
)?;

Ok(DumbBuffer {
fd: match &*self.internal {
DrmDeviceInternal::Atomic(dev) => dev.fd.clone(),
DrmDeviceInternal::Legacy(dev) => dev.fd.clone(),
},
fd: self.fd.clone(),
handle,
format: Format {
code: fourcc,
Expand Down Expand Up @@ -96,7 +105,9 @@ impl AsDmabuf for DumbBuffer {

#[profiling::function]
fn export(&self) -> Result<Dmabuf, Self::Error> {
let fd = self.fd.buffer_to_prime_fd(self.handle.handle(), 0)?;
let fd = self
.fd
.buffer_to_prime_fd(self.handle.handle(), drm::CLOEXEC | drm::RDWR)?;
let mut builder = Dmabuf::builder(
self.size(),
self.format.code,
Expand Down
45 changes: 45 additions & 0 deletions src/backend/drm/compositor/dumb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! Implementation for ExportFramebuffer and related utilizies for dumb buffers

use thiserror::Error;

use super::{ExportBuffer, ExportFramebuffer};
use crate::backend::{
allocator::dumb::DumbBuffer,
drm::{
dumb::{framebuffer_from_dumb_buffer, DumbFramebuffer},
error::AccessError,
DrmDeviceFd,
},
};

/// Possible errors for attaching a [`framebuffer::Handle`]
#[derive(Error, Debug)]
pub enum Error {
/// The buffer is not supported
#[error("Unsupported buffer supplied")]
Unsupported,
/// Failed to add a framebuffer for the dumb buffer
#[error("failed to add a framebuffer for the dumb buffer")]
Drm(AccessError),
}

impl ExportFramebuffer<DumbBuffer> for DrmDeviceFd {
type Framebuffer = DumbFramebuffer;
type Error = Error;

#[profiling::function]
fn add_framebuffer(
&self,
_drm: &DrmDeviceFd,
buffer: ExportBuffer<'_, DumbBuffer>,
use_opaque: bool,
) -> Result<Option<Self::Framebuffer>, Self::Error> {
match buffer {
#[cfg(feature = "wayland_frontend")]
ExportBuffer::Wayland(_) => return Err(Error::Unsupported),
ExportBuffer::Allocator(buffer) => framebuffer_from_dumb_buffer(self, buffer, use_opaque)
.map_err(Error::Drm)
.map(Some),
}
}
}
Loading
Loading