# RenderCadenceCompositor This app is the modular version of the working DeckLink render-cadence probe. Its job is to prove the production-facing foundation before the current compositor's shader/runtime/control features are ported over. Before adding features here, read the guardrails in [Render Cadence Golden Rules](../../docs/RENDER_CADENCE_GOLDEN_RULES.md). ## Architecture ```text RenderThread owns a hidden OpenGL context renders simple BGRA8 motion at selected cadence queues async PBO readback publishes completed frames into SystemFrameExchange SystemFrameExchange owns Free / Rendering / Completed / Scheduled slots drops old completed unscheduled frames when render needs space protects scheduled frames until DeckLink completion DeckLinkOutputThread consumes completed system-memory frames schedules them into DeckLink up to target depth never renders ``` Startup warms up real rendered frames before DeckLink scheduled playback starts. ## Current Scope Included now: - output-only DeckLink - hidden render-thread-owned OpenGL context - simple smooth-motion renderer - BGRA8-only output - async PBO readback - latest-N system-memory frame exchange - rendered-frame warmup - background Slang compile of `shaders/happy-accident` - app-owned submission of a completed shader artifact - render-thread-only GL commit once the artifact is ready - manifest-driven stateless single-pass shader packages - default float, vec2, color, boolean, enum, and trigger parameters - small JSON writer for future HTTP/WebSocket payloads - JSON serialization for cadence telemetry snapshots - background logging with `log`, `warning`, and `error` levels - compact telemetry - non-GL frame-exchange tests Intentionally not included yet: - DeckLink input - multipass shader rendering - temporal/history/feedback shader storage - texture/LUT asset upload - text-parameter rasterization - runtime state - OSC/API control - preview - screenshots - persistence Those features should be ported only after the cadence spine is stable. ## Build ```powershell cmake --build --preset build-debug --target RenderCadenceCompositor -- /m:1 ``` The executable is: ```text build\vs2022-x64-debug\Debug\RenderCadenceCompositor.exe ``` ## Run Run from VS Code with: ```text Debug RenderCadenceCompositor ``` Or from a terminal: ```powershell build\vs2022-x64-debug\Debug\RenderCadenceCompositor.exe ``` Press Enter to stop. To test a different compatible shader package: ```powershell build\vs2022-x64-debug\Debug\RenderCadenceCompositor.exe --shader solid-color ``` Use `--no-shader` to keep the simple motion fallback only. ## Expected Telemetry Startup, shutdown, shader-build, and render-thread event messages are written through the app logger. Telemetry is intentionally separate and remains a compact once-per-second cadence line. The logger writes to the console, `OutputDebugStringA`, and `logs/render-cadence-compositor.log` by default. Render-thread log calls use the non-blocking path so diagnostics do not become cadence blockers. The app prints one line per second: ```text renderFps=59.9 scheduleFps=59.9 free=7 completed=1 scheduled=4 completedPollMisses=0 scheduleFailures=0 completions=119 late=0 dropped=0 shaderCommitted=1 shaderFailures=0 decklinkBuffered=4 scheduleCallMs=0.0 ``` Healthy first-run signs: - visible DeckLink output is smooth - `renderFps` is close to the selected cadence - `scheduleFps` is close to the selected cadence after warmup - `scheduled` stays near 4 - `decklinkBuffered` stays near 4 when available - `late` and `dropped` do not increase continuously - `scheduleFailures` does not increase - `shaderCommitted` becomes `1` after the background Happy Accident compile completes - `shaderFailures` remains `0` `completedPollMisses` means the DeckLink scheduling thread woke up before a completed frame was available. It is not a DeckLink playout underrun by itself. Treat it as healthy polling noise when `scheduled`, `decklinkBuffered`, `late`, `dropped`, and `scheduleFailures` remain stable. ## Runtime Slang Shader Test On startup the app begins compiling the selected shader package on a background thread owned by the app orchestration layer. The default is `shaders/happy-accident`. The render thread keeps drawing the simple motion renderer while Slang compiles. It does not choose packages, launch Slang, or track build lifecycle. It only receives a completed shader artifact and attempts the OpenGL shader compile/link at a frame boundary. If either the Slang build or GL commit fails, the app keeps rendering the simple motion fallback. Current runtime shader support is deliberately limited to stateless single-pass packages: - one pass only - no temporal history - no feedback storage - no texture/LUT assets yet - no text parameters yet - manifest defaults are used for parameters - `gVideoInput` and `gLayerInput` are bound to a small fallback source texture until DeckLink input is added Successful handoff signs: - telemetry shows `shaderCommitted=1` - output changes from the simple motion pattern to the Happy Accident shader - render/schedule cadence remains near 60 fps during and after the handoff - DeckLink buffer remains stable ## Baseline Result Date: 2026-05-12 User-visible result: - output was smooth - DeckLink held a 4-frame buffer Representative telemetry: ```text renderFps=59.9 scheduleFps=59.9 free=8 completed=0 scheduled=4 completedPollMisses=30 scheduleFailures=0 completions=720 late=0 dropped=0 decklinkBuffered=4 scheduleCallMs=1.2 renderFps=59.8 scheduleFps=59.8 free=7 completed=1 scheduled=4 completedPollMisses=36 scheduleFailures=0 completions=1080 late=0 dropped=0 decklinkBuffered=4 scheduleCallMs=4.7 renderFps=59.9 scheduleFps=59.9 free=7 completed=1 scheduled=4 completedPollMisses=86 scheduleFailures=0 completions=1381 late=0 dropped=0 decklinkBuffered=4 scheduleCallMs=2.1 ``` Read: - render cadence and DeckLink schedule cadence both held roughly 60 fps - app scheduled depth stayed at 4 - actual DeckLink buffered depth stayed at 4 - no late frames, dropped frames, or schedule failures were observed - completed poll misses were benign because playout remained fully fed ## Tests ```powershell cmake --build --preset build-debug --target RenderCadenceCompositorFrameExchangeTests -- /m:1 ctest --test-dir build\vs2022-x64-debug -C Debug -R RenderCadenceCompositorFrameExchangeTests --output-on-failure ``` ## Relationship To The Probe `apps/DeckLinkRenderCadenceProbe` proved the timing model in one compact file. This app keeps the same core behavior but splits it into modules that can grow: - `frames/`: system-memory handoff - `platform/`: COM/Win32/hidden GL context support - `render/`: cadence, simple rendering, PBO readback - `json/`: compact JSON serialization helpers - `video/`: DeckLink output wrapper and scheduling thread - `telemetry/`: cadence telemetry - `app/`: startup/shutdown orchestration ## Next Porting Steps Only after this app matches the probe's smooth output: 1. replace `SimpleMotionRenderer` with a render-scene interface 2. port shader package rendering 3. port runtime snapshots/live state 4. add control services 5. add preview/screenshot from system-memory frames 6. add DeckLink input as a CPU latest-frame mailbox