Skip to content
Snippets Groups Projects
Commit d9984abb authored by Lyude Paul's avatar Lyude Paul
Browse files

WIP: Basic bindings for drm_plane_state...?

I think this is right for drm_plane_state - we don't pin it since the
duplicate_state and destroy_state callbacks should be the only two
locations that we will actually have ownership over the data - and as far
as I can tell it shouldn't matter at all if we move it around so long as it
stops moving once it's passed to drm.
parent 8cac86e0
No related merge requests found
......@@ -2,36 +2,54 @@
//! KMS atomic plane abstractions for rust.
use alloc::boxed::Box;
use crate::{
container_of,
bindings,
container_of,
drm::device::Device,
error::to_result,
init::Zeroable,
prelude::*,
};
use core::{
cell::UnsafeCell,
marker::PhantomPinned,
mem
mem,
ptr::{NonNull, addr_of_mut, null_mut},
};
use macros::pin_data;
use super::KmsDriver;
/// The main data structure for a drm_plane. This holds the actual drm_plane struct, along with
/// whatever the driver's private data type (T) is.
#[repr(C)]
#[pin_data] // TODO: verify this is how we want to pin things?
pub struct Plane<T: DriverPlane> {
plane: bindings::drm_plane,
plane: UnsafeCell<bindings::drm_plane>,
#[pin]
inner: T,
#[pin]
_p: PhantomPinned,
}
unsafe impl Zeroable for bindings::drm_plane {}
/// The main trait for implementing the drm_plane API. This contains the various trait methods that
/// need to be implemented by a driver. The private driver data for the plane is contained in
/// whatever struct the driver defines which implements this trait.
pub trait DriverPlane: Sized {
/// The return type of the new() function. Should be `impl PinInit<Self, Error>`.
/// TODO: Remove this when return_position_impl_trait_in_trait is stable.
type Initializer: PinInit<Self, Error>;
/// The parent driver implementation
type Driver: KmsDriver;
/// The type for this driver's drm_plane_state implementation
type State: DriverPlaneState;
/// Create a new plane for this driver
fn new() -> Self::Initializer;
}
impl<T: DriverPlane> Plane<T> {
......@@ -45,8 +63,8 @@ impl<T: DriverPlane> Plane<T> {
destroy: None,
reset: Some(bindings::drm_atomic_helper_plane_reset),
set_property: None,
atomic_duplicate_state: Some(atomic_duplicate_state_callback::<T>),
atomic_destroy_state: None, // TODO: required (some sort of clone?)
atomic_duplicate_state: Some(atomic_duplicate_state_callback::<T::State>),
atomic_destroy_state: Some(atomic_destroy_state_callback::<T::State>),
atomic_set_property: None, // TODO someday
atomic_get_property: None, // TODO someday
late_register: None, // TODO someday
......@@ -54,16 +72,47 @@ impl<T: DriverPlane> Plane<T> {
atomic_print_state: None, // TODO: Display someday???
format_mod_supported: None // TODO someday
};
fn new(
dev: &Device<T::Driver>,
possible_crtcs: u32,
formats: &'static [u32],
format_modifiers: &'static [u64],
type_: bindings::drm_plane_type,
name: &CStr,
) -> Result<Pin<Box<Self>>> {
// TODO: Figure out some way of making sure that format_modifiers has the correct
// terminating sentinel (DRM_FORMAT_MOD_INVALID)
let plane: Pin<Box<Self>> = Box::pin_init(try_pin_init!(Self {
// SAFETY: This struct is expected to be zero-initialized
plane: UnsafeCell::new(bindings::drm_plane { ..Default::default() }),
inner <- T::new(),
_p: PhantomPinned
}))?;
to_result(unsafe {
bindings::drm_universal_plane_init(
dev.drm.get(),
plane.plane.get(),
possible_crtcs,
&Self::FUNCS,
formats.as_ptr(),
formats.len() as _,
format_modifiers.as_ptr(),
type_,
name.as_char_ptr()
)
})?;
Ok(plane)
}
}
#[pin_data]
#[derive(Clone)]
#[repr(C)]
pub struct PlaneState<T: DriverPlaneState> {
state: bindings::drm_plane_state,
#[pin]
inner: T,
#[pin]
_p: PhantomPinned,
}
/// Traits which must be implemented by KMS drivers for DRM planes.
......@@ -72,17 +121,76 @@ pub trait DriverPlaneState: Clone + Sized {
type Plane: DriverPlane;
}
unsafe extern "C" fn atomic_duplicate_state_callback<T: DriverPlane>(
impl<T: DriverPlaneState> PlaneState<T> {
/// Consume this struct without dropping it, and return a pointer to it's base `drm_plane_state`
/// which can be handed off to DRM.
fn into_raw(self: Box<Self>) -> *mut bindings::drm_plane_state {
let this = Box::into_raw(self);
unsafe { addr_of_mut!((*this).state) }
}
/// Consume a raw pointer and recover the original `Box<PlaneState<T>>`
///
/// SAFETY: Callers must ensure that ptr contains a non-null pointer
unsafe fn from_raw(ptr: *mut bindings::drm_plane_state) -> Box<Self> {
unsafe { Box::from_raw(container_of!(ptr, Self, state) as *mut _) }
}
/// Obtain a mutable reference back to the PlaneState<T>
///
/// SAFETY: Callers must ensure that ptr contains a non-null pointer
unsafe fn as_mut<'a>(ptr: *mut bindings::drm_plane_state) -> &'a mut Self {
unsafe { &mut *(container_of!(ptr, Self, state) as *mut _) }
}
/// Obtain a mutable pointer to the base plane state, for use in FFI calls
fn as_ptr(&mut self) -> *mut bindings::drm_plane_state {
addr_of_mut!(self.state)
}
}
unsafe impl Zeroable for bindings::drm_plane_state { }
unsafe extern "C" fn atomic_duplicate_state_callback<T: DriverPlaneState>(
plane: *mut bindings::drm_plane
) -> *mut bindings::drm_plane_state
{
// SAFETY: `plane` has to be non-null, since it holds the vtable for this function - which is
// the only possible entrypoint the caller could have used
let state = unsafe { (*plane).state };
// SAFETY: `plane` is guaranteed by FFI call signatures to be PlaneState<S>
// TODO: Do we need container_of!? I think we might actually be able to just cast this if the
// layout is identical
let state = container_of!(state, PlaneState<T::State>, state);
if state.is_null() {
return null_mut();
}
// SAFETY: We just verified that `state` is non-null, and we're guaranteed by our bindings that
// `state` is of type `PlaneState<T>`.
let state = unsafe { PlaneState::<T>::as_mut(state) };
let mut new: Result<Box<PlaneState<T>>> = Box::try_init(try_init!(PlaneState::<T> {
state: bindings::drm_plane_state { ..Default::default() },
inner: state.inner.clone()
}));
if let Ok(mut new) = new {
// SAFETY: Just a lil' FFI call, nothing special here
unsafe { bindings::__drm_atomic_helper_plane_duplicate_state(plane, new.as_ptr()) };
new.into_raw()
} else {
null_mut()
}
}
let new = unsafe { (&*state).clone() };
unsafe extern "C" fn atomic_destroy_state_callback<T: DriverPlaneState>(
_plane: *mut bindings::drm_plane,
plane_state: *mut bindings::drm_plane_state
) {
// SAFETY: This callback wouldn't be called unless there a plane state to destroy
unsafe { bindings::__drm_atomic_helper_plane_destroy_state(plane_state) };
todo!()
// SAFETY: We're guaranteed by type invariants that plane_state is of type PlaneState<T>, and
// since this is the destructor callback for DRM - we're guaranteed to hold the only remaining
// reference to this state
unsafe { PlaneState::<T>::from_raw(plane_state) };
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment