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 not letting go of what an outstanding flip still scans out (5). The first three are what the type does. The fifth it checks: landing the flip is the caller’s job, and dropping a scene with one still armed asserts.

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 on_session_paused(&mut self)

The session is losing DRM master: hand every held buffer back to its source, then tell each source and the canvas to stop using the device.

Port of the reference’s LayerScene::on_session_paused. The held buffers go back first, while their sources are still in a state to accept a release; each source then forgets or tears down what is bound to the descriptor, and the canvas forgets its buffers without an ioctl. A flip still armed is counted as landed: its event belongs to a descriptor that is being revoked and will never be dispatched.

Call on_session_resumed with the new device when the session comes back.

Source

pub fn on_session_resumed(&mut self, device: &Device) -> Result<(), SceneError>

The session is back, on device: rebuild everything that belonged to the old descriptor, and lift any suspension.

Port of the reference’s LayerScene::on_session_resumed. The allocator forgets the previous output – its assignment, committed baseline and failure cache describe kernel state the old descriptor took with it – so the next frame is searched and emitted in full, and is never skipped as unchanged. Each source re-allocates or re-imports against device. The canvas is made again at its size and format; if that fails composition is off until enable_composition is called again, as the reference drops its canvas then.

The plane registry is the caller’s, passed to each build_frame: probe it again on device too.

§Errors

SceneError::Source with the first source that cannot resume, as the reference stops at it. The sources after it have not been resumed, and the scene stays suspended if it was; calling this again retries.

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, returning whether there was one. A stale handle is a no-op and returns false.

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.