Skip to main content

ff_render/
lib.rs

1//! # ff-render
2//!
3//! GPU compositing pipeline for real-time video preview, built on [wgpu].
4//!
5//! `ff-render` sits above `ff-preview` in the crate stack and implements
6//! [`ff_preview::FrameSink`] so it integrates directly with
7//! [`ff_preview::PlayerRunner`].
8//!
9//! ## Feature flags
10//!
11//! | Feature | Description | Default |
12//! |---------|-------------|---------|
13//! | `wgpu`  | GPU processing via wgpu (Metal / Vulkan / DX12 / WebGPU) | no |
14//!
15//! Without `wgpu` only the CPU fallback path is available via
16//! [`RenderGraph::process_cpu`].
17//!
18//! ## Usage — wiring to `PlayerRunner`
19//!
20//! ```ignore
21//! use std::sync::Arc;
22//!
23//! use ff_preview::{PreviewPlayer, RgbaSink};
24//! use ff_render::context::RenderContext;
25//! use ff_render::graph::RenderGraph;
26//! use ff_render::nodes::ColorGradeNode;
27//! use ff_render::sink::GpuFrameSink;
28//!
29//! # #[tokio::main]
30//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
31//! // 1. Initialise the GPU device (headless — no window required).
32//! let ctx = Arc::new(RenderContext::init().await?);
33//!
34//! // 2. Build a render graph: apply a gentle brightness boost.
35//! let graph = RenderGraph::new(Arc::clone(&ctx)).push(ColorGradeNode {
36//!     brightness: 0.1,
37//!     ..Default::default()
38//! });
39//!
40//! // 3. Open the player, attach the GPU sink, and run on a dedicated thread.
41//! let downstream = RgbaSink::new();
42//! let handle = downstream.frame_handle();
43//! let (mut runner, _player_handle) = PreviewPlayer::open("clip.mp4")?.split();
44//! runner.set_sink(Box::new(GpuFrameSink::new(graph, Box::new(downstream))));
45//!
46//! std::thread::spawn(move || runner.run());
47//!
48//! // 4. Retrieve the latest processed frame from any thread.
49//! if let Some(frame) = handle.lock().unwrap().as_ref() {
50//!     println!("frame: {}×{} pts={:?}", frame.width, frame.height, frame.pts);
51//! }
52//! # Ok(())
53//! # }
54//! ```
55
56#![warn(clippy::all)]
57#![warn(clippy::pedantic)]
58
59pub mod error;
60pub mod graph;
61pub mod nodes;
62pub mod sink;
63
64#[cfg(feature = "wgpu")]
65pub mod compositor;
66#[cfg(feature = "wgpu")]
67pub mod context;
68
69// ── Top-level re-exports ─────────────────────────────────────────────────────
70
71#[cfg(feature = "wgpu")]
72pub use compositor::{Compositor, FrameLayer, LayerTransform};
73pub use error::RenderError;
74pub use graph::RenderGraph;
75pub use nodes::{
76    AlphaMatteNode, BlendMode, BlendModeNode, ChromaKeyNode, ColorGradeNode, CrossfadeNode,
77    LumaMaskNode, OverlayNode, RenderNodeCpu, ScaleAlgorithm, ScaleNode, ShapeMaskNode,
78    TransformNode, YuvFormat, YuvUploadNode,
79};
80pub use sink::GpuFrameSink;
81
82#[cfg(feature = "wgpu")]
83pub use context::RenderContext;
84#[cfg(feature = "wgpu")]
85pub use nodes::RenderNode;
86#[cfg(feature = "wgpu")]
87pub use sink::TextureHandle;