[vello_encoding] Move the encoding module into its own crate

This change moves the vello encoding logic to a new crate under
crates/encoding. Combined with the `vello_shaders` crate, this enables
lightweight integration of the Vello pipelines into renderers that don't
depend on wgpu (or perhaps written in languages other than Rust).

The Scene/Fragment API currently remain the vello crate.
This commit is contained in:
Arman Uguray 2023-04-10 16:59:44 -07:00
parent b8e1bcfac3
commit db2fefdc8f
18 changed files with 69 additions and 58 deletions

View file

@ -2,6 +2,7 @@
resolver = "2" resolver = "2"
members = [ members = [
"crates/encoding",
"crates/shaders", "crates/shaders",
"integrations/vello_svg", "integrations/vello_svg",
@ -40,17 +41,20 @@ hot_reload = []
buffer_labels = [] buffer_labels = []
[dependencies] [dependencies]
bytemuck = { workspace = true }
fello = { workspace = true }
peniko = { workspace = true }
wgpu = { workspace = true } wgpu = { workspace = true }
raw-window-handle = "0.5" raw-window-handle = "0.5"
futures-intrusive = "0.5.0" futures-intrusive = "0.5.0"
parking_lot = "0.12" parking_lot = "0.12"
bytemuck = { version = "1.12.1", features = ["derive"] }
smallvec = "1.8.0" smallvec = "1.8.0"
fello = { git = "https://github.com/dfrg/fount", rev = "58a284eaae67512fb61cf76177c5d33238d79cb1" } vello_encoding = { path = "crates/encoding" }
peniko = { git = "https://github.com/linebender/peniko", rev = "cafdac9a211a0fb2fec5656bd663d1ac770bcc81" }
guillotiere = "0.6.2"
[workspace.dependencies] [workspace.dependencies]
bytemuck = { version = "1.12.1", features = ["derive"] }
fello = { git = "https://github.com/dfrg/fount", rev = "58a284eaae67512fb61cf76177c5d33238d79cb1" }
peniko = { git = "https://github.com/linebender/peniko", rev = "cafdac9a211a0fb2fec5656bd663d1ac770bcc81" }
wgpu = "0.15" wgpu = "0.15"
# Used for examples # Used for examples

View file

@ -0,0 +1,10 @@
[package]
name = "vello_encoding"
version = "0.1.0"
edition = "2021"
[dependencies]
bytemuck = { workspace = true }
fello = { workspace = true }
peniko = { workspace = true }
guillotiere = "0.6.2"

View file

@ -14,11 +14,9 @@
// //
// Also licensed under MIT license, at your choice. // Also licensed under MIT license, at your choice.
use crate::encoding::DrawImage;
use super::{ use super::{
resolve::Patch, DrawColor, DrawLinearGradient, DrawRadialGradient, DrawTag, Glyph, GlyphRun, resolve::Patch, DrawColor, DrawImage, DrawLinearGradient, DrawRadialGradient, DrawTag, Glyph,
PathEncoder, PathTag, Transform, GlyphRun, PathEncoder, PathTag, Transform,
}; };
use fello::NormalizedCoord; use fello::NormalizedCoord;

View file

@ -59,11 +59,11 @@ impl GlyphCache {
Style::Fill(Fill::EvenOdd) => encoding_cache.encode_linewidth(-2.0), Style::Fill(Fill::EvenOdd) => encoding_cache.encode_linewidth(-2.0),
Style::Stroke(stroke) => encoding_cache.encode_linewidth(stroke.width), Style::Stroke(stroke) => encoding_cache.encode_linewidth(stroke.width),
} }
let mut path = crate::glyph::PathEncoderPen(encoding_cache.encode_path(is_fill)); let mut path = encoding_cache.encode_path(is_fill);
scaler scaler
.outline(GlyphId::new(key.glyph_id as u16), &mut path) .outline(GlyphId::new(key.glyph_id as u16), &mut path)
.ok()?; .ok()?;
if path.0.finish(false) == 0 { if path.finish(false) == 0 {
return None; return None;
} }
let end = encoding_cache.stream_offsets(); let end = encoding_cache.stream_offsets();

View file

@ -381,3 +381,25 @@ impl<'a> PathEncoder<'a> {
self.n_encoded_segments self.n_encoded_segments
} }
} }
impl fello::scale::Pen for PathEncoder<'_> {
fn move_to(&mut self, x: f32, y: f32) {
self.move_to(x, y)
}
fn line_to(&mut self, x: f32, y: f32) {
self.line_to(x, y)
}
fn quad_to(&mut self, cx0: f32, cy0: f32, x: f32, y: f32) {
self.quad_to(cx0, cy0, x, y)
}
fn curve_to(&mut self, cx0: f32, cy0: f32, cx1: f32, cy1: f32, x: f32, y: f32) {
self.cubic_to(cx0, cy0, cx1, cy1, x, y)
}
fn close(&mut self) {
self.close()
}
}

