pub struct ScanoutBackend { /* private fields */ }Expand description
One output, one layer, and everything between a producer and the screen.
Discovers the output, reads the driver’s profile, negotiates a modifier against what the CRTC’s planes can scan out, asks the producer for a buffer in one of them, and drives a single-layer scene over it. What is left for the caller is rendering and pacing.
The backend does not dispatch the page-flip event, for the reason
DumbScanoutSink does not: the scene deliberately has no commit() of its
own, so the caller drives its own PageFlip and calls
flip_landed.
§Teardown
Dropping the backend while a flip it armed is still outstanding waits, up to
100 ms, for the CRTC’s vblank sequence to move past that commit or for its
flip event to be queued, before the scene lets go of its buffers. On a CRTC
with no vblank counter the queued event is the only thing it waits on. It
never reads the event queue, so the event stays queued for the caller.
Dispatching it and calling flip_landed first means
there is nothing to wait for. The device must outlive the backend: the wait
polls it.
Implementations§
Source§impl ScanoutBackend
impl ScanoutBackend
Sourcepub fn create(
device: &Device,
producer: &mut dyn ScanoutProducer,
config: &Config,
) -> Result<Self, PresentError>
pub fn create( device: &Device, producer: &mut dyn ScanoutProducer, config: &Config, ) -> Result<Self, PresentError>
Discover an output and build everything needed to present on it.
§Errors
PresentError::Bind if no output can be found, the driver or the
planes cannot be probed, or the producer cannot allocate.
Sourcepub fn present(
&mut self,
device: &Device,
flags: AtomicCommitFlags,
out_fence: Option<&mut Option<OwnedFd>>,
) -> Result<CommitReport, PresentError>
pub fn present( &mut self, device: &Device, flags: AtomicCommitFlags, out_fence: Option<&mut Option<OwnedFd>>, ) -> Result<CommitReport, PresentError>
Present one frame.
out_fence receives this commit’s OUT_FENCE where the CRTC exposes
OUT_FENCE_PTR — it signals once the frame is on screen, which is what
a producer waits on rather than blocking the CPU until the flip event.
§Errors
PresentError::Bind if the mode cannot be learned for the first,
modesetting frame; PresentError::Build if the scene cannot build
the frame; PresentError::Commit if the kernel refuses it.
Sourcepub fn present_if_changed(
&mut self,
device: &Device,
content_changed: bool,
flags: AtomicCommitFlags,
out_fence: Option<&mut Option<OwnedFd>>,
) -> Result<CommitReport, PresentError>
pub fn present_if_changed( &mut self, device: &Device, content_changed: bool, flags: AtomicCommitFlags, out_fence: Option<&mut Option<OwnedFd>>, ) -> Result<CommitReport, PresentError>
Present only if the content changed, suppressing an idle frame.
The first frame always commits, whatever content_changed says:
nothing is on screen yet, so “unchanged” describes nothing, and a
suppressed first frame leaves the scanout contents undefined.
A suppressed frame returns a report with
skipped_idle set and every other field
zero — there was no commit to count.
§Errors
As present.
Sourcepub const fn set_vrr(&mut self, enable: bool)
pub const fn set_vrr(&mut self, enable: bool)
Ask for variable refresh, or stop asking, from the next frame.
A no-op on a CRTC that exposes no VRR_ENABLED.
Sourcepub const fn vrr_capable(&self) -> bool
pub const fn vrr_capable(&self) -> bool
Whether the discovered output can do variable refresh.
Sourcepub const fn force_full_present(&mut self)
pub const fn force_full_present(&mut self)
Make the next frame a full commit, whatever the economy would decide.
Sourcepub const fn frames_committed(&self) -> u64
pub const fn frames_committed(&self) -> u64
How many frames were sent for commit.
Counted when the frame is decided, before it is built: a frame whose mode could not be learned, that the scene could not build, or that the kernel refused is counted all the same.
Sourcepub const fn frames_skipped(&self) -> u64
pub const fn frames_skipped(&self) -> u64
How many frames were suppressed as idle.
Sourcepub const fn target(&self) -> &ScanoutTarget
pub const fn target(&self) -> &ScanoutTarget
The output this backend found.
Sourcepub const fn profile(&self) -> &DriverProfile
pub const fn profile(&self) -> &DriverProfile
The driver’s capabilities, as probed.
Sourcepub fn modifiers(&self) -> &[u64]
pub fn modifiers(&self) -> &[u64]
The negotiated modifiers, most preferred first.
Empty when the backend fell back to LINEAR – no plane advertised
IN_FORMATS, or none of them took a layout the producer could make –
and the producer was allowed LINEAR alone.
Sourcepub const fn scene(&self) -> &LayerScene
pub const fn scene(&self) -> &LayerScene
The scene, for a caller adding layers of its own.
Sourcepub const fn scene_mut(&mut self) -> &mut LayerScene
pub const fn scene_mut(&mut self) -> &mut LayerScene
The scene, mutably.
Sourcepub const fn layer(&self) -> LayerHandle
pub const fn layer(&self) -> LayerHandle
The layer the producer’s buffer is presented on.
Sourcepub fn flip_landed(&mut self)
pub fn flip_landed(&mut self)
Tell the scene the flip it armed has landed.
Until this is called the scene believes a flip is outstanding, which is what keeps teardown from releasing a buffer the display engine is still reading — invariant 5.