docs update
This commit is contained in:
@@ -10,7 +10,10 @@ The active plan for tightening render-thread ownership is:
|
||||
|
||||
The plan for building a fresh modular app around the proven probe architecture is:
|
||||
|
||||
- [New Render Cadence App Plan](NEW_RENDER_CADENCE_APP_PLAN.md)
|
||||
- [RenderCadenceCompositor README](../apps/RenderCadenceCompositor/README.md)
|
||||
- [Render Cadence Golden Rules](RENDER_CADENCE_GOLDEN_RULES.md)
|
||||
|
||||
`NEW_RENDER_CADENCE_APP_PLAN.md` remains as historical planning context, but the README and golden rules are the current contract for the new cadence-first app.
|
||||
|
||||
## Application Shape
|
||||
|
||||
@@ -287,7 +290,7 @@ Slots have four states:
|
||||
- `Completed`
|
||||
- `Scheduled`
|
||||
|
||||
Completed-but-unscheduled frames are treated as a latest-N cache. If render cadence needs space and old completed frames have not been scheduled, the oldest unscheduled completed frame can be recycled.
|
||||
In the current legacy app, completed-but-unscheduled frames are treated as a latest-N cache. The newer `RenderCadenceCompositor` uses a bounded FIFO completed reserve instead; see its README for the cadence-first contract.
|
||||
|
||||
Scheduled frames are protected until DeckLink reports completion.
|
||||
|
||||
@@ -295,7 +298,7 @@ Scheduled frames are protected until DeckLink reports completion.
|
||||
|
||||
`RenderOutputQueue` holds completed unscheduled output frames waiting to be scheduled.
|
||||
|
||||
It is bounded and latest-N:
|
||||
In the legacy app it is bounded and latest-N:
|
||||
|
||||
- pushing beyond capacity releases/drops the oldest ready frame
|
||||
- `DropOldestFrame()` is used when the frame pool needs to recycle old completed work
|
||||
@@ -363,7 +366,7 @@ The probe does not use the main runtime, shader system, preview path, input uplo
|
||||
- one OpenGL render thread with its own hidden GL context
|
||||
- simple BGRA8 motion rendering
|
||||
- async PBO readback
|
||||
- latest-N system-memory frame slots
|
||||
- legacy latest-N system-memory frame slots; bounded FIFO completed reserve in `RenderCadenceCompositor`
|
||||
- a playout thread that feeds DeckLink
|
||||
- real rendered warmup before scheduled playback
|
||||
|
||||
@@ -531,7 +534,7 @@ When `VST_DISABLE_INPUT_CAPTURE=1`, this flow is skipped.
|
||||
- Keep one owner for each kind of state.
|
||||
- Keep GL work on the render thread.
|
||||
- Keep DeckLink completion callbacks passive.
|
||||
- Treat completed unscheduled output frames as latest-N cache entries.
|
||||
- In the legacy app, treat completed unscheduled output frames as latest-N cache entries; in `RenderCadenceCompositor`, preserve completed frames as a bounded FIFO reserve.
|
||||
- Protect scheduled output frames until DeckLink completion.
|
||||
- Keep output timing more important than preview/screenshot.
|
||||
- Measure timing by domain instead of adding fallback branches blindly.
|
||||
|
||||
@@ -115,6 +115,24 @@ Lesson:
|
||||
- keep synthetic counters only as diagnostics
|
||||
- do not infer device health from internal stream indexes alone
|
||||
|
||||
### Schedule Cursor Recovery Must Be Conservative
|
||||
|
||||
The DeckLink schedule cursor should normally advance as a continuous stream timeline. Continuously realigning the next scheduled stream time to the sampled playback cursor can create its own timing fault: output may look like low FPS even when render and scheduling counters average 59.94/60 fps.
|
||||
|
||||
What worked better:
|
||||
|
||||
- use the exact DeckLink frame duration for the render cadence
|
||||
- keep healthy scheduling on a continuous stream cursor
|
||||
- measure schedule lead from DeckLink playback time versus the next schedule time
|
||||
- realign only after real pressure, such as a late/drop report or dangerously low measured lead
|
||||
- re-arm proactive realignment only after lead has recovered
|
||||
|
||||
Lesson:
|
||||
|
||||
- schedule recovery is an output-edge safety valve, not a per-frame timing policy
|
||||
- if recovery increments continuously, the recovery path has become the problem
|
||||
- include schedule lead and realignment count in telemetry/logs so drift is visible before guessing
|
||||
|
||||
### More Buffer Is Not Automatically Smoother
|
||||
|
||||
Increasing DeckLink scheduled frames sometimes made the reported device buffer look healthier while visible motion still stuttered.
|
||||
@@ -196,7 +214,7 @@ Lesson:
|
||||
|
||||
- system-memory slots are the contract between render and playout
|
||||
- scheduled slots must not be recycled early
|
||||
- completed-but-unscheduled slots can be latest-N cache entries
|
||||
- completed-but-unscheduled slots should form a bounded FIFO reserve for playout
|
||||
|
||||
### Startup Needs Real Preroll
|
||||
|
||||
@@ -222,18 +240,18 @@ Lesson:
|
||||
|
||||
The app has at least two important frame stores:
|
||||
|
||||
- system-memory completed/latest-N frames
|
||||
- system-memory completed FIFO reserve frames
|
||||
- DeckLink scheduled/device buffer
|
||||
|
||||
They have different ownership rules.
|
||||
|
||||
Completed-but-unscheduled frames are disposable if a newer frame is available and cadence needs the slot.
|
||||
Completed-but-unscheduled frames should be a bounded FIFO reserve for playout. If that reserve overflows, dropping the oldest completed frame is an app-side reserve policy and should be counted separately from DeckLink dropped frames.
|
||||
|
||||
Scheduled frames are not disposable because DeckLink may still read them.
|
||||
|
||||
Lesson:
|
||||
|
||||
- latest-N completed frames are a cache
|
||||
- completed frames waiting for playout are a bounded FIFO reserve
|
||||
- scheduled frames are owned by DeckLink until completion
|
||||
- keep metrics for both
|
||||
|
||||
@@ -246,7 +264,8 @@ That couples the clocks again.
|
||||
Lesson:
|
||||
|
||||
- render cadence should keep rendering at selected cadence
|
||||
- if completed cache is full, recycle/drop the oldest unscheduled completed frame
|
||||
- render acquire should not evict completed frames that are waiting for playout
|
||||
- if the completed reserve overflows, drop/count the oldest unscheduled completed frame
|
||||
- only scheduled/in-flight saturation should prevent rendering to a safe slot
|
||||
|
||||
## Render Thread Lessons
|
||||
@@ -340,7 +359,7 @@ The current direction is still sound:
|
||||
```text
|
||||
Render cadence loop
|
||||
renders at selected output cadence
|
||||
writes latest-N completed system-memory frames
|
||||
writes completed system-memory frames into a bounded FIFO reserve
|
||||
never sprints to refill DeckLink
|
||||
|
||||
Frame store
|
||||
@@ -387,7 +406,7 @@ A full rewrite becomes attractive only if the current GL ownership model cannot
|
||||
- Render cadence is time-driven, not completion-driven.
|
||||
- DeckLink scheduling is device-buffer-driven, not render-driven.
|
||||
- Completion callbacks release and report; they do not render.
|
||||
- System-memory completed frames are latest-N cache entries.
|
||||
- System-memory completed frames are a bounded FIFO reserve.
|
||||
- Scheduled frames are protected until DeckLink completion.
|
||||
- Startup uses real rendered warmup/preroll.
|
||||
- Black fallback is degraded/error behavior, not steady-state behavior.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# New Render Cadence App Plan
|
||||
|
||||
Status: historical implementation plan. `apps/RenderCadenceCompositor` now exists; use [apps/RenderCadenceCompositor/README.md](../apps/RenderCadenceCompositor/README.md) and [Render Cadence Golden Rules](RENDER_CADENCE_GOLDEN_RULES.md) as the current implementation contract.
|
||||
|
||||
This plan describes a new application folder that rebuilds the output path from the proven `DeckLinkRenderCadenceProbe` architecture, but as a maintainable app foundation rather than a monolithic probe file.
|
||||
|
||||
The first goal is not to port the current compositor feature set. The first goal is to reproduce the probe's smooth 59.94/60 fps DeckLink output with clean module boundaries, tests where possible, and a structure that can later accept the shader/runtime/control systems without compromising timing.
|
||||
@@ -43,7 +45,7 @@ Render cadence thread
|
||||
|
||||
System frame exchange
|
||||
-> owns Free / Rendering / Completed / Scheduled slots
|
||||
-> latest-N semantics for completed unscheduled frames
|
||||
-> bounded FIFO reserve for completed unscheduled frames
|
||||
-> protects scheduled frames until DeckLink completion
|
||||
|
||||
DeckLink output thread
|
||||
@@ -63,7 +65,7 @@ Everything else must fit around that spine.
|
||||
- Completion callbacks never render.
|
||||
- No synchronous render request exists in the output path.
|
||||
- Preview, screenshot, input upload, shader rebuild, and runtime control cannot run ahead of a due output frame.
|
||||
- Completed unscheduled frames are latest-N and disposable.
|
||||
- Completed unscheduled frames are a bounded FIFO reserve; overflow drops are counted separately from DeckLink drops.
|
||||
- Scheduled frames are protected until DeckLink completion.
|
||||
- Startup warms up real rendered frames before scheduled playback starts.
|
||||
|
||||
@@ -77,7 +79,7 @@ Keep these behaviors from `DeckLinkRenderCadenceProbe`:
|
||||
- PBO ring readback
|
||||
- non-blocking fence polling with zero timeout
|
||||
- system-memory slots with `Free`, `Rendering`, `Completed`, `Scheduled`
|
||||
- drop oldest completed unscheduled frame if render needs space
|
||||
- preserve completed frames waiting for playout; drop/count the oldest completed frame only if the bounded reserve overflows
|
||||
- DeckLink playout thread only schedules completed frames
|
||||
- warmup completed frames before `StartScheduledPlayback()`
|
||||
- one-line-per-second timing telemetry
|
||||
@@ -430,7 +432,7 @@ Feature set:
|
||||
- simple motion renderer
|
||||
- BGRA8 only
|
||||
- PBO async readback
|
||||
- latest-N system-memory frame exchange
|
||||
- bounded FIFO system-memory frame exchange
|
||||
- warmup before playback
|
||||
- one-line telemetry
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ The output/scheduling side may:
|
||||
- release frames after DeckLink completion
|
||||
- report late/dropped/schedule telemetry
|
||||
- record app-side poll misses
|
||||
- conservatively realign the DeckLink schedule cursor after measured timing pressure
|
||||
|
||||
It must not:
|
||||
|
||||
@@ -55,6 +56,7 @@ It must not:
|
||||
- invoke GL
|
||||
- compile shaders
|
||||
- block the render cadence waiting for DeckLink
|
||||
- continuously rewrite healthy scheduled timestamps
|
||||
|
||||
If no completed frame is available, record the miss and keep the ownership boundary intact.
|
||||
|
||||
@@ -93,9 +95,11 @@ Short mutex use for exchanging small already-prepared objects is acceptable. Hol
|
||||
|
||||
## 6. System Memory Frames Are A Handoff, Not A Render Driver
|
||||
|
||||
The system-memory frame exchange stores the latest rendered frames and protects frames scheduled to DeckLink.
|
||||
The system-memory frame exchange stores completed frames as a bounded FIFO reserve and protects frames scheduled to DeckLink.
|
||||
|
||||
It may drop old completed, unscheduled frames when the render thread needs a free slot. It must never force the render thread to wait for the output side to consume a frame.
|
||||
Render acquire must not evict completed frames that are waiting for playout, and it must never force the render thread to wait for the output side to consume a frame.
|
||||
|
||||
If the completed reserve overflows, the exchange may drop the oldest completed, unscheduled frame and record `completedDrops`. That is an app-side reserve drop, not a DeckLink dropped frame.
|
||||
|
||||
## 7. Startup Uses Warmup, Not Burst Rendering
|
||||
|
||||
@@ -114,6 +118,8 @@ Good examples:
|
||||
- `completedPollMisses`
|
||||
- `scheduleFailures`
|
||||
- `decklinkBuffered`
|
||||
- `deckLinkScheduleLeadFrames`
|
||||
- `deckLinkScheduleRealignments`
|
||||
- `inputCaptureFps`
|
||||
- `inputSubmitMs`
|
||||
- `inputUploadMs`
|
||||
|
||||
@@ -98,7 +98,7 @@ render cadence thread
|
||||
-> samples latest render input/state
|
||||
-> renders one frame
|
||||
-> queues async readback/copies completed readback into system-memory slot
|
||||
-> publishes completed frame to latest-N output buffer
|
||||
-> publishes completed frame to bounded FIFO output reserve
|
||||
|
||||
video output thread
|
||||
-> consumes completed system-memory frames
|
||||
|
||||
Reference in New Issue
Block a user