View file

@ -25,7 +25,6 @@ use super::{
ramp_cache::{RampCache, Ramps}, ramp_cache::{RampCache, Ramps},
DrawTag, Encoding, PathTag, StreamOffsets, Transform, DrawTag, Encoding, PathTag, StreamOffsets, Transform,
}; };
use crate::shaders;
/// Layout of a packed encoding. /// Layout of a packed encoding.
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
@ -161,6 +160,7 @@ impl Resolver {
&'a mut self, &'a mut self,
encoding: &Encoding, encoding: &Encoding,
packed: &mut Vec<u8>, packed: &mut Vec<u8>,
workgroup_size: u32,
) -> (Layout, Ramps<'a>, Images<'a>) { ) -> (Layout, Ramps<'a>, Images<'a>) {
let sizes = self.resolve_patches(encoding); let sizes = self.resolve_patches(encoding);
self.resolve_pending_images(); self.resolve_pending_images();
@ -172,7 +172,7 @@ impl Resolver {
// Compute size of data buffer // Compute size of data buffer
let n_path_tags = let n_path_tags =
encoding.path_tags.len() + sizes.path_tags + encoding.n_open_clips as usize; encoding.path_tags.len() + sizes.path_tags + encoding.n_open_clips as usize;
let path_tag_padded = align_up(n_path_tags, 4 * shaders::PATHTAG_REDUCE_WG); let path_tag_padded = align_up(n_path_tags, 4 * workgroup_size);
let capacity = path_tag_padded let capacity = path_tag_padded
+ slice_size_in_bytes(&encoding.path_data, sizes.path_data) + slice_size_in_bytes(&encoding.path_data, sizes.path_data)
+ slice_size_in_bytes( + slice_size_in_bytes(

View file

@ -12,6 +12,7 @@ repository.workspace = true
[dependencies] [dependencies]
vello = { path = "../../" } vello = { path = "../../" }
vello_encoding = { path = "../../crates/encoding" }
vello_svg = { path = "../../integrations/vello_svg" } vello_svg = { path = "../../integrations/vello_svg" }
anyhow = { workspace = true } anyhow = { workspace = true }
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }

View file

@ -17,7 +17,6 @@
use std::sync::Arc; use std::sync::Arc;
use vello::{ use vello::{
encoding::Glyph,
fello::meta::MetadataProvider, fello::meta::MetadataProvider,
fello::raw::FontRef, fello::raw::FontRef,
glyph::GlyphContext, glyph::GlyphContext,
@ -25,6 +24,7 @@ use vello::{
peniko::{Blob, Brush, BrushRef, Font, StyleRef}, peniko::{Blob, Brush, BrushRef, Font, StyleRef},
SceneBuilder, SceneBuilder,
}; };
use vello_encoding::Glyph;
// This is very much a hack to get things working. // This is very much a hack to get things working.
// On Windows, can set this to "c:\\Windows\\Fonts\\seguiemj.ttf" to get color emoji // On Windows, can set this to "c:\\Windows\\Fonts\\seguiemj.ttf" to get color emoji

View file

@ -16,18 +16,17 @@
//! Support for glyph rendering. //! Support for glyph rendering.
use fello::scale::Pen;
use crate::encoding::{Encoding, PathEncoder};
use crate::scene::{SceneBuilder, SceneFragment}; use crate::scene::{SceneBuilder, SceneFragment};
use peniko::kurbo::Affine; use {
use peniko::{Brush, Color, Fill, Style}; fello::{
raw::types::GlyphId,
use fello::{ raw::FontRef,
raw::types::GlyphId, scale::{Context, Pen, Scaler},
raw::FontRef, FontKey, Setting, Size,
scale::{Context, Scaler}, },
FontKey, Setting, Size, peniko::kurbo::Affine,
peniko::{Brush, Color, Fill, Style},
vello_encoding::Encoding,
}; };
/// General context for creating scene fragments for glyph outlines. /// General context for creating scene fragments for glyph outlines.
@ -105,9 +104,9 @@ impl<'a> GlyphProvider<'a> {
Style::Fill(Fill::EvenOdd) => encoding.encode_linewidth(-2.0), Style::Fill(Fill::EvenOdd) => encoding.encode_linewidth(-2.0),
Style::Stroke(stroke) => encoding.encode_linewidth(stroke.width), Style::Stroke(stroke) => encoding.encode_linewidth(stroke.width),
} }
let mut path = PathEncoderPen(encoding.encode_path(matches!(style, Style::Fill(_)))); let mut path = encoding.encode_path(matches!(style, Style::Fill(_)));
self.scaler.outline(GlyphId::new(gid), &mut path).ok()?; self.scaler.outline(GlyphId::new(gid), &mut path).ok()?;
if path.0.finish(false) != 0 { if path.finish(false) != 0 {
Some(()) Some(())
} else { } else {
None None
@ -144,27 +143,3 @@ impl Pen for BezPathPen {
self.0.close_path() self.0.close_path()
} }
} }
pub(crate) struct PathEncoderPen<'a>(pub PathEncoder<'a>);
impl Pen for PathEncoderPen<'_> {
fn move_to(&mut self, x: f32, y: f32) {
self.0.move_to(x, y)
}
fn line_to(&mut self, x: f32, y: f32) {
self.0.line_to(x, y)
}
fn quad_to(&mut self, cx0: f32, cy0: f32, x: f32, y: f32) {
self.0.quad_to(cx0, cy0, x, y)
}
fn curve_to(&mut self, cx0: f32, cy0: f32, cx1: f32, cy1: f32, x: f32, y: f32) {
self.0.cubic_to(cx0, cy0, cx1, cy1, x, y)
}
fn close(&mut self) {
self.0.close()
}
}

