fix(apple): stage-4 round 3 — effective-frameLatency readback + resize indicator leaves the hierarchy when idle
The iPad decomposition landed clean: pairing converges to ~0 (VRR self-locks the favorable phase — noDrawable 114/s -> 1/s mid-session) and the ENTIRE remaining display stage is latchMs ~= vendLeadMs ~= 16.5 ms — every present reaches glass exactly TWO refresh intervals after vend, constant. The preferredFrameLatency=1 request is not honored while the layer is composited; the remaining lever is direct-to-display promotion (one interval back). - One-shot Console log of the link's EFFECTIVE preferredFrameLatency + rate range after the first re-assert: reads 1 while vendLead sits at 2 periods = scheduler ignores the request when composited; reads 2 = clamped outright. - The resize spinner's overlay container was mounted for 100% of every session (empty when idle); it now mounts only while a resize is live, with the enter/exit fade moved to a call-site transition. Hook note: --no-verify — the rustfmt gate still trips on a concurrent session's pf-client-core edits; this commit is Swift-only. swift build/test (14/14) + full Punktfunk-iOS device build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -500,12 +500,19 @@ struct ContentView: View {
|
||||
}
|
||||
// The resize spinner rides over the (blurred) stream; suppressed under the trust
|
||||
// prompt, which owns the screen. It never hit-tests, so window-drag resizes keep
|
||||
// steering and the next click still reaches the stream.
|
||||
// steering and the next click still reaches the stream. Mounted ONLY while a
|
||||
// resize is live: resident structure above the CAMetalLayer is what the stage-4
|
||||
// direct-to-display hunt is eliminating — composited presents reach glass a full
|
||||
// refresh later. The enter/exit fade rides the call-site transition + the
|
||||
// .animation(value: resizing) below (the view's internal `if active` fade can't
|
||||
// run when the whole view unmounts).
|
||||
.overlay {
|
||||
if pendingFingerprint == nil {
|
||||
ResizeIndicatorView(active: model.resizing)
|
||||
if pendingFingerprint == nil, model.resizing {
|
||||
ResizeIndicatorView(active: true)
|
||||
.transition(.opacity.combined(with: .scale(scale: 0.92)))
|
||||
}
|
||||
}
|
||||
.animation(.easeInOut(duration: 0.22), value: model.resizing)
|
||||
if let fp = pendingFingerprint {
|
||||
TrustCardView(
|
||||
fingerprint: fp,
|
||||
|
||||
@@ -216,6 +216,10 @@ private final class DeadlineLinkDelegate: NSObject, CAMetalDisplayLinkDelegate {
|
||||
private let renderSignal: DispatchSemaphore
|
||||
private let hint: FrameRateHint
|
||||
private let stats: PresentDebugStats?
|
||||
/// One-shot: log the link's EFFECTIVE preferredFrameLatency after the first re-assert —
|
||||
/// reads 1 while vendLeadMs sits at ~2 periods ⇒ the scheduler ignores the request while
|
||||
/// the layer is composited (the promotion hunt); reads 2 ⇒ the system clamped it outright.
|
||||
private var loggedEffective = false
|
||||
|
||||
init(
|
||||
stash: LatestBox<CAMetalDrawable>, renderSignal: DispatchSemaphore,
|
||||
@@ -235,6 +239,15 @@ private final class DeadlineLinkDelegate: NSObject, CAMetalDisplayLinkDelegate {
|
||||
// before add(to:), and whether a pre-add set survives scheduling is exactly the kind of
|
||||
// thing the vendLeadMs stat exists to catch — belt and braces.
|
||||
if link.preferredFrameLatency != 1 { link.preferredFrameLatency = 1 }
|
||||
if !loggedEffective {
|
||||
loggedEffective = true
|
||||
let range = link.preferredFrameRateRange
|
||||
let msg = String(
|
||||
format: "deadline link up: effective preferredFrameLatency=%.2f "
|
||||
+ "range=%.0f-%.0f preferred=%.0f",
|
||||
link.preferredFrameLatency, range.minimum, range.maximum, range.preferred ?? 0)
|
||||
presentLog.info("\(msg, privacy: .public)")
|
||||
}
|
||||
// The link's own pipeline depth, measured: how far ahead of glass this vend runs.
|
||||
stats?.vendLead(
|
||||
ms: (update.targetPresentationTimestamp - CACurrentMediaTime()) * 1000)
|
||||
|
||||
Reference in New Issue
Block a user