pub struct ReleaseQueue { /* private fields */ }Expand description
The two-deep ring of in-flight acquisitions.
§Invariant 1: release after the flip, not after the ioctl
A buffer goes back to its source only once the page flip that stops
scanning it out has completed — two commits deep, never when commit’s
ioctl returns. Releasing at ioctl return would let a producer overwrite a
buffer the display engine is still reading, which tears on hardware whose
producer driver attaches no reservation fence.
Three generations are tracked:
| Generation | Frame | State |
|---|---|---|
current | N | just committed, about to be scanned out |
previous | N-1 | on screen; the flip for N displaces it |
two_ago | N-2 | off screen — safe to return |
A successful commit returns two_ago, then rotates. That is the whole
mechanism.
§Why this is not the scene’s own field
The queue never calls a source. It yields the buffers to hand back and lets the caller route each to the right source, because a source is owned by its layer and the queue has no business borrowing the layer table. It also means the entire contract is testable with no device, no source, and no kernel — which is what these tests do.
Implementations§
Source§impl ReleaseQueue
impl ReleaseQueue
Sourcepub fn commit_succeeded<F>(
&mut self,
current: Vec<Acquisition>,
release_fence: Option<&SyncFence>,
wants_fence: F,
) -> Released
pub fn commit_succeeded<F>( &mut self, current: Vec<Acquisition>, release_fence: Option<&SyncFence>, wants_fence: F, ) -> Released
Record a successful real commit and return the buffers it retired.
Invariant 1. The returned buffers are frame N-2’s: the flip just armed displaces frame N-1, so N-2 is what has finished scanning out. Frame N’s buffers stay held.
release_fence is this commit’s OUT_FENCE. It signals when the
buffers currently on screen — frame N-1 — leave it, so it is stamped
onto those and rides down to be handed back next rotation. A source that
wants it can then wait GPU-side instead of blocking the CPU until the
later release edge.
wants_fence decides per layer whether to stamp, so a scene with no
interested source pays nothing.
Sourcepub fn release_displaced(&mut self) -> Released
pub fn release_displaced(&mut self) -> Released
Return frame N-2’s buffers now, ahead of the next commit.
Only sound once the flip of the most recent real commit has completed:
that flip is what took them off screen. FrameLifecycle gates it on
the commit’s sequence for that reason; see
LayerScene::release_displaced.
Sourcepub fn commit_failed(&mut self, current: Vec<Acquisition>) -> Released
pub fn commit_failed(&mut self, current: Vec<Acquisition>) -> Released
Record a failed commit and return this frame’s buffers at once.
Invariant 2. No flip is in flight to gate them on, so deferring would just stall the source’s ring. Self-healing producer rings depend on reusing their buffers immediately after a rejection; the dropped frame heals on the next one.
The in-flight generations are not disturbed: the previous commit’s buffers are still on screen, and a failed commit did not displace them.
Sourcepub fn test_committed(&mut self, current: Vec<Acquisition>) -> Released
pub fn test_committed(&mut self, current: Vec<Acquisition>) -> Released
Record a test commit and return its buffers at once.
A TEST_ONLY applies nothing to hardware, so nothing in the scanout
pipeline references these buffers and deferring would only stall the
ring. Distinguished from commit_failed because
the caller reports them differently, not because the buffers are handled
differently.
Sourcepub fn drain(&mut self) -> Released
pub fn drain(&mut self) -> Released
Return everything held, oldest first.
Invariant 5’s counterpart. For teardown, session pause, and rebind — paths where no flip is in flight, so holding buffers back from their sources would simply leak them.
This does not wait on the kernel and must not: the scene’s drop stays
non-blocking, and landing an armed flip first is the caller’s job. See
ScenePendingFlip.