Skip to main content

LayerScene

Struct LayerScene 

Source
pub struct LayerScene { /* private fields */ }
Expand description

One CRTC’s layers and the commit machinery around them.

Layers are added once and kept: add_layer returns a LayerHandle that stays valid until the layer is removed, and a stale one resolves to nothing rather than to whatever now occupies the slot. Per frame, the caller changes what it wants — geometry through set_display, content through the source — and asks for a build_frame.

The scene is deliberately not a commit loop. It builds a plan and reads the kernel’s answer; issuing the commit, attaching a modeset, and dispatching the page-flip event belong to the caller, because a compositor has its own ideas about all three. See the crate documentation for the shape of a frame.

Four of the six pinned invariants are the scene’s: buffers released a flip late rather than an ioctl early (1), a failed commit releasing immediately because no flip will gate it (2), the FB-only fast path (4), and teardown draining an outstanding flip before letting go of what it scans out (5). None of them is something a caller opts into; they are what the type does.

Implementations§

Source§

impl LayerScene

Source

pub fn new(crtc_id: u32) -> Self

A scene driving crtc_id, with no layers.

Source

pub const fn crtc_id(&self) -> u32

The CRTC this scene drives.

Source

pub fn len(&self) -> usize

How many layers the scene holds.

Source

pub fn is_empty(&self) -> bool

Whether the scene holds no layers.

Source

pub const fn is_suspended(&self) -> bool

Whether the scene is suspended after losing DRM master.

Source

pub const fn has_pending_flip(&self) -> bool

Whether a page-flip event is armed and undispatched.

Invariant 5. Dropping the scene while this is true tears down a framebuffer the flip still references.

Source

pub const fn flip_landed(&mut self)

Record that the armed page-flip event was dispatched.

Source

pub fn resume(&mut self)

Lift a suspension after the session resumes.

Whoever held the CRTC meanwhile may have left planes lit, so the next frame turns off every plane it does not use.

Source

pub fn add_layer(&mut self, source: Box<dyn LayerBufferSource>) -> LayerHandle

Add a layer backed by source.

Source

pub fn remove_layer(&mut self, handle: LayerHandle) -> bool

Remove a layer. A stale handle is a no-op.

If the layer’s buffers are still in flight, its source is kept alive until they come back — releasing to a dropped source would strand them. The source hears LayerBufferSource::on_retired first.

Source

pub fn layer(&self, handle: LayerHandle) -> Option<&SceneLayer>

Borrow a layer, or None if the handle is stale.

Source

pub fn layer_mut(&mut self, handle: LayerHandle) -> Option<&mut SceneLayer>

Borrow a layer mutably, or None if the handle is stale.

Source

pub fn handles(&self) -> impl Iterator<Item = LayerHandle> + '_

Every live handle, in slot order.

Source

pub fn build_frame<C: TestCommitter>( &mut self, registry: &PlaneRegistry, crtc_index: u32, kind: CommitKind, committer: &mut C, ) -> Result<FrameBuild, SceneError>

Acquire from every layer, lower it, and run the allocator.

A source with nothing to contribute is skipped and counted, never treated as a failure — see SourceError::WouldBlock.

§Errors
Source

pub fn enable_composition( &mut self, device: &Device, width: u32, height: u32, ) -> Result<(), DumbError>

Give the scene a composition canvas.

Layers the allocator cannot place are blended into this surface and it goes on a plane of its own. Without one they are reported unassigned and simply do not reach the screen.

Separate from new because the search itself is device-free and this is not: the canvas owns two dumb buffers.

The canvas is ARGB8888, which every plane that matters takes. enable_composition_on is for the ones that do not.

§Errors

drmkit_dumb::DumbError if either buffer cannot be allocated.

Source

pub fn enable_composition_on( &mut self, device: &Device, width: u32, height: u32, plane: &PlaneCapabilities, ) -> Result<(), DumbError>

Give the scene a canvas in a format plane can scan out.

On a controller with one plane and no ARGB8888 – tilcdc on a BeagleBone, i.MX LCDIF, the small SPI panels – an ARGB8888 canvas cannot be armed at all, so every layer that overflows the plane count is dropped rather than composited. This negotiates instead, and blends in ARGB8888 regardless: the conversion happens once at flush rather than quantizing at every layer.

§Errors

drmkit_dumb::DumbError::InvalidConfig if the plane advertises nothing the canvas can write – a YUV-only overlay, say – and otherwise as enable_composition.

Source

pub fn canvas_fourcc(&self) -> Option<u32>

What the composition canvas scans out as, if there is one.

Source

pub fn finalize_frame( &mut self, build: FrameBuild, result: KernelResult, ) -> CommitReport

Reconcile scene state with the kernel’s answer, releasing buffers per invariants 1, 2 and 5.

Source

pub fn finalize_frame_with_fence( &mut self, build: FrameBuild, result: KernelResult, release_fence: Option<&SyncFence>, ) -> CommitReport

Finalize a frame, handing over the commit’s OUT_FENCE.

