perf(latency): tier-0 attribution + tier-1 send-path levers from the latency plan
ci / web (push) Successful in 49s
ci / docs-site (push) Successful in 54s
decky / build-publish (push) Successful in 18s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
apple / swift (push) Successful in 1m23s
ci / rust (push) Failing after 4m15s
arch / build-publish (push) Failing after 4m35s
deb / build-publish (push) Failing after 4m4s
docker / deploy-docs (push) Successful in 24s
ci / bench (push) Successful in 5m35s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 3m45s
windows-host / package (push) Failing after 9m8s
release / apple (push) Successful in 5m49s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 5m25s
flatpak / build-publish (push) Failing after 8m3s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m58s
android / android (push) Successful in 14m9s
apple / screenshots (push) Successful in 6m28s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 7m0s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 9m28s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 12m26s
ci / web (push) Successful in 49s
ci / docs-site (push) Successful in 54s
decky / build-publish (push) Successful in 18s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
apple / swift (push) Successful in 1m23s
ci / rust (push) Failing after 4m15s
arch / build-publish (push) Failing after 4m35s
deb / build-publish (push) Failing after 4m4s
docker / deploy-docs (push) Successful in 24s
ci / bench (push) Successful in 5m35s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Failing after 3m45s
windows-host / package (push) Failing after 9m8s
release / apple (push) Successful in 5m49s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 5m25s
flatpak / build-publish (push) Failing after 8m3s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m58s
android / android (push) Successful in 14m9s
apple / screenshots (push) Successful in 6m28s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 7m0s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 9m28s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 12m26s
design/latency-reduction-2026-07.md T0.1/T0.2/T1.2/T1.3:
- T1.2 rate-capped front-loaded pacing: the paced overflow's budget is now
min(0.9x slack, overflow wire time at ~3x the live encoder bitrate)
(PUNKTFUNK_PACE_FACTOR, 0 = legacy deadline-only spread). A 300 KB-1 MB
frame's tail leaves in ~2-5 ms instead of smearing across ~15 ms at 60 fps;
GameStream schedule byte-identical (pins unchanged).
- T1.3 data-first wire order: packetize emits every block's data shards before
any parity (per-block parity pools keep all blocks' parity alive for the
second pass), so lossless completion stops waiting behind the parity tail.
EOF = last emitted packet; receiver already order-agnostic.
- T0.1 staged 0xCF: HostTiming gains an append-extensible per-stage tail
(queue/encode/pace us; seal+channel-wait derived as residual) - no cap bit
needed, old peers read the 13-byte prefix. Joined client-side into
Stats::host_{queue,encode,xfer,pace}_ms, the OSD detailed tier, and the
probe's report.
- T0.2 true on-glass present timing: VK_KHR_present_id/present_wait enabled
when supported; a PresentTimer waiter thread resolves each present id to
real visibility, replacing the submit-time display stamp (which undercounts
by up to a refresh and hides a silent-FIFO standing queue).
Validated on .21: core 185 + host 185 tests, pf-presenter 19, clippy
-D warnings across all five touched crates; loss-harness recovery curve
unchanged; C ABI harness round-trips.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ use pf_client_core::video::{CpuFrame, VkVideoFrame};
|
||||
mod gpu;
|
||||
mod overlay_pipe;
|
||||
mod present;
|
||||
mod present_timing;
|
||||
mod reconfig;
|
||||
mod resources;
|
||||
mod setup;
|
||||
@@ -187,6 +188,16 @@ pub struct Presenter {
|
||||
/// The submit fence has a submission pending (wait before recording again — also
|
||||
/// what makes the single staging buffer safe to overwrite).
|
||||
submitted: bool,
|
||||
/// `VK_KHR_present_wait` on-glass timing (latency plan T0.2) — `None` when the
|
||||
/// device lacks the present-id/present-wait pair; the run loop then keeps its
|
||||
/// submit-time display stamp.
|
||||
present_timer: Option<present_timing::PresentTimer>,
|
||||
/// Monotonic present id (global counter — strictly increasing per swapchain, which
|
||||
/// is all the spec asks). 0 = nothing presented with an id yet.
|
||||
next_present_id: u64,
|
||||
/// The last successful id-carrying present, awaiting its [`Presenter::note_presented`]
|
||||
/// claim from the run loop (which owns the frame's pts/decode stamps).
|
||||
last_presented: Option<(vk::SwapchainKHR, u64)>,
|
||||
}
|
||||
|
||||
impl Presenter {
|
||||
@@ -220,6 +231,30 @@ impl Presenter {
|
||||
unsafe { self.device.device_wait_idle() }.ok();
|
||||
}
|
||||
|
||||
/// True when `VK_KHR_present_wait` drives the display stamp — the run loop then
|
||||
/// defers its e2e/display windows to [`Presenter::take_presented_samples`] instead
|
||||
/// of stamping at `present()` return.
|
||||
pub(crate) fn present_timing_active(&self) -> bool {
|
||||
self.present_timer.is_some()
|
||||
}
|
||||
|
||||
/// Claim the just-submitted present for on-glass timing. Call right after a
|
||||
/// `present()` that returned `true`, with that frame's capture + decode stamps
|
||||
/// (the presenter itself never sees them). No-op when timing is inactive.
|
||||
pub(crate) fn note_presented(&mut self, pts_ns: u64, decoded_ns: u64) {
|
||||
if let (Some(t), Some((sc, id))) = (&self.present_timer, self.last_presented.take()) {
|
||||
t.enqueue(sc, id, pts_ns, decoded_ns);
|
||||
}
|
||||
}
|
||||
|
||||
/// Take the window's completed on-glass samples (empty when timing is inactive).
|
||||
pub(crate) fn take_presented_samples(&self) -> Vec<present_timing::PresentedSample> {
|
||||
self.present_timer
|
||||
.as_ref()
|
||||
.map(|t| t.take_samples())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// The device handles the console-UI overlay renders on (§6.1). Valid for the
|
||||
/// presenter's lifetime; the run loop drops the overlay first.
|
||||
pub fn shared_device(&self) -> SharedDevice {
|
||||
@@ -237,6 +272,10 @@ impl Presenter {
|
||||
|
||||
impl Drop for Presenter {
|
||||
fn drop(&mut self) {
|
||||
// The present-wait waiter references the swapchain — stop it (its Drop joins
|
||||
// after in-flight waits complete, bounded by their 250 ms cap) BEFORE the
|
||||
// swapchain teardown below.
|
||||
self.present_timer.take();
|
||||
unsafe {
|
||||
{
|
||||
// Insurance against a straggling submitter (the run loop joins the
|
||||
|
||||
Reference in New Issue
Block a user