vello_cpu/filter/mod.rs
1// Copyright 2025 the Vello Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! Filter effects implementation for `vello_cpu`.
5//!
6//! This module provides CPU-based implementations of SVG filter effects,
7//! supporting both low-precision (u8) and high-precision (f32) rendering paths.
8//! Filters are applied to rendered layer pixmaps and may use scratch storage for
9//! intermediate buffers.
10
11pub(crate) mod context;
12mod drop_shadow;
13mod flood;
14mod gaussian_blur;
15mod offset;
16mod shift;
17
18use context::ScratchBuffer;
19use vello_common::filter::PreparedFilter;
20use vello_common::filter_effects::Filter;
21use vello_common::kurbo::Affine;
22use vello_common::pixmap::Pixmap;
23
24/// Trait for filter effects that can be applied to layers.
25///
26/// Each filter implements this trait with both u8 and f32 variants
27/// to support different rendering backends and precision requirements.
28/// The low-precision path (`execute_lowp`) uses 8-bit color channels for
29/// better performance, while the high-precision path (`execute_highp`)
30/// uses 32-bit floating-point for higher quality at the cost of speed.
31pub(crate) trait FilterEffect {
32 /// Apply the low-precision (u8) version of the filter.
33 ///
34 /// # Arguments
35 /// * `pixmap` - The target pixmap containing rendering metadata
36 /// * `filter_scratch` - Reusable scratch storage for intermediate buffers
37 fn execute_lowp(&self, pixmap: &mut Pixmap, filter_scratch: &mut ScratchBuffer);
38
39 /// Apply the high-precision (f32) version of the filter.
40 ///
41 /// # Arguments
42 /// * `pixmap` - The target pixmap containing rendering metadata
43 /// * `filter_scratch` - Reusable scratch storage for intermediate buffers
44 fn execute_highp(&self, pixmap: &mut Pixmap, filter_scratch: &mut ScratchBuffer);
45}
46
47/// Apply the low-precision (u8) version of a filter effect to a layer.
48///
49/// This function dispatches filter primitives from a filter graph to their
50/// corresponding CPU implementations using 8-bit color channels.
51///
52/// # Arguments
53/// * `filter` - The filter containing the graph of primitives to apply
54/// * `pixmap` - The target pixmap containing rendering metadata
55/// * `filter_scratch` - Reusable scratch storage for intermediate buffers
56/// * `transform` - The transformation matrix to extract scale from for filter parameters
57///
58/// # Limitations
59/// Currently only supports filter graphs with a single primitive.
60/// Multi-primitive filter graphs are not yet implemented.
61pub(crate) fn filter_lowp(
62 filter: &Filter,
63 pixmap: &mut Pixmap,
64 filter_scratch: &mut ScratchBuffer,
65 transform: Affine,
66) {
67 let prepared_filter = PreparedFilter::new(filter, &transform);
68
69 match prepared_filter {
70 PreparedFilter::Flood(flood) => {
71 flood.execute_lowp(pixmap, filter_scratch);
72 }
73 PreparedFilter::GaussianBlur(blur) => {
74 blur.execute_lowp(pixmap, filter_scratch);
75 }
76 PreparedFilter::Offset(offset) => {
77 offset.execute_lowp(pixmap, filter_scratch);
78 }
79 PreparedFilter::DropShadow(drop_shadow) => {
80 drop_shadow.execute_lowp(pixmap, filter_scratch);
81 }
82 }
83}
84
85/// Apply the high-precision (f32) version of a filter effect to a layer.
86///
87/// This function dispatches filter primitives from a filter graph to their
88/// corresponding CPU implementations using 32-bit floating-point color channels.
89///
90/// # Arguments
91/// * `filter` - The filter containing the graph of primitives to apply
92/// * `pixmap` - The target pixmap containing rendering metadata
93/// * `filter_scratch` - Reusable scratch storage for intermediate buffers
94/// * `transform` - The transformation matrix to extract scale from for filter parameters
95///
96/// # Limitations
97/// Currently only supports filter graphs with a single primitive.
98/// Multi-primitive filter graphs are not yet implemented.
99pub(crate) fn filter_highp(
100 filter: &Filter,
101 pixmap: &mut Pixmap,
102 filter_scratch: &mut ScratchBuffer,
103 transform: Affine,
104) {
105 let prepared_filter = PreparedFilter::new(filter, &transform);
106
107 match prepared_filter {
108 PreparedFilter::Flood(flood) => {
109 flood.execute_highp(pixmap, filter_scratch);
110 }
111 PreparedFilter::GaussianBlur(blur) => {
112 blur.execute_highp(pixmap, filter_scratch);
113 }
114 PreparedFilter::Offset(offset) => {
115 offset.execute_highp(pixmap, filter_scratch);
116 }
117 PreparedFilter::DropShadow(drop_shadow) => {
118 drop_shadow.execute_highp(pixmap, filter_scratch);
119 }
120 }
121}