mirror of
https://github.com/storytold/filmcraft.git
synced 2026-11-07 12:12:37 +00:00
* render, gpu: adjustment layers composited on the GPU An adjustment layer anywhere at a time sent the whole frame to the CPU renderer, so GPU rendering did nothing for the frames under one. A full-frame adjustment layer at 100 % opacity, Normal, unmasked and with only effects the GPU stage runs is now a PlanStep::Adjust: its effects run in the effect stage on the accumulator (the composite of the tracks below) and the result replaces it before the tracks above are drawn. Every other adjustment layer keeps the whole-frame CPU fallback. The export renderer takes Composite plans without transitions; frames with a Push still go to the CPU there, as before. perf.stats gpu gains adjustments / cpuAdjustments. * docs: adjustment layers on the GPU compositor in parity and performance hardware-parity.md gains an Adjustment layers row; performance.md gains the main-against-branch export timings with an adjustment layer. * render, gpu: adjustment layer review fixes - is_cpu_frame and plan_frame now ask the same adjustment_ops (evaluated at the render scale, which is_cpu_frame takes from the RenderOptions): a Transform that shrinks the frame no longer takes a pooled export renderer only to be rendered on the CPU and counted as a GPU frame. - FxOp::eval leaves a Transform with its shutter angle on (motion blur) to the CPU; the GPU drew it sharp, on clips and adjustment layers. - The effect stage's texture pool spans the whole composite frame, so an adjustment step's working textures are reused instead of made again every frame. Composite plans honour resolve = false (export). - ExportRenderer::render hands frames with an adjustment layer back to the CPU when the device has no effect stage, instead of compositing them on the CPU and uploading the result to read it back. - adjustment_covers_output checks the full-frame geometry without building the coverage image. - The GPU adjustment test also runs without an effect stage. * render, gpu, export, ui: plan adjustment layers for the device's caps plan_frame and is_cpu_frame take plan::DeviceCaps (how large a frame the device runs adjustment layers on; none without an effect stage), so a frame the compositing device can't adjust becomes a CPU image on the thread that plans it, never on the UI thread or inside a renderer slot. - Monitor: the caps are part of the frame key (Target::SequencePlan(seq, caps)), so a plan made for another device is never reused. - Export: FrameRenderer::caps is required; the renderer pool plans with the smallest caps of its renderers before it takes one. - The compositor's own CPU fallback stays as a safety net for a plan made for other caps; the tests check that nothing reaches it. - Main's own-shutter Transform check replaces the duplicate guard in gpufx. Tests: a Push under an adjustment layer exported on the GPU against render_sequence (forward and reversed, scales 1 and 0.5); routing without an effect stage in the export pipeline and in the monitor's frame server; GPU parity against render_sequence with colour and alpha for a partly transparent canvas, stacked adjustment layers, an empty canvas, a nested sequence below and one inside a nest, at scales 1 and 0.5; caps boundaries and is_cpu_frame agreeing with plan_frame. * gpu: end a refused effect image's frame; count steps once drawn effect_image began an effect stage frame and returned without ending it when the stage refused the job, so the stage stayed mid-frame and kept its working images. The compositor's step counters are added once the whole frame is drawn on the GPU, so a frame that falls back half way no longer counts the steps it threw away.