diff --git a/.github/copyright.sh b/.github/copyright.sh index b090c0879..07de4c95f 100755 --- a/.github/copyright.sh +++ b/.github/copyright.sh @@ -7,7 +7,7 @@ # -g "!src/special_directory" # Check all the standard Rust source files -output=$(rg "^// Copyright (19|20)[\d]{2} (.+ and )?the Vello Authors( and .+)?$\n^// SPDX-License-Identifier: Apache-2\.0 OR MIT$\n\n" --files-without-match --multiline -g "*.rs" -g "!{shader,crates/shaders/src/cpu}" .) +output=$(rg "^// Copyright (19|20)[\d]{2} (.+ and )?the Vello Authors( and .+)?$\n^// SPDX-License-Identifier: Apache-2\.0 OR MIT$\n\n" --files-without-match --multiline -g "*.rs" -g "!vello_shaders/{shader,src/cpu}" .) if [ -n "$output" ]; then echo -e "The following files lack the correct copyright header:\n" @@ -20,7 +20,7 @@ if [ -n "$output" ]; then fi # Check all the shaders, both WGSL and CPU shaders in Rust, as they also have Unlicense -output=$(rg "^// Copyright (19|20)[\d]{2} (.+ and )?the Vello Authors( and .+)?$\n^// SPDX-License-Identifier: Apache-2\.0 OR MIT OR Unlicense$\n\n" --files-without-match --multiline -g "{shader,crates/shaders/src/cpu}/**/*.{rs,wgsl}" .) +output=$(rg "^// Copyright (19|20)[\d]{2} (.+ and )?the Vello Authors( and .+)?$\n^// SPDX-License-Identifier: Apache-2\.0 OR MIT OR Unlicense$\n\n" --files-without-match --multiline -g "vello_shaders/{shader,src/cpu}/**/*.{rs,wgsl}" .) if [ -n "$output" ]; then echo -e "The following shader files lack the correct copyright header:\n" diff --git a/.vscode/settings.json b/.vscode/settings.json index bda7c8724..6be52f083 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,18 +1,18 @@ { "wgsl-analyzer.customImports": { - "bbox": "${workspaceFolder}/shader/shared/bbox.wgsl", - "blend": "${workspaceFolder}/shader/shared/blend.wgsl", - "bump": "${workspaceFolder}/shader/shared/bump.wgsl", - "clip": "${workspaceFolder}/shader/shared/clip.wgsl", - "config": "${workspaceFolder}/shader/shared/config.wgsl", - "cubic": "${workspaceFolder}/shader/shared/cubic.wgsl", - "drawtag": "${workspaceFolder}/shader/shared/drawtag.wgsl", - "pathtag": "${workspaceFolder}/shader/shared/pathtag.wgsl", - "ptcl": "${workspaceFolder}/shader/shared/ptcl.wgsl", - "segment": "${workspaceFolder}/shader/shared/segment.wgsl", - "tile": "${workspaceFolder}/shader/shared/tile.wgsl", - "transform": "${workspaceFolder}/shader/shared/transform.wgsl", - "util": "${workspaceFolder}/shader/shared/util.wgsl" + "bbox": "${workspaceFolder}/vello_shaders/shader/shared/bbox.wgsl", + "blend": "${workspaceFolder}/vello_shaders/shader/shared/blend.wgsl", + "bump": "${workspaceFolder}/vello_shaders/shader/shared/bump.wgsl", + "clip": "${workspaceFolder}/vello_shaders/shader/shared/clip.wgsl", + "config": "${workspaceFolder}/vello_shaders/shader/shared/config.wgsl", + "cubic": "${workspaceFolder}/vello_shaders/shader/shared/cubic.wgsl", + "drawtag": "${workspaceFolder}/vello_shaders/shader/shared/drawtag.wgsl", + "pathtag": "${workspaceFolder}/vello_shaders/shader/shared/pathtag.wgsl", + "ptcl": "${workspaceFolder}/vello_shaders/shader/shared/ptcl.wgsl", + "segment": "${workspaceFolder}/vello_shaders/shader/shared/segment.wgsl", + "tile": "${workspaceFolder}/vello_shaders/shader/shared/tile.wgsl", + "transform": "${workspaceFolder}/vello_shaders/shader/shared/transform.wgsl", + "util": "${workspaceFolder}/vello_shaders/shader/shared/util.wgsl" }, "wgsl-analyzer.diagnostics.nagaVersion": "main", "wgsl-analyzer.preprocessor.shaderDefs": [ diff --git a/README.md b/README.md index 077c024bf..f9e27ee0f 100644 --- a/README.md +++ b/README.md @@ -274,9 +274,9 @@ Licensed under either of at your option. -In addition, all files in the [`shader`](https://github.com/linebender/vello/tree/main/shader) and [`src/cpu_shader`](https://github.com/linebender/vello/tree/main/src/cpu_shader) +In addition, all files in the [`vello_shaders/shader`](https://github.com/linebender/vello/tree/main/vello_shaders/shader) and [`vello_shaders/src/cpu`](https://github.com/linebender/vello/tree/main/vello_shaders/src/cpu) directories and subdirectories thereof are alternatively licensed under -the Unlicense ([shader/UNLICENSE](https://github.com/linebender/vello/tree/main/shader/UNLICENSE) or ). +the Unlicense ([shader/UNLICENSE](https://github.com/linebender/vello/tree/main/vello_shaders/shader/UNLICENSE) or ). For clarity, these files are also licensed under either of the above licenses. The intent is for this research to be used in as broad a context as possible. diff --git a/doc/ARCHITECTURE.md b/doc/ARCHITECTURE.md index 7abbe3740..f0650f5ee 100644 --- a/doc/ARCHITECTURE.md +++ b/doc/ARCHITECTURE.md @@ -31,16 +31,15 @@ Our current priority is to fill in missing features and to fix rendering artifac The repository is structured as such: -- `crates/` - - `encoding/` - Types that represent the data that needs to be rendered. - - `shaders/` - Infrastructure to preprocess and cross-compile shaders at compile time; see "Shader templating". - - `cpu/` - Functions that perform the same work as their equivalently-named WGSL shaders for the CPU fallbacks. The name is a bit loose; they're "shaders" in the sense that they work on resource bindings with the exact same layout as actual GPU shaders. - - `tests/` - Helper code for writing tests; current has a single smoke test and not much else. - `doc/` - Various documents detailing the vision for Vello as it was developed. This directory should probably be refactored away; adding to it not recommended. -- `examples/` - Example projects using Vello. Each example is its own crate, with its own dependencies. The simplest example is the `shapes` one. -- `shader/` - This is where the magic happens. WGSL shaders that define the compute operations (often variations of prefix sum) that Vello does to render a scene. - - `shared/` - Shared types, functions and constants included in other shaders through non-standard `#import` preprocessor directives (see "Shader templating"). -- `src/` - Code for the main `vello` crate. +- `examples/` - Example projects using Vello. Each example is its own crate, with its own dependencies. The simplest example is called `simple`. +- `vello/` - Code for the main `vello` crate. +- `vello_encoding/` - Types that represent the data that needs to be rendered. +- `vello_shaders/` - Infrastructure to preprocess and cross-compile shaders at compile time; see "Shader templating". + - `shader/` - This is where the magic happens. WGSL shaders that define the compute operations (often variations of prefix sum) that Vello does to render a scene. + - `shared/` - Shared types, functions and constants included in other shaders through non-standard `#import` preprocessor directives (see "Shader templating"). + - `cpu/` - Functions that perform the same work as their equivalently-named WGSL shaders for the CPU fallbacks. The name is a bit loose; they're "shaders" in the sense that they work on resource bindings with the exact same layout as actual GPU shaders. +- `vello_tests/` - Helper code for writing tests; current has a single smoke test and not much else. ## Shader templating @@ -81,7 +80,7 @@ In principle, other backends could consume a `Recording`, but for now the only i ### CPU rendering -The code in `cpu_shader/*.rs` and `cpu_dispatch.rs` provides *some* support for CPU-side rendering. It's in an awkward place right now: +The code in `vello_shaders/src/cpu/*.rs` and `vello_shaders/src/cpu.rs` provides *some* support for CPU-side rendering. It's in an awkward place right now: - It's called through WgpuEngine, so the dependency on wgpu is still there. - Fine rasterization (the part at the end that puts pixels on screen) doesn't work in CPU yet (see [#386]). diff --git a/vello/README.md b/vello/README.md new file mode 100644 index 000000000..f9e27ee0f --- /dev/null +++ b/vello/README.md @@ -0,0 +1,296 @@ +
+ +# Vello + +**An experimental GPU compute-centric 2D renderer** + +[![Linebender Zulip](https://img.shields.io/badge/Linebender-%23gpu-blue?logo=Zulip)](https://xi.zulipchat.com/#narrow/stream/197075-gpu) +[![dependency status](https://deps.rs/repo/github/linebender/vello/status.svg)](https://deps.rs/repo/github/linebender/vello) +[![MIT/Apache 2.0](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](#license) +[![wgpu version](https://img.shields.io/badge/wgpu-v0.20.0-orange.svg)](https://crates.io/crates/wgpu) + +[![Crates.io](https://img.shields.io/crates/v/vello.svg)](https://crates.io/crates/vello) +[![Docs](https://docs.rs/vello/badge.svg)](https://docs.rs/vello) +[![Build status](https://github.com/linebender/vello/workflows/CI/badge.svg)](https://github.com/linebender/vello/actions) + +
+ +Vello is an experimental 2D graphics rendering engine written in Rust, with a focus on GPU compute. +It can draw large 2D scenes with interactive or near-interactive performance, using [`wgpu`] for GPU access. + +Quickstart to run an example program: + +```shell +cargo run -p with_winit +``` + +![image](https://github.com/linebender/vello/assets/8573618/cc2b742e-2135-4b70-8051-c49aeddb5d19) + +It is used as the rendering backend for [Xilem], a Rust GUI toolkit. + +> [!WARNING] +> Vello can currently be considered in an alpha state. In particular, we're still working on the following: +> +> - [Implementing blur and filter effects](https://github.com/linebender/vello/issues/476). +> - [Conflations artifacts](https://github.com/linebender/vello/issues/49). +> - [GPU memory allocation strategy](https://github.com/linebender/vello/issues/366) +> - [Glyph caching](https://github.com/linebender/vello/issues/204) + +## Motivation + +Vello is meant to fill the same place in the graphics stack as other vector graphics renderers like [Skia](https://skia.org/), [Cairo](https://www.cairographics.org/), and its predecessor project [Piet](https://github.com/linebender/piet). +On a basic level, that means it provides tools to render shapes, images, gradients, text, etc, using a PostScript-inspired API, the same that powers SVG files and [the browser `` element](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D). + +Vello's selling point is that it gets better performance than other renderers by better leveraging the GPU. +In traditional PostScript-style renderers, some steps of the render process like sorting and clipping either need to be handled in the CPU or done through the use of intermediary textures. +Vello avoids this by using prefix-sum algorithms to parallelize work that usually needs to happen in sequence, so that work can be offloaded to the GPU with minimal use of temporary buffers. + +This means that Vello needs a GPU with support for compute shaders to run. + +## Getting started + +Vello is meant to be integrated deep in UI render stacks. +While drawing in a Vello scene is easy, actually rendering that scene to a surface requires setting up a wgpu context, which is a non-trivial task. + +To use Vello as the renderer for your PDF reader / GUI toolkit / etc, your code will have to look roughly like this: + +```rust +// Initialize wgpu and get handles +let (width, height) = ...; +let device: wgpu::Device = ...; +let queue: wgpu::Queue = ...; +let surface: wgpu::Surface<'_> = ...; +let texture_format: wgpu::TextureFormat = ...; +let mut renderer = Renderer::new( + &device, + RendererOptions { + surface_format: Some(texture_format), + use_cpu: false, + antialiasing_support: vello::AaSupport::all(), + num_init_threads: NonZeroUsize::new(1), + }, +).expect("Failed to create renderer"); + +// Create scene and draw stuff in it +let mut scene = vello::Scene::new(); +scene.fill( + vello::peniko::Fill::NonZero, + vello::Affine::IDENTITY, + vello::Color::rgb8(242, 140, 168), + None, + &vello::Circle::new((420.0, 200.0), 120.0), +); + +// Draw more stuff +scene.push_layer(...); +scene.fill(...); +scene.stroke(...); +scene.pop_layer(...); + +// Render to your window/buffer/etc. +let surface_texture = surface.get_current_texture() + .expect("failed to get surface texture"); +renderer + .render_to_surface( + &device, + &queue, + &scene, + &surface_texture, + &vello::RenderParams { + base_color: Color::BLACK, // Background color + width, + height, + antialiasing_method: AaConfig::Msaa16, + }, + ) + .expect("Failed to render to surface"); +surface_texture.present(); +``` + +See the [`examples/`](https://github.com/linebender/vello/tree/main/examples) folder to see how that code integrates with frameworks like winit and bevy. + +## Performance + +We've observed 177 fps for the paris-30k test scene on an M1 Max, at a resolution of 1600 pixels square, which is excellent performance and represents something of a best case for the engine. + +More formal benchmarks are on their way. + +## Integrations + +### SVG + +A separate Linebender integration for rendering SVG files is available through the [`vello_svg`](https://github.com/linebender/vello_svg) crate. + +### Lottie + +A separate Linebender integration for playing Lottie animations is available through the [`velato`](https://github.com/linebender/velato) crate. + +## Examples + +Our examples are provided in separate packages in the [`examples`](https://github.com/linebender/vello/tree/main/examples) folder. +This allows them to have independent dependencies and faster builds. +Examples must be selected using the `--package` (or `-p`) Cargo flag. + +### Winit + +Our [winit] example ([examples/with_winit](https://github.com/linebender/vello/tree/main/examples/with_winit)) demonstrates rendering to a [winit] window. +By default, this renders the [GhostScript Tiger] as well as all SVG files you add in the [examples/assets/downloads/](https://github.com/linebender/vello/tree/main/examples/assets/downloads) directory. +A custom list of SVG file paths (and directories to render all SVG files from) can be provided as arguments instead. +It also includes a collection of test scenes showing the capabilities of `vello`, which can be shown with `--test-scenes`. + +```shell +cargo run -p with_winit +``` + + + +### Bevy + +There is a separate community integration for rendering raw scenes or Lottie and SVG files in [Bevy] through [`bevy_vello`](https://github.com/loopystudios/bevy_vello). + +## Platforms + +We aim to target all environments which can support WebGPU with the [default limits](https://www.w3.org/TR/webgpu/#limits). +We defer to [`wgpu`] for this support. +Other platforms are more tricky, and may require special building/running procedures. + +### Web + +Because Vello relies heavily on compute shaders, we rely on the emerging WebGPU standard to run on the web. +Until browser support becomes widespread, it will probably be necessary to use development browser versions (e.g. Chrome Canary) and explicitly enable WebGPU. + +The following command builds and runs a web version of the [winit demo](#winit). +This uses [`cargo-run-wasm`](https://github.com/rukai/cargo-run-wasm) to build the example for web, and host a local server for it + +```shell +# Make sure the Rust toolchain supports the wasm32 target +rustup target add wasm32-unknown-unknown + +# The binary name must also be explicitly provided as it differs from the package name +cargo run_wasm -p with_winit --bin with_winit_bin +``` + +There is also a web demo [available here](https://linebender.github.io/vello) on supporting web browsers. + +> [!WARNING] +> The web is not currently a primary target for Vello, and WebGPU implementations are incomplete, so you might run into issues running this example. + +### Android + +The [`with_winit`](#winit) example supports running on Android, using [cargo apk](https://crates.io/crates/cargo-apk). + +```shell +cargo apk run -p with_winit +``` + +> [!TIP] +> cargo apk doesn't support running in release mode without configuration. +> See [their crates page docs](https://crates.io/crates/cargo-apk) (around `package.metadata.android.signing.`). +> +> See also [cargo-apk#16](https://github.com/rust-mobile/cargo-apk/issues/16). +> To run in release mode, you must add the following to `examples/with_winit/Cargo.toml` (changing `$HOME` to your home directory): + +```toml +[package.metadata.android.signing.release] +path = "$HOME/.android/debug.keystore" +keystore_password = "android" +``` + +> [!NOTE] +> As `cargo apk` does not allow passing command line arguments or environment variables to the app when ran, these can be embedded into the +> program at compile time (currently for Android only) +> `with_winit` currently supports the environment variables: +> +> - `VELLO_STATIC_LOG`, which is equivalent to `RUST_LOG` +> - `VELLO_STATIC_ARGS`, which is equivalent to passing in command line arguments + +For example (with unix shell environment variable syntax): + +```sh +VELLO_STATIC_LOG="vello=trace" VELLO_STATIC_ARGS="--test-scenes" cargo apk run -p with_winit --lib +``` + +## Minimum supported Rust Version (MSRV) + +This version of Vello has been verified to compile with **Rust 1.75** and later. + +Future versions of Vello 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. + +
+Click here if compiling fails. + +As time has passed, some of Vello'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 +``` + +
+ +## Community + +Discussion of Vello development happens in the [Linebender Zulip](https://xi.zulipchat.com/), specifically the [#gpu stream](https://xi.zulipchat.com/#narrow/stream/197075-gpu). All public content can be read without logging in. + +Contributions are welcome by pull request. The [Rust code of conduct] applies. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +licensed as noted in the "License" section, without any additional terms or conditions. + +## History + +Vello was previously known as `piet-gpu`. +This prior incarnation used a custom cross-API hardware abstraction layer, called `piet-gpu-hal`, instead of [`wgpu`]. + +An archive of this version can be found in the branches [`custom-hal-archive-with-shaders`] and [`custom-hal-archive`]. +This succeeded the previous prototype, [piet-metal], and included work adapted from [piet-dx12]. + +The decision to lay down `piet-gpu-hal` in favor of WebGPU is discussed in detail in the blog post [Requiem for piet-gpu-hal]. + +A [vision](https://github.com/linebender/vello/tree/main/doc/vision.md) document dated December 2020 explained the longer-term goals of the project, and how we might get there. +Many of these items are out-of-date or completed, but it still may provide some useful background. + +## Related projects + +Vello takes inspiration from many other rendering projects, including: + +- [Pathfinder](https://github.com/servo/pathfinder) +- [Spinel](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/src/graphics/lib/compute/spinel/) +- [Forma](https://github.com/google/forma) +- [Massively Parallel Vector Graphics](https://w3.impa.br/~diego/projects/GanEtAl14/) +- [Random-access rendering of general vector graphics](https://hhoppe.com/proj/ravg/) + +## License + +Licensed under either of + +- Apache License, Version 2.0 + ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license + ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +In addition, all files in the [`vello_shaders/shader`](https://github.com/linebender/vello/tree/main/vello_shaders/shader) and [`vello_shaders/src/cpu`](https://github.com/linebender/vello/tree/main/vello_shaders/src/cpu) +directories and subdirectories thereof are alternatively licensed under +the Unlicense ([shader/UNLICENSE](https://github.com/linebender/vello/tree/main/vello_shaders/shader/UNLICENSE) or ). +For clarity, these files are also licensed under either of the above licenses. +The intent is for this research to be used in as broad a context as possible. + +The files in subdirectories of the [`examples/assets`](https://github.com/linebender/vello/tree/main/examples/assets) directory are licensed solely under +their respective licenses, available in the `LICENSE` file in their directories. + +[piet-metal]: https://github.com/linebender/piet-metal +[`wgpu`]: https://wgpu.rs/ +[Xilem]: https://github.com/linebender/xilem/ +[rust code of conduct]: https://www.rust-lang.org/policies/code-of-conduct +[`custom-hal-archive-with-shaders`]: https://github.com/linebender/piet-gpu/tree/custom-hal-archive-with-shaders +[`custom-hal-archive`]: https://github.com/linebender/piet-gpu/tree/custom-hal-archive +[piet-dx12]: https://github.com/bzm3r/piet-dx12 +[GhostScript tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg +[winit]: https://github.com/rust-windowing/winit +[Bevy]: https://bevyengine.org/ +[Requiem for piet-gpu-hal]: https://raphlinus.github.io/rust/gpu/2023/01/07/requiem-piet-gpu-hal.html