WP1+WP2 of design/desktop-presentation-rebuild.md. The shared Linux/Windows session client presented arrival-paced with no pacing layer at all: two depth-2 newest-wins hops into a drain-to-newest and an immediate present. That IS the lowest-latency intent, but it was unnamed, unselectable, and had no alternative — and on a surface without MAILBOX (AMD's Windows driver offers none, and any compositor holding images does the same) the swapchain's own FIFO becomes a standing queue worth a measured 11-13 ms at 60 Hz. WP1 — the settings cluster, under the keys the Apple client already writes into the shared profile catalog (present_priority / smooth_buffer / vsync / allow_vrr): mismatched names would ride SettingsOverlay::extra, carried but never applied. PresentPriority::resolve mirrors the Android reference exactly (anything but an explicit "smooth" is latency; a buffer outside 1..=3 becomes 2), so a profile authored on any client means the same thing on all of them. Only the first two are consumed here; vsync/allow_vrr land in WP3. WP2 — the engine (present_pace.rs, pure state + arithmetic, 6 tests): - FrameStore: newest-wins slot, or the smoothing FIFO with preroll-to-capacity, drop-oldest overflow, and an underflow that re-arms the preroll (repeat by omission) — the Apple/Android semantics, with qDrop/qDry counters. - LatchClock: the panel grid learned from VK_KHR_present_wait glass stamps, min positive spacing capped by the mode refresh (measured, never queried — VRR and Android's per-uid refresh lie both punish trusting a reported rate). It now also publishes the host-facing LatchGrid, so the phase-lock report and the local scheduler cannot disagree about the grid. - PresentGate: one undisplayed present in flight on FIFO surfaces, with the 100 ms stale force-open. This is the standing-queue killer, and it is inert on MAILBOX/IMMEDIATE and without present timing — where behaviour stays byte-for-byte the shipped arrival pacing. Wiring: glass samples drain every pass (a 1 Hz batch would starve clock and gate) and the waiter pushes an SDL wake, so a gate reopen never waits out the event timeout; smoothness serves one frame per latch slot and tightens the loop's wait to that deadline; the adaptive slot margin starts at 0 and widens +500 us per missed window toward 2.5 ms (a fixed lead was measured to be pure display tax). PUNKTFUNK_PRESENTER=arrival disables the whole engine for field A/B without a rebuild. PyroWave collapses smoothness to latency for the stream: its plane-ring retirement accounting assumes the depth-2 newest-wins hand-off, and all-intra frames make buffering moot anyway. Gates (punktfunk-rust-ci, linux/amd64, sources touched first so a warm target cannot print a vacuous Finished): clippy -D warnings across pf-client-core, pf-presenter and punktfunk-client-session; 80 + 32 tests pass; rustfmt clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
67 lines
3.3 KiB
Rust
67 lines
3.3 KiB
Rust
//! The Vulkan session presenter (punktfunk-planning `linux-client-rearchitecture.md`,
|
|
//! Phase 1): an SDL3 window + ash swapchain that presents the shared session pump's
|
|
//! decoded frames, captures input on the `ui_stream` state-machine contract, and reports
|
|
//! the unified stats window on stdout. No UI toolkit anywhere in the dependency tree.
|
|
//!
|
|
//! Three frame paths: software (`CpuFrame` RGBA staging upload), Vulkan Video (the
|
|
//! decoder's VkImage on THIS device — plane views + the CICP-driven CSC pass), and on
|
|
//! Linux additionally VAAPI hardware (NV12 dmabuf imported per-plane — `dmabuf.rs`),
|
|
//! all composited by a letterboxed blit. Devices without the import extensions, and any
|
|
//! import/present failure streak, demote the decoder to software via the session pump's
|
|
//! `force_software` contract, same as the GTK presenter.
|
|
//!
|
|
//! Builds on Linux AND Windows; `dmabuf` is Linux-only (DRM-PRIME does not exist on
|
|
//! Windows) and `d3d11` is its Windows counterpart (D3D11VA shared-texture import) —
|
|
//! the decode chain there is Vulkan → D3D11VA → software.
|
|
|
|
// Unsafe-proof program: every `unsafe {}` in this crate carries a `// SAFETY:` proof.
|
|
#![deny(clippy::undocumented_unsafe_blocks)]
|
|
|
|
// THE VULKAN CONTRACT, stated once - most `// SAFETY:` proofs in this crate are an instance of it.
|
|
//
|
|
// Nearly every `unsafe` here is an `ash` call, which is `unsafe` because Vulkan is a C API, not
|
|
// because each call carries its own bespoke obligation. Three shapes recur, and only one of them
|
|
// has a real precondition worth restating per site:
|
|
//
|
|
// * CREATE / ALLOCATE - `create_*`, `allocate_*`. The device is live (this type owns it), and the
|
|
// `vk::*CreateInfo` builders are locals that outlive the synchronous call. The handle returned is
|
|
// owned by the value being constructed and destroyed in its `Drop`.
|
|
// * RECORD - `cmd_*`, `begin/end_command_buffer`, `update_descriptor_sets`. Recorded into a command
|
|
// buffer this code owns and has begun, referencing handles it also owns. Nothing executes until
|
|
// submit, so a recording error is not yet a memory error.
|
|
// * DESTROY - `destroy_*`, `free_*`, `unmap_memory`. THIS is the one with a real obligation: the
|
|
// GPU must not still be using the object. That is established on the path, not by the call - a
|
|
// fence wait, a `queue_wait_idle`, or the swapchain having been retired - and the per-site proofs
|
|
// say so, because getting it wrong is a use-after-free the type system cannot catch.
|
|
//
|
|
// A block doing something OUTSIDE these three shapes gets a real, specific proof; if you add one and
|
|
// find yourself writing "as above", it probably belongs in one of them.
|
|
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub mod csc;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub mod cursor;
|
|
#[cfg(windows)]
|
|
pub mod d3d11;
|
|
#[cfg(target_os = "linux")]
|
|
pub mod dmabuf;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub mod input;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub mod keymap_sdl;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub mod overlay;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
mod present_pace;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
mod run;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub mod touch;
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub mod vk;
|
|
#[cfg(windows)]
|
|
mod win32;
|
|
|
|
#[cfg(any(target_os = "linux", windows))]
|
|
pub use run::{run_browse, run_session, ActionOutcome, Outcome, SessionOpts};
|