feat(text): composite shared text rasters in output

Raster static text on UI-thread changes and reuse the same transparent BGRA frame in preview and all compositor paths. Cache text frame identity in the frame-pump signature and invalidate static bakes on edits. Follow OBS text-source conventions: https://obsproject.com/kb/text-sources
This commit is contained in:
2026-11-04 15:01:47 -08:00
parent 58eb640c4e
commit 5c4acf141b
19 changed files with 622 additions and 81 deletions
+8
View File
@@ -381,6 +381,14 @@ seam:** `Func<Scene?>`, `Func<SceneElement, VideoFrame?>` resolver, `Func<Compos
renderer — `Same()` for unchanged inputs, `NotSame()` on message/config change, null on empty).
Accepted cost pending take 6: one slow tick (~15-25ms) per arriving message; if chat-burst frame
loss shows up, the next slice moves the re-render off-tick (debounced, dispatcher-side).
- **TASK 3.17 — static TextOverlay raster-on-change:** `TextOverlayRenderer.UpdatePreview` runs WPF
`FormattedText` + `RenderTargetBitmap` only on the dispatcher when text, formatting, or box size
changes. It publishes one immutable straight-alpha BGRA `VideoFrame` and a `WriteableBitmap`
copied from those same pixels; preview and output therefore share the raster. `FramePump` calls
only `RenderFrame` (a concurrent cache read), never WPF. Text is a static `Source`, so its raster
participates in the static bake or above-split path; property changes invalidate the bake, and the
full-render signature includes the resolved text frame. Its premultiplied WPF readback is
unpremultiplied before entering `VideoFrame`, whose compositor contract is straight-alpha BGRA.
- **Slice 5 — paste cache for non-opaque layers (2026-09-04, take 7/8 data):** the render/resolve
split (added in the stamp commit) finally named the last thing honestly: `resolve ≈ 0` but
`render 26-27ms` (124-135/300, ≈2.2x) — the chat fix HAD worked; the remaining cost was the