Hi Lyude, > On 30 Sep 2024, at 20:09, Lyude Paul <lyude@xxxxxxxxxx> wrote: > > Same thing as OpaqueCrtc and OpaqueCrtcState, but for plane states now. > > Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx> > > --- > > TODO: > * Finish adding upcast functions. > > Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx> > --- > rust/kernel/drm/kms/plane.rs | 143 +++++++++++++++++++++++++++++++++++ > 1 file changed, 143 insertions(+) > > diff --git a/rust/kernel/drm/kms/plane.rs b/rust/kernel/drm/kms/plane.rs > index 3040c4546b121..3ace487316d46 100644 > --- a/rust/kernel/drm/kms/plane.rs > +++ b/rust/kernel/drm/kms/plane.rs > @@ -217,6 +217,43 @@ pub fn new<'a, 'b: 'a, const FMT_COUNT: usize, const MOD_COUNT: usize>( > // SAFETY: We don't move anything > Ok(unsafe { &*Box::into_raw(Pin::into_inner_unchecked(this)) }) > } > + > + /// Attempt to convert an [`OpaquePlane`] into a fully qualified [`Plane`]. > + /// > + /// This checks if the given [`OpaquePlane`] uses the same [`DriverPlane`] implementation, and > + /// returns the [`OpaquePlane`] as a [`Plane`] object if so. > + pub fn try_from_opaque<'a, D>(opaque: &'a OpaquePlane<D>) -> Option<&'a Self> > + where > + D: KmsDriver, > + T: DriverPlane<Driver = D> > + { > + // SAFETY: The vtables for a `Plane` are initialized by the time that we expose `Plane` > + // objects to users, and their values are invariant throughout the lifetime of the device. > + let funcs = unsafe { (*opaque.plane.get()).funcs }; > + > + // SAFETY: We just guaranteed that the opaque plane shares our vtable pointers, which means > + // it must belong to our `DriverPlane` implementation. As well, all `Plane<DriverPlane>` > + // objects start with an identical data layout to `OpaquePlane` > + ptr::eq(funcs, &T::OPS.funcs).then(|| unsafe { mem::transmute(opaque) }) > + } > + > + /// Convert a [`OpaquePlane`] into its fully qualified [`Plane`]. > + /// > + /// This is an infallible version of [`Self::try_from_opaque`]. This function is mainly useful > + /// for drivers where only a single [`DriverPlane`] implementation exists. > + /// > + /// # Panics > + /// > + /// This function will panic if the underlying [`Plane`] which contains the provided > + /// [`OpaquePlane`] does not belong to the same [`DriverPlane`] implementation. > + pub fn from_opaque<'a, D>(opaque: &'a OpaquePlane<D>) -> &'a Self > + where > + D: KmsDriver, > + T: DriverPlane<Driver = D> > + { > + Self::try_from_opaque(opaque) > + .expect("Passed OpaquePlane does not share this DriverPlane implementation") > + } I guess the same question from the previous patch applies. If a driver has only a single implementor for `DriverPlane`, why should it care about OpaquePlane? > } > > /// A trait implemented by any type that acts as a [`struct drm_plane`] interface. > @@ -275,6 +312,63 @@ unsafe impl<T: DriverPlane> Send for Plane<T> {} > // SAFETY: Our interface is thread-safe. > unsafe impl<T: DriverPlane> Sync for Plane<T> {} > > +/// A [`struct drm_plane`] without a known [`DriverPlane`] implementation. > +/// > +/// This is mainly for situations where our bindings can't infer the [`DriverPlane`] implementation > +/// for a [`struct drm_plane`] automatically. It is identical to [`Plane`], except that it does not > +/// provide access to the driver's private data. > +/// > +/// It may be upcasted to a full [`Plane`] using [`Plane::from_opaque`] or > +/// [`Plane::try_from_opaque`]. > +/// > +/// # Invariants > +/// > +/// - `plane` is initialized for as long as this object is made available to users. > +/// - The data layout of this structure is equivalent to [`struct drm_plane`]. > +/// > +/// [`struct drm_plane`]: srctree/include/drm/drm_plane.h > +#[repr(transparent)] > +pub struct OpaquePlane<T: KmsDriver> { > + plane: Opaque<bindings::drm_plane>, > + _p: PhantomData<T>, > +} > + > +impl<T: KmsDriver> Sealed for OpaquePlane<T> {} > + > +impl<T: KmsDriver> AsRawPlane for OpaquePlane<T> { > + type State = OpaquePlaneState<T>; > + > + fn as_raw(&self) -> *mut bindings::drm_plane { > + self.plane.get() > + } > + > + unsafe fn from_raw<'a>(ptr: *mut bindings::drm_plane) -> &'a Self { > + // SAFETY: Our data layout is identical to `bindings::drm_plane` > + unsafe { &*ptr.cast() } > + } > +} > + > +impl<T: KmsDriver> ModeObject for OpaquePlane<T> { > + type Driver = T; > + > + fn drm_dev(&self) -> &Device<Self::Driver> { > + // SAFETY: DRM planes exist for as long as the device does, so this pointer is always valid > + unsafe { Device::borrow((*self.as_raw()).dev) } > + } > + > + fn raw_mode_obj(&self) -> *mut bindings::drm_mode_object { > + // SAFETY: We don't expose DRM planes to users before `base` is initialized > + unsafe { &mut ((*self.as_raw()).base) } > + } > +} > + > +// SAFETY: Planes do not have a refcount > +unsafe impl<T: KmsDriver> StaticModeObject for OpaquePlane<T> {} > + > +// SAFETY: Our plane interfaces are guaranteed to be thread-safe > +unsafe impl<T: KmsDriver> Send for OpaquePlane<T> {} > +unsafe impl<T: KmsDriver> Sync for OpaquePlane<T> {} > + > /// A trait implemented by any type which can produce a reference to a [`struct drm_plane_state`]. > /// > /// This is implemented internally by DRM. > @@ -419,6 +513,55 @@ fn deref_mut(&mut self) -> &mut Self::Target { > } > } > > +/// A [`struct drm_plane_state`] without a known [`DriverPlaneState`] implementation. > +/// > +/// This is mainly for situations where our bindings can't infer the [`DriverPlaneState`] > +/// implementation for a [`struct drm_plane_state`] automatically. It is identical to [`Plane`], > +/// except that it does not provide access to the driver's private data. > +/// > +/// TODO: Add upcast functions > +/// > +/// # Invariants > +/// > +/// - The DRM C API and our interface guarantees that only the user has mutable access to `state`, > +/// up until [`drm_atomic_helper_commit_hw_done`] is called. Therefore, `plane` follows rust's > +/// data aliasing rules and does not need to be behind an [`Opaque`] type. > +/// - `state` is initialized for as long as this object is exposed to users. > +/// - The data layout of this structure is identical to [`struct drm_plane_state`]. > +/// > +/// [`struct drm_plane_state`]: srctree/include/drm/drm_plane.h > +/// [`drm_atomic_helper_commit_hw_done`]: srctree/include/drm/drm_atomic_helper.h > +#[repr(transparent)] > +pub struct OpaquePlaneState<T: KmsDriver> { > + state: bindings::drm_plane_state, > + _p: PhantomData<T>, > +} > + > +impl<T: KmsDriver> AsRawPlaneState for OpaquePlaneState<T> { > + type Plane = OpaquePlane<T>; > +} > + > +impl<T: KmsDriver> private::AsRawPlaneState for OpaquePlaneState<T> { > + fn as_raw(&self) -> &bindings::drm_plane_state { > + &self.state > + } > + > + unsafe fn as_raw_mut(&mut self) -> &mut bindings::drm_plane_state { > + &mut self.state > + } > +} > + > +impl<T: KmsDriver> FromRawPlaneState for OpaquePlaneState<T> { > + unsafe fn from_raw<'a>(ptr: *const bindings::drm_plane_state) -> &'a Self { > + // SAFETY: Our data layout is identical to `ptr` > + unsafe { &*ptr.cast() } > + } > + > + unsafe fn from_raw_mut<'a>(ptr: *mut bindings::drm_plane_state) -> &'a mut Self { > + // SAFETY: Our data layout is identical to `ptr` > + unsafe { &mut *ptr.cast() } > + } > +} > unsafe extern "C" fn plane_destroy_callback<T: DriverPlane>( > plane: *mut bindings::drm_plane > ) { > -- > 2.46.1 > Apart for the clarification I asked above, this patch looks good. — Daniel