Expand description
§ff-render
GPU compositing pipeline for real-time video preview, built on [wgpu].
ff-render sits above ff-preview in the crate stack and implements
ff_preview::FrameSink so it integrates directly with
ff_preview::PlayerRunner.
§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.
§Usage — wiring to PlayerRunner
ⓘ
use std::sync::Arc;
use ff_preview::{PreviewPlayer, RgbaSink};
use ff_render::context::RenderContext;
use ff_render::graph::RenderGraph;
use ff_render::nodes::ColorGradeNode;
use ff_render::sink::GpuFrameSink;
// 1. Initialise the GPU device (headless — no window required).
let ctx = Arc::new(RenderContext::init().await?);
// 2. Build a render graph: apply a gentle brightness boost.
let graph = RenderGraph::new(Arc::clone(&ctx)).push(ColorGradeNode {
brightness: 0.1,
..Default::default()
});
// 3. Open the player, attach the GPU sink, and run on a dedicated thread.
let downstream = RgbaSink::new();
let handle = downstream.frame_handle();
let (mut runner, _player_handle) = PreviewPlayer::open("clip.mp4")?.split();
runner.set_sink(Box::new(GpuFrameSink::new(graph, Box::new(downstream))));
std::thread::spawn(move || runner.run());
// 4. Retrieve the latest processed frame from any thread.
if let Some(frame) = handle.lock().unwrap().as_ref() {
println!("frame: {}×{} pts={:?}", frame.width, frame.height, frame.pts);
}Re-exports§
pub use error::RenderError;pub use graph::RenderGraph;pub use nodes::AlphaMatteNode;pub use nodes::BlendMode;pub use nodes::BlendModeNode;pub use nodes::ChromaKeyNode;pub use nodes::ColorGradeNode;pub use nodes::CrossfadeNode;pub use nodes::LumaMaskNode;pub use nodes::OverlayNode;pub use nodes::RenderNodeCpu;pub use nodes::ScaleAlgorithm;pub use nodes::ScaleNode;pub use nodes::ShapeMaskNode;pub use nodes::TransformNode;pub use nodes::YuvFormat;pub use nodes::YuvUploadNode;pub use sink::GpuFrameSink;