perf(capture): slice 8 — buffer ring + paste-cache Epoch; gen2 visibility (take-11 spikes)
Take 11 (c10ce06c) validated the off-UI architecture: typical frames land work ~10ms + wait ~6.8ms = 16.7 exactly on the deadline; 212/300 best yet. The ENTIRE remaining gap is periodic 35-65ms render spikes that WORSENED across the take (189 -> 147) — the signature of gen2 GC pauses. Biggest churner is structural: the screen capture minted a fresh ~8.3MB byte[] per DWM frame (~500MB/s of LOH), a producer OBS never does (it owns fixed surface pools). - ScreenCaptureFrameSource: 4-deep buffer ring with size-matched slots (a <=17ms consumer cannot be lapped at 60Hz) + reused downscale row scratch. - VideoFrame.Epoch: monotonic per producer frame. The paste cache keys on array IDENTITY, so recycled arrays MUST be distinguished — epoch joins the PasteKey. Producers handing fresh arrays leave it 0 (key unchanged effect). - Stats print 'gen2 +N' per 5s window: next take acquits or convicts GC without another guess (rule: prove the stage). - Test (the ONE): PasteCache_RecycledArrayWithNewEpoch_ReRasterizes_NotStaleHits — same array, new content, bumped epoch; fails on the old key by construction. 37/37 compositor/pump, clean build. - Next suspect if gen2 stays hot: the 10Hz WebView2 capture (full-canvas PNG decode + fresh arrays on the UI thread) — recorded, untouched. Creator audio ask queued in the same working session (+40% post-mix master gain before the -1dBFS limiter) lands as its own commit next.
This commit is contained in:
+18
-6
@@ -60,12 +60,24 @@ RealApp boot-smoke. Scope-check passed.
|
||||
`avg wait` so render+submit+wait ≈ period (accounting closed — nothing can hide). Webcam now
|
||||
routes through the paste cache too (bypass re-sampled 156k px even between identical device
|
||||
frames). 52/52 per-class green, clean build 0 warnings, committed this slice.
|
||||
4. **Take 11 (user, ~30s record-only):** read the superscript; expect `≈300/300 frames, wait ≈ the true remainder, worst render` now visible. If ~300: playback must be honest 1x — saga CLOSED, Unit B starts. If still ~250-280 with worst-render spikes: raster-miss spikes (web capture ~ every second) — next slice is pre-rasterizing on content change rather than on first-tick-after-change (cache the miss behind a swap-in). If wait is STILL large: the context theory was wrong and I have egg to eat — re-instrument, don't guess.
|
||||
~22, wait ~0-3` — honest 60fps IF render+submit ≤ ~16.7. If wait is near zero and n/300 sits at
|
||||
~200, the remaining gap is pure render 22ms → next slice = per-phase compositor timing (the stats
|
||||
can split blit phases the same way they split resolve; that is the honest path, not a guess).
|
||||
If take 10 lands at ~300/300 → recording saga CLOSED.
|
||||
5. **Unit B — the top bar + session logic (user spec 2026-09-04 re-sent twice + decisions settled in Q&A):**
|
||||
4. **Take 11 ran + slice 8 (2026-09-04, committed with the audio unit below):** off-UI loop
|
||||
WORKED — typical frames land exactly on the deadline (work ~10 + wait ~6.8 = 16.7; 212/300).
|
||||
Remaining gap = periodic 35-65ms spikes growing across the take = gen2 GC pauses; the capture
|
||||
path minted a fresh ~8.3MB byte[] per DWM frame (~500MB/s LOH). Slice 8: 4-deep buffer ring
|
||||
in ScreenCaptureFrameSource (size-matched slots, reused row scratch) + `VideoFrame.Epoch`
|
||||
joins the paste-cache key so recycled arrays can never false-hit + `gen2 +N` per stats window
|
||||
(suspect-or-acquit — never guess at the tail again). Test `PasteCache_RecycledArrayWithNewEpoch_
|
||||
ReRasterizes_NotStaleHits` fails on the old key by construction. 37/37 compositor/pump green.
|
||||
4b. **AUDIO (creator ask 2026-09-04):** post-mix volume up ~40% — constant master gain applied
|
||||
in AudioMixer.FillAndMix BEFORE the −1 dBFS limiter (limiter still owns the ceiling: the
|
||||
gain can't add clipping, it just makes the limiter bind sooner on hot material). If the
|
||||
creator reports pumping on loud game audio → the constant is the tuning knob (or per-input
|
||||
defaults need raising instead — discuss with data).
|
||||
5. **Take 12 (user, ~30s record + talk):** stats: `gen2 +N` should be ~0-1/window, `worst render`
|
||||
→ ~16-20ms, n/300 → 300; playback honest speed; file audio ~40% hotter than before. If gen2
|
||||
still >2/window: next suspect is the 10Hz WebView2 capture (full-canvas PNG decode + fresh
|
||||
arrays on the UI thread) — throttle or move it, cited pattern first.
|
||||
6. **Unit B — the top bar + session logic (user spec 2026-09-04 re-sent twice + decisions settled in Q&A):**
|
||||
- Two-line top bar. Line 1: center = REC + **LIVE** pills (text renamed from ON-AIR; pills become
|
||||
mutually-exclusive RADIOS — record-OR-stream ruling), right = avatar + **Login/Logout** button
|
||||
(no account status light). Line 2: centered primary **Start** (grayed while NO pill armed —
|
||||
|
||||
Reference in New Issue
Block a user