ff_render/nodes/mod.rs
1pub mod blur;
2pub mod color_grade;
3pub mod color_wheels;
4pub mod composite;
5pub mod crossfade;
6pub mod curves;
7pub mod film_grain;
8pub mod glow;
9pub mod hsl;
10pub mod lut;
11pub mod overlay;
12pub mod scale;
13pub mod transition;
14pub mod upload;
15pub mod vignette;
16
17pub use blur::{GaussianBlurNode, MotionBlurNode, SharpenNode};
18pub use color_grade::ColorGradeNode;
19pub use color_wheels::ColorWheelsNode;
20pub use composite::{
21 AlphaMatteNode, BlendMode, BlendModeNode, ChromaKeyNode, CompositeOp, LumaMaskNode,
22 ShapeMaskNode, TransformNode,
23};
24pub use crossfade::CrossfadeNode;
25pub use curves::CurvesNode;
26pub use film_grain::FilmGrainNode;
27pub use glow::GlowNode;
28pub use hsl::HslNode;
29pub use lut::LutNode;
30pub use overlay::OverlayNode;
31pub use scale::{ScaleAlgorithm, ScaleNode};
32pub use transition::{
33 DipToColorNode, DissolveTransitionNode, FadeTransitionNode, WipeTransitionNode,
34};
35pub use upload::{YuvFormat, YuvUploadNode};
36pub use vignette::VignetteNode;
37
38// RenderNodeCpu
39
40/// CPU fallback processing for a render node.
41///
42/// Implemented by all built-in nodes. Nodes that do not change frame
43/// dimensions modify `rgba` in-place. Multi-input nodes (e.g. [`CrossfadeNode`])
44/// store their secondary inputs as fields and access them during `process_cpu`.
45pub trait RenderNodeCpu: Send {
46 /// Process `rgba` in-place.
47 ///
48 /// `rgba` is a row-major RGBA buffer of size `w × h × 4` bytes.
49 /// Nodes that cannot implement a CPU path leave `rgba` unchanged.
50 fn process_cpu(&self, rgba: &mut [u8], w: u32, h: u32);
51}
52
53/// A parameter a node accepts per frame without being rebuilt.
54///
55/// This exists for **stateful** nodes. A node whose output depends only on its
56/// parameters can simply be rebuilt when one changes; [`MotionBlurNode`] cannot,
57/// because rebuilding discards the exposure trail that is the whole point of it.
58/// So the parameter travels to the live node instead.
59///
60/// Non-exhaustive: more animatable parameters join it as they are needed.
61#[derive(Debug, Clone, Copy, PartialEq)]
62#[non_exhaustive]
63pub enum NodeParam {
64 /// [`MotionBlurNode`]'s shutter angle in degrees.
65 MotionBlurShutter(f32),
66 /// [`ShapeMaskNode`]'s rectangle, in source-frame pixels, and whether it is
67 /// inverted. The shader evaluates the rectangle, so moving it is a parameter
68 /// change rather than a rebuild.
69 ShapeMaskRect {
70 /// Left edge.
71 x: u32,
72 /// Top edge.
73 y: u32,
74 /// Width in pixels.
75 width: u32,
76 /// Height in pixels.
77 height: u32,
78 /// Keep outside the rectangle instead of inside.
79 invert: bool,
80 },
81}
82
83// RenderNode
84
85/// GPU render node. Extends [`RenderNodeCpu`] so both paths are available.
86///
87/// Each node is responsible for creating and caching its own wgpu pipeline
88/// on first use. The pipeline is stored in a [`std::sync::OnceLock`] field
89/// so it is created exactly once per node instance.
90///
91/// `process` may submit one or more `wgpu::CommandEncoder` buffers. The
92/// [`RenderGraph`](crate::graph::RenderGraph) guarantees that the queue
93/// processes them in submission order.
94#[cfg(feature = "wgpu")]
95pub trait RenderNode: RenderNodeCpu {
96 /// Number of input textures required by this node (default: 1).
97 fn input_count(&self) -> usize {
98 1
99 }
100
101 /// Number of render passes (default: 1). Multi-pass nodes (e.g. gaussian
102 /// blur) return 2 or more.
103 fn pass_count(&self) -> usize {
104 1
105 }
106
107 /// Output dimensions this node produces given its input dimensions.
108 ///
109 /// Default: unchanged (`(in_w, in_h)`). A resampling node (e.g.
110 /// [`ScaleNode`]) overrides this so the executor allocates its output target
111 /// — and every following node's input — at the new size. All of a node's
112 /// `pass_count()` targets are allocated at this size.
113 fn output_dimensions(&self, in_w: u32, in_h: u32) -> (u32, u32) {
114 (in_w, in_h)
115 }
116
117 /// Run the GPU render pass.
118 ///
119 /// `inputs` has `input_count()` textures: `inputs[0]` is the previous node's
120 /// final-pass output (or the source frame for the first node), and
121 /// `inputs[1..]` are the original source frame. `outputs` has `pass_count()`
122 /// pre-allocated `Rgba8Unorm` targets; write the final result into
123 /// `outputs[pass_count()-1]`, which the executor feeds to the next node.
124 fn process(
125 &self,
126 inputs: &[&wgpu::Texture],
127 outputs: &[&wgpu::Texture],
128 ctx: &crate::context::RenderContext,
129 );
130
131 /// Applies `param` to this node in place, returning whether it was taken.
132 ///
133 /// Takes `&self` because the caller only ever holds the graph, and because a
134 /// node that accepts a parameter is by nature one that already carries interior
135 /// mutability for its state.
136 ///
137 /// Defaults to `false`: a node that does not name a parameter is unaffected by
138 /// one, and a caller can tell nothing was applied.
139 fn set_param(&self, _param: NodeParam) -> bool {
140 false
141 }
142}