From f35392cd3eabe7181a29f092b9e44b4a8fe5b709 Mon Sep 17 00:00:00 2001 From: arnav-hiwarkar Date: Wed, 11 Nov 2026 11:22:09 +0530 Subject: [PATCH 1/2] #1615: say EFFECTCRAFT_CPU_INFLIGHT caps Render Queue renders and exports, not previews --- docs/preferences.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/preferences.md b/docs/preferences.md index e20084c5f..4e379909a 100644 --- a/docs/preferences.md +++ b/docs/preferences.md @@ -102,10 +102,10 @@ Commands (CLI, MCP, control channel): `EFFECTCRAFT_GPU_INFLIGHT` overrides it. CPU renders have no such setting: they keep one frame per thread in flight, so their memory grows with the core count. Set `EFFECTCRAFT_CPU_INFLIGHT` to a whole number of frames (at least 1) to cap the frames in - flight of every render, `effectcraft-cli render` included - ([#1615](https://github.com/storytold/effectcraft/issues/1615)). One exception: while a job - on GPU Acceleration times both compositors on its first frames, it renders them under the - cap but keeps them all (up to 12) until it has chosen. + flight of every Render Queue render and export, `effectcraft-cli render` included + ([#1615](https://github.com/storytold/effectcraft/issues/1615)); previews don't read it. One + exception: while a job on GPU Acceleration times both compositors on its first frames, it + renders them under the cap but keeps them all (up to 12) until it has chosen. - `threeD.defaultRenderer`: Default 3D Renderer - `labels.N.name` / `labels.N.color`: the 16 label names and colours, used by the Label menu, the timeline, project panel, render queue and viewer handles From 861c65ab26fb676894321fda9fefca7b0219325b Mon Sep 17 00:00:00 2001 From: arnav-hiwarkar Date: Wed, 11 Nov 2026 11:22:09 +0530 Subject: [PATCH 2/2] #3335: document EFFECTCRAFT_RQ_RENDERER and the Render Queue's per-job compositor choice architecture.md and web.md still said every job renders on the project's renderer (#414); since #3335 a GPU job times both compositors on its first frames and keeps the faster. --- docs/architecture.md | 9 ++++++--- docs/preferences.md | 6 +++++- docs/web.md | 6 +++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 195634eb1..f50c38f64 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -340,10 +340,13 @@ whichever compositor measured faster for it (`render::auto::AutoPick`, kept by t per comp, output scale and path (readback or viewer display) it averages CPU and GPU frame times (warm-up on both sides, the fastest warm-up frame starting the average, single stalls capped), picks the GPU unless the CPU is clearly faster, and re-measures the other side every 48 frames. -Render Queue jobs don't use Auto: every frame of a job renders on the project's renderer (the -GPU compositor with GPU Acceleration), so runs of a render don't differ by timing. Light comps (a few small layers, which the CPU composites only within their bounds) then stay on -the CPU instead of paying for full-frame passes and a readback. A GPU frame walks the comp like +the CPU instead of paying for full-frame passes and a readback. Render Queue jobs don't use +Auto per frame: a job renders every frame on one compositor, never a mix (#3335). A GPU +Acceleration job with an accelerator times both on its first frames +(`export::pipeline::Cx::probe`, jobs of 12 frames or more) and keeps the faster, the CPU only +when clearly faster; `EFFECTCRAFT_RQ_RENDERER=gpu|cpu` fixes the choice, and readback-deferred +accelerators (the web) render on the project's renderer. A GPU frame walks the comp like `draw_comp`: cached layer buffers are uploaded once per buffer, then transformed with the CPU's sampling (nearest, bilinear, Catmull-Rom bicubic, the same minification pre-filter), motion-blur sub-samples are accumulated, and track mattes, Preserve Transparency, layer style passes, diff --git a/docs/preferences.md b/docs/preferences.md index 4e379909a..215ada597 100644 --- a/docs/preferences.md +++ b/docs/preferences.md @@ -105,7 +105,11 @@ Commands (CLI, MCP, control channel): flight of every Render Queue render and export, `effectcraft-cli render` included ([#1615](https://github.com/storytold/effectcraft/issues/1615)); previews don't read it. One exception: while a job on GPU Acceleration times both compositors on its first frames, it - renders them under the cap but keeps them all (up to 12) until it has chosen. + renders them under the cap but keeps them all (up to 12) until it has chosen. That timing + picks the compositor that a job of 12 frames or more renders every frame on (the render log + names it and why). `EFFECTCRAFT_RQ_RENDERER` set to `gpu` or `cpu` skips it and renders on + that compositor; `auto` (the default) measures. A queue item's later output modules reuse its + first one's choice, and Software Rendering projects always render on the CPU. - `threeD.defaultRenderer`: Default 3D Renderer - `labels.N.name` / `labels.N.color`: the 16 label names and colours, used by the Label menu, the timeline, project panel, render queue and viewer handles diff --git a/docs/web.md b/docs/web.md index f94a687be..f4eb882a8 100644 --- a/docs/web.md +++ b/docs/web.md @@ -173,9 +173,9 @@ the same futures with `passes::block_on`; they never wait there). - **Render Queue**: `effectcraft_export::export_async` renders each frame in passes (frames with deferred readbacks render one by one instead of in parallel batches) and encodes as - before (`Exporter::export_async`). As on the desktop, a job renders every frame on the - project's renderer (the worker's GPU with GPU Acceleration), not on whichever - compositor measured faster, so runs don't differ by timing. + before (`Exporter::export_async`). Unlike the desktop, which times both compositors on a + job's first frames and keeps the faster, a job renders every frame on the project's renderer + (the worker's GPU with GPU Acceleration), so runs don't differ by timing. - **Analyses** (Warp Stabilizer, 3D Camera Tracker, Track Motion, mask and face tracking, Roto Brush freeze and propagation): their work functions are `async`; started with `wait` inside a job they are queued and awaited (`offload::run_or_queue`), and each input frame renders in