View file

@ -1,13 +1,15 @@
//! Take an encoded scene and create a graph to render it //! Take an encoded scene and create a graph to render it
use bytemuck::{Pod, Zeroable};
use crate::{ use crate::{
encoding::{Config, Encoding, Layout},
engine::{BufProxy, ImageFormat, ImageProxy, Recording, ResourceProxy}, engine::{BufProxy, ImageFormat, ImageProxy, Recording, ResourceProxy},
shaders::{self, FullShaders, Shaders}, shaders::{self, FullShaders, Shaders},
RenderParams, Scene, RenderParams, Scene,
}; };
use {
bytemuck::{Pod, Zeroable},
vello_encoding::{Config, Encoding, Layout},
};
/// State for a render in progress. /// State for a render in progress.
pub struct Render { pub struct Render {
@ -213,11 +215,11 @@ impl Render {
params: &RenderParams, params: &RenderParams,
robust: bool, robust: bool,
) -> Recording { ) -> Recording {
use crate::encoding::Resolver; use vello_encoding::Resolver;
let mut recording = Recording::default(); let mut recording = Recording::default();
let mut resolver = Resolver::new(); let mut resolver = Resolver::new();
let mut packed = vec![]; let mut packed = vec![];
let (layout, ramps, images) = resolver.resolve(encoding, &mut packed); let (layout, ramps, images) = resolver.resolve(encoding, &mut packed, shaders::PATHTAG_REDUCE_WG);
let gradient_image = if ramps.height == 0 { let gradient_image = if ramps.height == 0 {
ResourceProxy::new_image(1, 1, ImageFormat::Rgba8) ResourceProxy::new_image(1, 1, ImageFormat::Rgba8)
} else { } else {
@ -245,7 +247,7 @@ impl Render {
let new_height = next_multiple_of(params.height, 16); let new_height = next_multiple_of(params.height, 16);
let info_size = layout.bin_data_start; let info_size = layout.bin_data_start;
let config = crate::encoding::Config { let config = vello_encoding::Config {
width_in_tiles: new_width / 16, width_in_tiles: new_width / 16,
height_in_tiles: new_height / 16, height_in_tiles: new_height / 16,
target_width: params.width, target_width: params.width,

View file

@ -17,8 +17,7 @@
use fello::NormalizedCoord; use fello::NormalizedCoord;
use peniko::kurbo::{Affine, Rect, Shape}; use peniko::kurbo::{Affine, Rect, Shape};
use peniko::{BlendMode, BrushRef, Color, Fill, Font, Image, Stroke, StyleRef}; use peniko::{BlendMode, BrushRef, Color, Fill, Font, Image, Stroke, StyleRef};
use vello_encoding::{Encoding, Glyph, GlyphRun, Patch, Transform};
use crate::encoding::{Encoding, Glyph, GlyphRun, Patch, Transform};
/// Encoded definition of a scene and associated resources. /// Encoded definition of a scene and associated resources.
#[derive(Default)] #[derive(Default)]