release_fence signals once this commit’s buffers are on screen — which is the moment the buffers it displaced are off screen and safe to render into again. Sources that opted in through wants_release_fence get a duplicate of it alongside each released buffer, so a GPU producer waits on it GPU-side instead of blocking until a later release edge.

Ask wants_release_fence whether to arm OUT_FENCE_PTR at all: with no source listening, the fence costs a descriptor per commit and nothing reads it.

Passing None is finalize_frame, and is correct whenever the CRTC has no OUT_FENCE_PTR or the commit did not ask for one.

Source

pub const fn set_force_full_property_writes(&mut self, force: bool)

Re-emit every property on every commit, for a driver that mishandles a partial write.

Off by default. A quirk escape hatch, not a tuning knob: it defeats invariant 4’s minimal-write path and multiplies per-frame property traffic, and the only reason to reach for it is a driver that gets the minimal set wrong. Exposed here because the allocator it configures is the scene’s, and a caller stuck on such a driver otherwise has no way in.

Source

pub const fn force_full_property_writes(&self) -> bool

Whether full property writes are being forced.

Source

pub fn content_changed(&self) -> bool

Whether this frame is worth committing at all.

The whole-commit skip. When every live source says it has nothing new and no layer has moved, the frame can be dropped without issuing an atomic commit — the display goes on scanning out what is already there. That is a power win on any device and the thing that lets a self-refresh panel stay in self-refresh, which it cannot do if a commit arrives every vblank saying nothing changed.

Answers true for anything it cannot rule out. A source that cannot tell whether its buffer changed reports “changed” by default, so a CPU producer painting into a dumb buffer never gets skipped; the layer set changing counts, geometry changing counts, and the first frame always counts, because nothing is on screen yet for “unchanged” to describe.

Source

pub fn find_by_identity_tag(&self, tag: u64) -> Option<LayerHandle>

The first layer carrying tag, if any.

The lookup that makes SceneLayer::set_identity_tag worth setting: a caller that survived a rebind, a session resume, or its own restart can find its layers again from its own identifiers rather than from handles it may no longer hold.

Source

pub const fn pending_detach(&self) -> Option<&PendingDetach>

What a rebind left lit on the CRTC the scene moved away from, until it is committed.

Source

pub fn detach_committed(&mut self)

Record that the pending detach reached the kernel.

commit_detach calls this after a successful commit; a caller committing the detach some other way must too.

Source

pub fn rebind(&mut self, crtc_id: u32, width: u32, height: u32) -> RebindReport

Move this scene to another output, keeping its layers.

For an output that changed underneath the caller: a mode set, a different CRTC after a session resume, a display swapped for another. Layer handles survive — that is the point, since a caller that had to rebuild its layers would have to rebuild everything it knows about them too.

Everything cached about the previous output is dropped – the assignment, the committed baseline, the failure cache – and the next commit is a full emit, with which the caller must set the new mode.

Moving to another CRTC leaves the old one’s planes lit, and the scene cannot turn them off itself: it does not commit. They are queued as a PendingDetach, and until the caller commits it through commit_detach, build_frame refuses with SceneError::DetachPending. Two reasons it cannot be skipped: the kernel will not move a plane from one CRTC to another in a single commit, so a plane both pipes can use is rejected outright on the new one; and a plane the new pipe cannot use would go on showing this scene’s last frame on the old output indefinitely. A rebind to the same CRTC queues nothing. Upstream fixed the same defect in a335bef (drm-cxx#340), from inside its rebind, which owns a device.

Returns what will not fit. A layer whose destination lies outside the new mode is not dropped — the caller may be about to move it, and deciding on its behalf would be worse than saying so.

Source

pub fn wants_release_fence(&self) -> bool

Whether any live source wants this commit’s OUT_FENCE.

The commit path asks before arming OUT_FENCE_PTR: the fence costs a descriptor per commit that has to be closed, and with nothing listening it is a descriptor leak dressed as a feature.

Source

pub fn release_displaced(&mut self, commit_seq: u64)

Hand back now the buffers that the page flip of real commit commit_seq (its CommitReport::commit_seq) took off screen, instead of at the next real commit.

A buffer leaves the screen when the flip of the commit after the one that showed it completes, and the scene hands it back at the commit after that (invariant 1) – right for a caller that commits ahead of its flips. A caller that waits for each flip before committing again, feeding producers that wait for a free buffer before rendering, may never make that next commit: a producer with two buffers then waits for good, and one with three gets each buffer a frame late. Call this once the flip completes – after dispatching its event, or at the start of the next frame – to hand those buffers back then.

A no-op unless commit_seq names the most recent real commit, so a late or repeated call cannot release a buffer still on screen. Port of upstream’s release_displaced (ee90026).

Source

pub fn drain(&mut self)

Hand every held buffer back, without waiting on the kernel.

Invariant 5. For teardown, session pause, and rebind. Landing an armed flip first is the caller’s job — see has_pending_flip.

Trait Implementations§

Source§

impl Debug for LayerScene

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for LayerScene

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.