ff-render
GPU compositing and effects pipeline for video, built on [wgpu]. Applies per-frame visual effects (colour grading, blending, masking, chroma key, YUV upload) in a linear render graph that can be attached to ff-preview's PlayerRunner as an opt-in GpuFrameSink.
ff-render is a GPU compositing and effects pipeline built on wgpu, not FFmpeg: WGSL shaders run colour grading, blends, chroma-key, masks, transforms, scaling, and a crossfade transition on GPU textures, with a CPU software fallback. It consumes decoded frames and plugs into ff-preview through the FrameSink trait. Errors are typed and contextual (RenderError), so a shader-compile or device failure reads as an actionable message.
It is an independent crate: use it on its own, or combine it with the other ff-* crates to assemble whatever media application, or editing model, you need. The ff-* crates are purified, model-free primitives, so none imposes an editing model on you; avio is one editing engine built on top of them. Each crate is versioned independently; see crates.io for current versions.
Status
Implemented today: the CPU and GPU render graph (RenderGraph), all built-in nodes listed below, the 18 BlendMode variants (CPU and GPU), the native YUV upload path, the multi-layer Compositor (wgpu feature), and GpuFrameSink for ff-preview integration.
GpuFrameSink is opt-in: you attach it explicitly with runner.set_sink(...). It is not the default preview compositor. avio's standard preview path composites on the CPU today; making GPU compositing the default preview and export compositor across avio is a separate, deferred effort tracked in #1365.
Installation
[]
= "0.16"
# Enable GPU processing (requires wgpu-compatible hardware)
= { = "0.16", = ["wgpu"] }
Feature Flags
| Feature | Description | Default |
|---|---|---|
wgpu |
GPU processing via wgpu (Metal / Vulkan / DX12 / WebGPU) | no |
Without wgpu only the CPU fallback path is available via RenderGraph::process_cpu. The CPU path is suitable for unit tests, CI, and software-only environments.
CPU Path (no wgpu required)
All built-in nodes implement RenderNodeCpu, which processes raw RGBA bytes without any GPU dependency.
use ;
// Build a pipeline: boost brightness then multiply-blend with an overlay.
let overlay_rgba: = /* ... */ vec!;
let graph = new_cpu
.push_cpu
.push_cpu;
let input_rgba: = /* decoded frame */ vec!;
let output: = graph.process_cpu;
GPU Path (wgpu feature)
When the wgpu feature is enabled, nodes run on the GPU via RenderGraph::process_gpu. The same nodes implement both RenderNode (GPU) and RenderNodeCpu (CPU fallback).
use Arc;
use ;
async
Integration with ff-preview
GpuFrameSink implements ff_preview::FrameSink, wiring the render graph directly into a PlayerRunner pipeline.
use Arc;
use ;
use ;
async
Multi-Layer Compositor (wgpu feature)
Compositor accepts a Vec<FrameLayer>, sorts layers by z_order, applies per-layer transforms and blend modes, and returns the composited wgpu::Texture.
use Arc;
use ;
async
Built-in Nodes
| Node | CPU | GPU | Description |
|---|---|---|---|
ColorGradeNode |
✓ | ✓ | Brightness, saturation, contrast, hue shift, colour temperature |
ScaleNode |
passthrough | ✓ | Resize to target dimensions (Bilinear / Nearest) |
OverlayNode |
✓ | ✓ | Alpha-composite a static overlay image over the base |
CrossfadeNode |
✓ | ✓ | Linear crossfade between base and a target image |
BlendModeNode |
✓ | ✓ | Photoshop-style blend modes with per-node opacity |
TransformNode |
passthrough | ✓ | Translate, rotate, and scale the frame in UV space |
ChromaKeyNode |
✓ | ✓ | Chroma key (green screen): removes a specified colour range |
ShapeMaskNode |
✓ | ✓ | Binary alpha mask from an RGBA mask image |
LumaMaskNode |
✓ | ✓ | Luma-derived alpha mask (bright = keep, dark = cut) |
AlphaMatteNode |
✓ | ✓ | Alpha-composite foreground over a background using fg alpha |
YuvUploadNode |
✓ | ✓ | Upload native YUV planes (4:2:0 / 4:2:2 / 4:4:4) without sws_scale |
Blend Modes
BlendModeNode supports the following modes via BlendMode:
Normal · Multiply · Screen · Overlay · SoftLight · HardLight · ColorDodge · ColorBurn · Difference · Exclusion · Add · Subtract · Darken · Lighten · Hue · Saturation · Color · Luminosity
YUV Upload
YuvUploadNode accepts planar YUV data directly, bypassing sws_scale:
use ;
let mut node = new;
node.set_planes;
let graph = new_cpu.push_cpu;
let rgba = graph.process_cpu;
Supported formats: Yuv420p, Yuv422p, Yuv444p.
Error Handling
All fallible operations return RenderError:
use RenderError;
match result
Crate stack
ff-sys → ff-common → ff-format → ff-preview → ff-render
ff-render depends on ff-preview for the FrameSink trait and VideoFrame type. It has no direct dependency on ff-decode or ff-filter; frames can come from any source.