# 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. ## 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 - compact telemetry - non-GL frame-exchange tests Intentionally not included yet: - DeckLink input - shader package rendering - 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. ## Expected Telemetry 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 `shaders/happy-accident` on a background thread owned by the app orchestration layer. 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. Successful handoff signs: - console prints `Runtime shader committed: happy-accident` - 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 - `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