Skip to content

Commit

Permalink
Various docs improvements (#712)
Browse files Browse the repository at this point in the history
Adds intra-doc links as appropriate.
Explains anti-aliasing methods.

---------

Co-authored-by: Kaur Kuut <[email protected]>
Co-authored-by: Raph Levien <[email protected]>
  • Loading branch information
3 people authored Oct 4, 2024
1 parent 7647a14 commit 06f5558
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 21 deletions.
2 changes: 1 addition & 1 deletion doc/roadmap_2023.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion doc/vision.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
82 changes: 65 additions & 17 deletions vello/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
//!
Expand Down Expand Up @@ -135,23 +135,55 @@ 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.
///
/// This can be converted into an `AaSupport` using [`Iterator::collect`],
/// 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
/// 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.
/// It generally has better performance than the multi-sampling methods.
///
/// 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.
/// 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`].
///
/// 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,
Expand All @@ -160,6 +192,9 @@ impl AaSupport {
}
}

/// Support only [`AaConfig::Area`].
///
/// This should be the default choice for most users.
pub fn area_only() -> Self {
Self {
area: true,
Expand Down Expand Up @@ -245,6 +280,10 @@ pub enum Error {
pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;

/// 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 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))]
Expand Down Expand Up @@ -274,6 +313,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.
Expand All @@ -289,6 +330,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
Expand Down Expand Up @@ -360,20 +402,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<wgpu::ImageCopyTextureBase<Arc<wgpu::Texture>>>,
) -> Option<wgpu::ImageCopyTextureBase<Arc<wgpu::Texture>>> {
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
Expand Down Expand Up @@ -484,6 +512,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<wgpu::ImageCopyTextureBase<Arc<wgpu::Texture>>>,
) -> Option<wgpu::ImageCopyTextureBase<Arc<wgpu::Texture>>> {
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.
Expand Down
12 changes: 11 additions & 1 deletion vello/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -322,6 +330,8 @@ impl From<Encoding> for Scene {
}

/// Builder for encoding a glyph run.
///
/// Created using [`Scene::draw_glyphs`].
pub struct DrawGlyphs<'a> {
scene: &'a mut Scene,
run: GlyphRun,
Expand Down
2 changes: 1 addition & 1 deletion vello_shaders/shader/fine.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down

0 comments on commit 06f5558

Please sign in to comment.