| <div align="center"> | |
| # Vello CPU | |
| **CPU-based renderer** | |
| [](https://crates.io/crates/vello_cpu) | |
| [](https://docs.rs/vello_cpu) | |
| [](#license) | |
| \ | |
| [](https://xi.zulipchat.com/#narrow/channel/197075-vello) [](https://github.com/linebender/vello/actions) | |
| [](https://deps.rs/crate/vello_cpu) | |
| </div> | |
| <!-- We use cargo-rdme to update the README with the contents of lib.rs. | |
| To edit the following section, update it in lib.rs, then run: | |
| cargo rdme --workspace-project=vello_cpu | |
| Full documentation at https://github.com/orium/cargo-rdme --> | |
| <!-- Intra-doc links used in lib.rs should be evaluated here. | |
| See https://linebender.org/blog/doc-include/ for related discussion. --> | |
| [`RenderContext`]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/struct.RenderContext.html | |
| [RenderContext::set_paint]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/struct.RenderContext.html#method.set_paint | |
| [RenderContext::fill_path]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/struct.RenderContext.html#method.fill_path | |
| [RenderContext::stroke_path]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/struct.RenderContext.html#method.stroke_path | |
| [RenderContext::glyph_run]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/struct.RenderContext.html#method.glyph_run | |
| [RenderMode::OptimizeSpeed]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/enum.RenderMode.html#variant.OptimizeSpeed | |
| [RenderMode::OptimizeQuality]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/enum.RenderMode.html#variant.OptimizeQuality | |
| [`RenderContext::render`]: | |
| https://docs.rs/vello_cpu/latest/vello_cpu/struct.RenderContext.html#method.render | |
| [`Pixmap`]: https://docs.rs/vello_cpu/latest/vello_cpu/struct.Pixmap.html | |
| [`Resources`]: https://docs.rs/vello_cpu/latest/vello_cpu/struct.Resources.html | |
| <!-- cargo-rdme start --> | |
| Vello CPU is a 2D graphics rendering engine written in Rust for devices with no | |
| or underpowered GPUs. | |
| We also develop: | |
| 1. [Vello GPU](https://crates.io/crates/vello_gpu), which shares Vello CPU's | |
| architecture but moves rasterization and compositing to the GPU. | |
| 2. [Vello Research], an experimental, high-performance, compute-centric GPU | |
| renderer. | |
| ### Usage | |
| To use Vello CPU, you need to: | |
| - Create a [`RenderContext`][], a 2D drawing context for a fixed-size scene | |
| area. | |
| - For each object in your scene: | |
| - Set how the object will be painted, using | |
| [`set_paint`][RenderContext::set_paint]. | |
| - Set the shape to be drawn for that object, using methods like | |
| [`fill_path`][RenderContext::fill_path], | |
| [`stroke_path`][RenderContext::stroke_path], or | |
| [`glyph_run`][RenderContext::glyph_run]. | |
| - Render it to an image using [`RenderContext::render`][]. | |
| ```rust | |
| use vello_cpu::{RenderContext, Resources, Pixmap}; | |
| use vello_cpu::{color::{palette::css, PremulRgba8}, kurbo::Rect}; | |
| let width = 10; | |
| let height = 5; | |
| let mut context = RenderContext::new(width, height); | |
| let mut resources = Resources::new(); | |
| context.set_paint(css::MAGENTA); | |
| context.fill_rect(&Rect::from_points((3., 1.), (7., 4.))); | |
| let mut target = Pixmap::new(width, height); | |
| // While calling `flush` is only strictly necessary if you are rendering using | |
| // multiple threads, it is recommended to always do this. | |
| context.flush(); | |
| context.render(&mut target, &mut resources); | |
| let expected_render = b"\ | |
| 0000000000\ | |
| 0001111000\ | |
| 0001111000\ | |
| 0001111000\ | |
| 0000000000"; | |
| let magenta = css::MAGENTA.premultiply().to_rgba8(); | |
| let transparent = PremulRgba8 {r: 0, g: 0, b: 0, a: 0}; | |
| let mut result = Vec::new(); | |
| for pixel in target.data() { | |
| if *pixel == magenta { | |
| result.push(b'1'); | |
| } else if *pixel == transparent { | |
| result.push(b'0'); | |
| } else { | |
| panic!("Got unexpected pixel value {pixel:?}"); | |
| } | |
| } | |
| assert_eq!(&result, expected_render); | |
| ``` | |
| See the | |
| [examples](https://github.com/linebender/vello/tree/main/vello_cpu/examples) for | |
| more complete demonstrations of Vello CPU's API. | |
| ### Features | |
| - `std` (enabled by default): Get floating point functions from the standard | |
| library (likely using your target's libc). | |
| - `libm`: Use floating point implementations from [libm][]. | |
| - `png`(enabled by default): Allow loading [`Pixmap`]s from PNG images. Also | |
| required for rendering glyphs with an embedded PNG. Implies `std`. | |
| - `multithreading`: Enable multi-threaded rendering. Implies `std`. | |
| - `text` (enabled by default): Enables glyph rendering | |
| ([`glyph_run`][RenderContext::glyph_run]). | |
| - `u8_pipeline` (enabled by default): Enable the u8 pipeline, for speed focused | |
| rendering using u8 math. The `u8` pipeline will be used for | |
| [`OptimizeSpeed`][RenderMode::OptimizeSpeed], if both pipelines are enabled. | |
| If you're using Vello CPU for application rendering, you should prefer this | |
| pipeline. | |
| - `f32_pipeline`: Enable the `f32` pipeline, which is slower but has more | |
| accurate results. This is espectially useful for rendering test snapshots. The | |
| `f32` pipeline will be used for | |
| [`OptimizeQuality`][RenderMode::OptimizeQuality], if both pipelines are | |
| enabled. | |
| At least one of `std` and `libm` is required; `std` overrides `libm`. At least | |
| one of `u8_pipeline` and `f32_pipeline` must be enabled. You might choose to | |
| disable one of these pipelines if your application won't use it, so as to reduce | |
| binary size. | |
| ### Current state | |
| Vello CPU is a solid CPU-only 2D renderer with broad, reliable feature support. | |
| It provides excellent performance across a wide range of workloads, with | |
| optimized SIMD implementations for all major architectures. The renderer is | |
| still under active development, however, and a few limitations remain: | |
| - Complex filter graphs are currently not supported at all and will panic. In | |
| multi-threaded mode, even simple filters are currently unsupported. | |
| - Parts of the API and its documentation are still suboptimal, for example the | |
| [`Resources`][] lifecycle. | |
| - Some exposed features remain experimental and are not recommended for use, | |
| including glyph caching. Experimental APIs are identified in their method | |
| documentation. | |
| - There is still more room for performance improvements, in particular on x86 | |
| systems and also for multi-threaded rendering. | |
| With that said, we are continuously improving Vello CPU and will address these | |
| and other limitations in future releases. | |
| ### Performance | |
| Performance benchmarks can be found | |
| [here](https://laurenzv.github.io/vello_chart/), As can be seen, Vello CPU | |
| achieves compelling performance on both, aarch64 and x86 platforms. We also have | |
| SIMD optimizations for WASM SIMD, meaning that you can expect good performance | |
| there as well. | |
| ### Implementation | |
| If you want to gain a better understanding of Vello CPU and the sparse strips | |
| paradigm, you can take a look at the | |
| [accompanying master's thesis](https://ethz.ch/content/dam/ethz/special-interest/infk/inst-pls/plf-dam/documents/StudentProjects/MasterTheses/2025-Laurenz-Thesis.pdf) | |
| that was written on the topic. Note that parts of the descriptions might become | |
| outdated as the implementation changes, but it should give a good overview | |
| nevertheless. | |
| <!-- We can't directly link to the libm crate built locally, because our feature is only a pass-through --> | |
| [libm]: https://crates.io/crates/libm | |
| [Vello Research]: | |
| https://github.com/linebender/vello/tree/main/research/vello_research | |
| <!-- cargo-rdme end --> | |
| ## Minimum supported Rust Version (MSRV) | |
| This version of Vello CPU has been verified to compile with **Rust 1.89** and | |
| later. | |
| Future versions of Vello CPU might increase the Rust version requirement. It | |
| will not be treated as a breaking change and as such can even happen with small | |
| patch releases. | |
| <details> | |
| <summary>Click here if compiling fails.</summary> | |
| As time has passed, some of Vello CPU's dependencies could have released | |
| versions with a higher Rust requirement. If you encounter a compilation issue | |
| due to a dependency and don't want to upgrade your Rust toolchain, then you | |
| could downgrade the dependency. | |
| ```sh | |
| # Use the problematic dependency's name and version | |
| cargo update -p package_name --precise 0.1.1 | |
| ``` | |
| </details> | |
| ## Community | |
| Discussion of Vello CPU development happens in the | |
| [Linebender Zulip](https://xi.zulipchat.com/), specifically the | |
| [#vello channel](https://xi.zulipchat.com/#narrow/channel/197075-vello). All | |
| public content can be read without logging in. | |
| Contributions are welcome by pull request. The [Rust code of conduct] applies. | |
| ## License | |
| Licensed under either of | |
| - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or | |
| <http://www.apache.org/licenses/LICENSE-2.0>) | |
| - MIT license ([LICENSE-MIT](LICENSE-MIT) or | |
| <http://opensource.org/licenses/MIT>) | |
| at your option. | |
| [Rust code of conduct]: https://www.rust-lang.org/policies/code-of-conduct |