vello_cpu/lib.rs
1// Copyright 2025 the Vello Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4// After you edit the crate's doc comment, run this command, then check README.md for any missing links
5// cargo rdme --workspace-project=vello_cpu
6
7//! Vello CPU is a 2D graphics rendering engine written in Rust, for devices with no or underpowered GPUs.
8//!
9//! We also develop [Vello](https://crates.io/crates/vello), which makes use of the GPU for 2D rendering and has higher performance than Vello CPU.
10//! Vello CPU is being developed as part of work to address shortcomings in Vello.
11//!
12//! # Usage
13//!
14//! To use Vello CPU, you need to:
15//!
16//! - Create a [`RenderContext`][], a 2D drawing context for a fixed-size scene area.
17//! - For each object in your scene:
18//! - Set how the object will be painted, using [`set_paint`][RenderContext::set_paint].
19//! - Set the shape to be drawn for that object, using methods like [`fill_path`][RenderContext::fill_path],
20//! [`stroke_path`][RenderContext::stroke_path], or [`glyph_run`][RenderContext::glyph_run].
21//! - Render it to an image using [`RenderContext::render`][].
22//!
23//! ```rust
24//! use vello_cpu::{RenderContext, Resources, Pixmap};
25//! use vello_cpu::{color::{palette::css, PremulRgba8}, kurbo::Rect};
26//! let width = 10;
27//! let height = 5;
28//! let mut context = RenderContext::new(width, height);
29//! let mut resources = Resources::new();
30//! context.set_paint(css::MAGENTA);
31//! context.fill_rect(&Rect::from_points((3., 1.), (7., 4.)));
32//!
33//! let mut target = Pixmap::new(width, height);
34//! // While calling `flush` is only strictly necessary if you are rendering using
35//! // multiple threads, it is recommended to always do this.
36//! context.flush();
37//! context.render(&mut target, &mut resources);
38//!
39//! let expected_render = b"\
40//! 0000000000\
41//! 0001111000\
42//! 0001111000\
43//! 0001111000\
44//! 0000000000";
45//! let magenta = css::MAGENTA.premultiply().to_rgba8();
46//! let transparent = PremulRgba8 {r: 0, g: 0, b: 0, a: 0};
47//! let mut result = Vec::new();
48//! for pixel in target.data() {
49//! if *pixel == magenta {
50//! result.push(b'1');
51//! } else if *pixel == transparent {
52//! result.push(b'0');
53//! } else {
54//! panic!("Got unexpected pixel value {pixel:?}");
55//! }
56//! }
57//! assert_eq!(&result, expected_render);
58//! ```
59//!
60//! See the
61//! [examples](https://github.com/linebender/vello/tree/main/sparse_strips/vello_cpu/examples)
62//! for more complete demonstrations of Vello CPU's API.
63//!
64//! # Features
65//!
66//! - `std` (enabled by default): Get floating point functions from the standard library
67//! (likely using your target's libc).
68//! - `libm`: Use floating point implementations from [libm][].
69//! - `png`(enabled by default): Allow loading [`Pixmap`]s from PNG images.
70//! Also required for rendering glyphs with an embedded PNG. Implies `std`.
71//! - `multithreading`: Enable multi-threaded rendering. Implies `std`.
72//! - `text` (enabled by default): Enables glyph rendering ([`glyph_run`][RenderContext::glyph_run]).
73//! - `u8_pipeline` (enabled by default): Enable the u8 pipeline, for speed focused rendering using u8 math.
74//! The `u8` pipeline will be used for [`OptimizeSpeed`][RenderMode::OptimizeSpeed], if both pipelines are enabled.
75//! If you're using Vello CPU for application rendering, you should prefer this pipeline.
76//! - `f32_pipeline`: Enable the `f32` pipeline, which is slower but has more accurate
77//! results. This is espectially useful for rendering test snapshots.
78//! The `f32` pipeline will be used for [`OptimizeQuality`][RenderMode::OptimizeQuality], if both pipelines are enabled.
79//!
80//! At least one of `std` and `libm` is required; `std` overrides `libm`.
81//! At least one of `u8_pipeline` and `f32_pipeline` must be enabled.
82//! You might choose to disable one of these pipelines if your application
83//! won't use it, so as to reduce binary size.
84//!
85//! # Current state
86//!
87//! Vello CPU is a solid CPU-only 2D renderer with broad, reliable feature
88//! support. It provides excellent performance across a wide range of workloads,
89//! with optimized SIMD implementations for all major architectures. The
90//! renderer is still under active development, however, and a few limitations
91//! remain:
92//!
93//! - Complex filter graphs are currently not supported at all and will panic.
94//! In multi-threaded mode, even simple filters are currently unsupported.
95//! - Parts of the API and its documentation are still suboptimal, for example
96//! the [`Resources`][] lifecycle.
97//! - Some exposed features remain experimental and are not recommended for use,
98//! including glyph caching. Experimental APIs are identified in their method
99//! documentation.
100//! - There is still more room for performance improvements, in particular on
101//! x86 systems and also for multi-threaded rendering.
102//!
103//! With that said, we are continuously improving Vello CPU and will address
104//! these and other limitations in future releases.
105//!
106//! # Performance
107//!
108//! Performance benchmarks can be found [here](https://laurenzv.github.io/vello_chart/),
109//! As can be seen, Vello CPU achieves compelling performance on both,
110//! aarch64 and x86 platforms. We also have SIMD optimizations for WASM SIMD,
111//! meaning that you can expect good performance there as well.
112//!
113//! # Implementation
114//!
115//! If you want to gain a better understanding of Vello CPU and the
116//! sparse strips paradigm, you can take a look at the [accompanying
117//! master's thesis](https://ethz.ch/content/dam/ethz/special-interest/infk/inst-pls/plf-dam/documents/StudentProjects/MasterTheses/2025-Laurenz-Thesis.pdf)
118//! that was written on the topic. Note that parts of the descriptions might
119//! become outdated as the implementation changes, but it should give a good
120//! overview nevertheless.
121//!
122//! <!-- We can't directly link to the libm crate built locally, because our feature is only a pass-through -->
123//! [libm]: https://crates.io/crates/libm
124// LINEBENDER LINT SET - lib.rs - v3
125// See https://linebender.org/wiki/canonical-lints/
126// These lints shouldn't apply to examples or tests.
127#![cfg_attr(not(test), warn(unused_crate_dependencies))]
128// These lints shouldn't apply to examples.
129#![warn(clippy::print_stdout, clippy::print_stderr)]
130// Targeting e.g. 32-bit means structs containing usize can give false positives for 64-bit.
131#![cfg_attr(target_pointer_width = "64", warn(clippy::trivially_copy_pass_by_ref))]
132// END LINEBENDER LINT SET
133#![cfg_attr(docsrs, feature(doc_cfg))]
134#![forbid(unsafe_code)]
135#![expect(
136 clippy::cast_possible_truncation,
137 reason = "We cast u16s to u8 in various places where we know for sure that it's < 256"
138)]
139#![no_std]
140
141extern crate alloc;
142extern crate core;
143// Unused in release mode because it's only used directly in the `text_debug` module
144// (or transitively in vello_common).
145#[cfg(feature = "png")]
146use png as _;
147#[cfg(feature = "std")]
148extern crate std;
149
150#[cfg(all(not(feature = "u8_pipeline"), not(feature = "f32_pipeline")))]
151compile_error!("vello_cpu must have at least one of the u8 or f32 pipelines enabled");
152
153mod render;
154
155mod coarse;
156mod dispatch;
157mod filter;
158mod record;
159#[cfg(feature = "text")]
160mod text;
161#[cfg(all(feature = "text", feature = "std", debug_assertions))]
162mod text_debug;
163mod util;
164
165#[doc(hidden)]
166pub mod fine;
167#[doc(hidden)]
168pub mod region;
169
170pub use render::{
171 CompositeMode, PixelFormat, RasterizerSettings, RenderContext, RenderSettings, Resources,
172};
173// Note: The first one is not something that should be
174// exposed, but is currently needed by vello_sparse_tests.
175#[cfg(feature = "text")]
176pub use glifo::Glyph;
177#[cfg(feature = "text")]
178pub use text::{CpuGlyphRunBackend, GlyphRunBuilder};
179pub use vello_common::fearless_simd::Level;
180pub use vello_common::mask::Mask;
181pub use vello_common::paint::{Image, ImageSource, Paint, PaintType};
182pub use vello_common::pixmap::{Pixmap, PixmapMut};
183pub use vello_common::{color, kurbo, peniko};
184
185/// The selected rendering mode.
186/// For using [`RenderMode::OptimizeQuality`] you also need to enable `f32_pipeline` feature.
187#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
188pub enum RenderMode {
189 /// Optimize speed (by performing calculations with u8/16).
190 #[default]
191 OptimizeSpeed,
192 /// Optimize quality (by performing calculations with f32).
193 OptimizeQuality,
194}