From e51142c06a880b192f5f031f257e4241dea98a1f Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 3 Oct 2024 11:35:07 +0100 Subject: [PATCH 1/6] Add some simple docs improvements with intra-doc links --- vello/src/lib.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- vello/src/scene.rs | 12 +++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/vello/src/lib.rs b/vello/src/lib.rs index fc6dbd72..05f3a63e 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -22,7 +22,7 @@ //! ## 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 setting up a wgpu context, which is a non-trivial task. +//! While drawing in a Vello [`Scene`] is easy, actually rendering that scene to a surface 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: //! @@ -132,22 +132,52 @@ use wgpu::{Device, Queue, SurfaceTexture, TextureFormat, TextureView}; use wgpu_profiler::{GpuProfiler, GpuProfilerSettings}; /// Represents the antialiasing method to use during a render pass. +/// +/// Can be configured for a render operation by setting [`RenderParams::antialiasing_method`]. +/// Each value of this can only be used if the corresponding field on [`AaSupport`] was used. +/// +/// This can be converted into an `AaSupport` using [`Iterator::collect`], +/// as `AaSupport` implements `FromIterator`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum AaConfig { + /// Area antialiasing, where the proportion of an edge pixel covered by a path determines its contribution. + /// + /// This can lead to some conflation artifacts, but might have better performance + /// than the multi-sampling method. + /// + /// Can only be used if [enabled][AaSupport::area] for the `Renderer`. Area, + /// 8x Multisampling + /// + /// Can only be used if [enabled][AaSupport::msaa8] for the `Renderer`. Msaa8, + /// 16x Multisampling + /// + /// Can only be used if [enabled][AaSupport::msaa16] for the `Renderer`. Msaa16, } /// Represents the set of antialiasing configurations to enable during pipeline creation. +/// +/// This is configured at Renderer creation time ([`Renderer::new`]) by setting +/// [`RendererOptions::antialiasing_support`]. +/// +/// This can be created from a set of `AaConfig` using [`Iterator::collect`], +/// as `AaSupport` implements `FromIterator`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct AaSupport { + /// Support [`AaConfig::Area`]. pub area: bool, + /// Support [`AaConfig::Msaa8`]. pub msaa8: bool, + /// Support [`AaConfig::Msaa16`]. pub msaa16: bool, } impl AaSupport { + /// Support every anti-aliasing method. + /// + /// This might increase startup time, as more shader variations must be compiled. pub fn all() -> Self { Self { area: true, @@ -156,6 +186,9 @@ impl AaSupport { } } + /// Support only [`AaConfig::Area`]. + /// + /// This should be the default choice for most users. pub fn area_only() -> Self { Self { area: true, @@ -241,6 +274,11 @@ pub enum Error { pub(crate) type Result = std::result::Result; /// Renders a scene into a texture or surface. +/// +/// Currently, each renderer only supports a single surface format, if it +/// supports drawing to surfaces at all. +/// +/// This is a known leaky assumption. #[cfg(feature = "wgpu")] pub struct Renderer { #[cfg_attr(not(feature = "hot_reload"), allow(dead_code))] @@ -270,6 +308,8 @@ pub struct Renderer { static_assertions::assert_impl_all!(Renderer: Send); /// Parameters used in a single render that are configurable by the client. +/// +/// These are used in [`Renderer::render_to_surface`] and [`Renderer::render_to_texture`]. pub struct RenderParams { /// The background color applied to the target. This value is only applicable to the full /// pipeline. @@ -292,6 +332,7 @@ pub struct RenderParams { } #[cfg(feature = "wgpu")] +/// Options which are set at renderer creation time, used in [`Renderer::new`]. pub struct RendererOptions { /// The format of the texture used for surfaces with this renderer/device /// If None, the renderer cannot be used with surfaces diff --git a/vello/src/scene.rs b/vello/src/scene.rs index 83edd04b..d3b3e193 100644 --- a/vello/src/scene.rs +++ b/vello/src/scene.rs @@ -29,8 +29,16 @@ use vello_encoding::{Encoding, Glyph, GlyphRun, Patch, Transform}; /// The main datatype for rendering graphics. /// -/// A Scene stores a sequence of drawing commands, their context, and the +/// A `Scene` stores a sequence of drawing commands, their context, and the /// associated resources, which can later be rendered. +/// +/// Most users will render this using [`Renderer::render_to_surface`][crate::Renderer::render_to_surface] +/// or [`Renderer::render_to_texture`][crate::Renderer::render_to_texture]. +/// +/// Rendering from a `Scene` will *not* clear it, which should be done in a separate step, by calling [`Scene::reset`]. +/// +/// If this is not done for a scene which is retained (to avoid allocations) between frames, this will likely +/// quickly increase the complexity of the render result, leading to crashes or potential host system instability. #[derive(Clone, Default)] pub struct Scene { encoding: Encoding, @@ -322,6 +330,8 @@ impl From for Scene { } /// Builder for encoding a glyph run. +/// +/// Created using [`Scene::draw_glyphs`]. pub struct DrawGlyphs<'a> { scene: &'a mut Scene, run: GlyphRun, From 4deae60add2c5ce6beb42ecff2c0bfbcd0acec4a Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 3 Oct 2024 16:34:40 +0100 Subject: [PATCH 2/6] Cleanup wording for `Renderer` doc comment --- vello/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vello/src/lib.rs b/vello/src/lib.rs index 05f3a63e..b62ae153 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -277,8 +277,7 @@ pub(crate) type Result = std::result::Result; /// /// Currently, each renderer only supports a single surface format, if it /// supports drawing to surfaces at all. -/// -/// This is a known leaky assumption. +/// This is an assumption which is known to be limiting, and is planned to change. #[cfg(feature = "wgpu")] pub struct Renderer { #[cfg_attr(not(feature = "hot_reload"), allow(dead_code))] From b5776b73e74f8025c48d1f39716324d685b92319 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:08:50 +0100 Subject: [PATCH 3/6] Update vello/src/lib.rs Co-authored-by: Kaur Kuut --- vello/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vello/src/lib.rs b/vello/src/lib.rs index b62ae153..252d883a 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -159,7 +159,7 @@ pub enum AaConfig { /// Represents the set of antialiasing configurations to enable during pipeline creation. /// -/// This is configured at Renderer creation time ([`Renderer::new`]) by setting +/// This is configured at `Renderer` creation time ([`Renderer::new`]) by setting /// [`RendererOptions::antialiasing_support`]. /// /// This can be created from a set of `AaConfig` using [`Iterator::collect`], From 0fd2249aac5e3287cb100fcda2e2daae2f4fd653 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:10:22 +0100 Subject: [PATCH 4/6] Add a more precise description for the Area `AaConfig` Co-authored-by: Raph Levien --- vello/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vello/src/lib.rs b/vello/src/lib.rs index 252d883a..24172d0c 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -140,7 +140,11 @@ use wgpu_profiler::{GpuProfiler, GpuProfilerSettings}; /// as `AaSupport` implements `FromIterator`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum AaConfig { - /// Area antialiasing, where the proportion of an edge pixel covered by a path determines its contribution. + /// Area anti-aliasing, where the alpha value for a pixel is computed from integrating + /// the winding number over its square area. + /// + /// This technique produces very accurate values when the shape has winding number of 0 or 1 + /// everywhere, but can result in conflation artifacts otherwise. /// /// This can lead to some conflation artifacts, but might have better performance /// than the multi-sampling method. From 3b59d1bc9186888a46b45259078cbea1442ed836 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:24:19 +0100 Subject: [PATCH 5/6] Consistently use anti-aliasing in docs --- doc/roadmap_2023.md | 2 +- doc/vision.md | 2 +- vello/src/lib.rs | 10 ++++------ vello_shaders/shader/fine.wgsl | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/doc/roadmap_2023.md b/doc/roadmap_2023.md index 2eb5b257..ee832b7b 100644 --- a/doc/roadmap_2023.md +++ b/doc/roadmap_2023.md @@ -135,7 +135,7 @@ Vello now has a "recording" abstraction that includes lightweight proxies for re The [standard compositing model] calls for first doing antialiased rendering of vector shapes, then compositing using Porter-Duff rules. That leads to "conflation artifacts," or seams that are visible when multiple objects have adjoining boundaries. (Another form of conflation artifacts involves rendering within a single path, where the path is self-intersecting; this may be quite important for compatibility when trying to match the exact appearance of existing renderers) -It remains an interesting question whether we can render without conflation artifacts and retain good performance. Tatsuyuki Ishii prototyped a patch which appears promising. It should also be noted that a supersampling approach might also be a good way to get gamma-correct antialiasing without changing the semantics of alpha blending, in addition to eliminating conflation artifacts. +It remains an interesting question whether we can render without conflation artifacts and retain good performance. Tatsuyuki Ishii prototyped a patch which appears promising. It should also be noted that a supersampling approach might also be a good way to get gamma-correct anti-aliasing without changing the semantics of alpha blending, in addition to eliminating conflation artifacts. This is a hard problem, but interesting, and might be motivated by needs of a specific client. diff --git a/doc/vision.md b/doc/vision.md index ee49d7f9..27a48d6d 100644 --- a/doc/vision.md +++ b/doc/vision.md @@ -105,7 +105,7 @@ The major advantages of GPU-side variable font rendering are to allow efficient The question of quality in GPU 2D rendering has long been complex. Many rasterization based approaches are dependent on [MSAA] in the GPU’s fixed-function pipeline, which may not always be available or perhaps only practical at lower settings (especially on mobile). Thus, GPU accelerated 2D rendering quality has gotten something of a bad name. -A compute-centric approach changes the story. All actual pixels are generated by code; the quality of the rendering is entirely up to the author of that code. The current piet-gpu codebase uses an exact-area approach to antialiasing (in the [tradition of libart]), and thus does not exhibit stepping or graininess characteristic of MSAA at low or medium settings. The quality should be the same as a good software renderer, because it *is* a software renderer, just one that happens to be running on hardware with orders of magnitude more parallelism than any reasonable CPU. +A compute-centric approach changes the story. All actual pixels are generated by code; the quality of the rendering is entirely up to the author of that code. The current piet-gpu codebase uses an exact-area approach to anti-aliasing (in the [tradition of libart]), and thus does not exhibit stepping or graininess characteristic of MSAA at low or medium settings. The quality should be the same as a good software renderer, because it *is* a software renderer, just one that happens to be running on hardware with orders of magnitude more parallelism than any reasonable CPU. Even so, I believe it’s possible to do even better. A CPU-bound renderer has barely enough performance to get pixels to the screen, so takes whatever shortcuts are needed to get the job done in that performance budget. A GPU typically has an order of magnitude more raw compute bandwidth, so there is headroom that can be used to improve quality. diff --git a/vello/src/lib.rs b/vello/src/lib.rs index 24172d0c..a3834b6a 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -131,7 +131,7 @@ use wgpu::{Device, Queue, SurfaceTexture, TextureFormat, TextureView}; #[cfg(all(feature = "wgpu", feature = "wgpu-profiler"))] use wgpu_profiler::{GpuProfiler, GpuProfilerSettings}; -/// Represents the antialiasing method to use during a render pass. +/// Represents the anti-aliasing method to use during a render pass. /// /// Can be configured for a render operation by setting [`RenderParams::antialiasing_method`]. /// Each value of this can only be used if the corresponding field on [`AaSupport`] was used. @@ -140,14 +140,12 @@ use wgpu_profiler::{GpuProfiler, GpuProfilerSettings}; /// as `AaSupport` implements `FromIterator`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum AaConfig { - /// Area anti-aliasing, where the alpha value for a pixel is computed from integrating + /// Area anti-aliasing, where the alpha value for a pixel is computed from integrating /// the winding number over its square area. /// /// This technique produces very accurate values when the shape has winding number of 0 or 1 /// everywhere, but can result in conflation artifacts otherwise. - /// - /// This can lead to some conflation artifacts, but might have better performance - /// than the multi-sampling method. + /// It generally has better performance than the multi-sampling methods. /// /// Can only be used if [enabled][AaSupport::area] for the `Renderer`. Area, @@ -161,7 +159,7 @@ pub enum AaConfig { Msaa16, } -/// Represents the set of antialiasing configurations to enable during pipeline creation. +/// Represents the set of anti-aliasing configurations to enable during pipeline creation. /// /// This is configured at `Renderer` creation time ([`Renderer::new`]) by setting /// [`RendererOptions::antialiasing_support`]. diff --git a/vello_shaders/shader/fine.wgsl b/vello_shaders/shader/fine.wgsl index 91b0ddda..922c7ec2 100644 --- a/vello_shaders/shader/fine.wgsl +++ b/vello_shaders/shader/fine.wgsl @@ -857,7 +857,7 @@ let PIXELS_PER_THREAD = 4u; #ifndef msaa -// Analytic area antialiasing. +// Analytic area anti-aliasing. // // This is currently dead code if msaa is enabled, but it would be fairly straightforward // to wire this so it's a dynamic choice (even per-path). From 86925239c403bcfa129524c8776e1e5198045f58 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:31:52 +0100 Subject: [PATCH 6/6] Move `override_image` down and tweak docs --- vello/src/lib.rs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/vello/src/lib.rs b/vello/src/lib.rs index a3834b6a..7a256091 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs @@ -405,20 +405,6 @@ impl Renderer { }) } - /// Overwrite the `Image` with the `Texture` texture. - /// - /// If texture is `None`, removes the override. - pub fn override_image( - &mut self, - image: &peniko::Image, - texture: Option>>, - ) -> Option>> { - match texture { - Some(texture) => self.engine.image_overrides.insert(image.data.id(), texture), - None => self.engine.image_overrides.remove(&image.data.id()), - } - } - /// Renders a scene to the target texture. /// /// The texture is assumed to be of the specified dimensions and have been created with @@ -529,6 +515,26 @@ impl Renderer { Ok(()) } + /// Overwrite `image` with `texture`. + /// + /// Whenever `image` would be rendered, instead the given `Texture` will be used. + /// + /// Correct behaviour is not guaranteed if the texture does not have the same + /// dimensions as the image, nor if an image which uses the same [data] but different + /// dimensions would be rendered. + /// + /// [data]: peniko::Image::data + pub fn override_image( + &mut self, + image: &peniko::Image, + texture: Option>>, + ) -> Option>> { + match texture { + Some(texture) => self.engine.image_overrides.insert(image.data.id(), texture), + None => self.engine.image_overrides.remove(&image.data.id()), + } + } + /// Reload the shaders. This should only be used during `vello` development #[cfg(feature = "hot_reload")] #[doc(hidden)] // End-users of Vello should not have `hot_reload` enabled.