Skip to content

Commit

Permalink
[encoding] Replace linewidth stream with the new style encoding
Browse files Browse the repository at this point in the history
* The linewidth stream is now the "style" stream. This has been wired up
  all the way up to the `flatten` pipeline which uses the new encoding
  to extract the fill rule.

* Pipelines downstream of `flatten` still use the old linewidth scheme.
  They will be fixed up in a follow-up change.
  • Loading branch information
armansito committed Oct 22, 2023
1 parent 958d1cd commit d2715d2
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 53 deletions.
33 changes: 15 additions & 18 deletions crates/encoding/src/encoding.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2022 The Vello authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use super::{DrawColor, DrawTag, PathEncoder, PathTag, Transform};
use super::{DrawColor, DrawTag, PathEncoder, PathTag, Style, Transform};

use peniko::{kurbo::Shape, BlendMode, BrushRef, Color, Fill};

Expand All @@ -25,8 +25,8 @@ pub struct Encoding {
pub draw_data: Vec<u8>,
/// The transform stream.
pub transforms: Vec<Transform>,
/// The line width stream.
pub linewidths: Vec<f32>,
/// The style stream
pub styles: Vec<Style>,
/// Late bound resource data.
#[cfg(feature = "full")]
pub resources: Resources,
Expand Down Expand Up @@ -56,7 +56,7 @@ impl Encoding {
self.transforms.clear();
self.path_tags.clear();
self.path_data.clear();
self.linewidths.clear();
self.styles.clear();
self.draw_data.clear();
self.draw_tags.clear();
self.n_paths = 0;
Expand All @@ -67,7 +67,7 @@ impl Encoding {
self.resources.reset();
if !is_fragment {
self.transforms.push(Transform::IDENTITY);
self.linewidths.push(-1.0);
self.styles.push(Style::from_fill(&Fill::NonZero));
}
}

Expand Down Expand Up @@ -96,7 +96,7 @@ impl Encoding {
run.stream_offsets.draw_tags += offsets.draw_tags;
run.stream_offsets.draw_data += offsets.draw_data;
run.stream_offsets.transforms += offsets.transforms;
run.stream_offsets.linewidths += offsets.linewidths;
run.stream_offsets.styles += offsets.styles;
run
}));
self.resources
Expand Down Expand Up @@ -148,7 +148,7 @@ impl Encoding {
} else {
self.transforms.extend_from_slice(&other.transforms);
}
self.linewidths.extend_from_slice(&other.linewidths);
self.styles.extend_from_slice(&other.styles);
}

/// Returns a snapshot of the current stream offsets.
Expand All @@ -159,19 +159,16 @@ impl Encoding {
draw_tags: self.draw_tags.len(),
draw_data: self.draw_data.len(),
transforms: self.transforms.len(),
linewidths: self.linewidths.len(),
styles: self.styles.len(),
}
}

/// Encodes a fill style.
pub fn encode_fill_style(&mut self, fill: Fill) {
let linewidth = match fill {
Fill::NonZero => -1.0,
Fill::EvenOdd => -2.0,
};
if self.linewidths.last() != Some(&linewidth) {
self.path_tags.push(PathTag::LINEWIDTH);
self.linewidths.push(linewidth);
let style = Style::from_fill(&fill);
if self.styles.last() != Some(&style) {
self.path_tags.push(PathTag::STYLE);
self.styles.push(style);
}
}

Expand Down Expand Up @@ -449,8 +446,8 @@ pub struct StreamOffsets {
pub draw_data: usize,
/// Current length of transform stream.
pub transforms: usize,
/// Current length of linewidth stream.
pub linewidths: usize,
/// Current length of style stream.
pub styles: usize,
}

impl StreamOffsets {
Expand All @@ -461,6 +458,6 @@ impl StreamOffsets {
self.draw_tags += other.draw_tags;
self.draw_data += other.draw_data;
self.transforms += other.transforms;
self.linewidths += other.linewidths;
self.styles += other.styles;
}
}
2 changes: 1 addition & 1 deletion crates/encoding/src/glyph_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl CachedRange {
draw_tags: self.end.draw_tags - self.start.draw_tags,
draw_data: self.end.draw_data - self.start.draw_data,
transforms: self.end.transforms - self.start.transforms,
linewidths: self.end.linewidths - self.start.linewidths,
styles: self.end.styles - self.start.styles,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/encoding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub use math::Transform;
pub use monoid::Monoid;
pub use path::{
Cubic, LineSoup, Path, PathBbox, PathEncoder, PathMonoid, PathSegment, PathSegmentType,
PathTag, SegmentCount, Tile,
PathTag, SegmentCount, Style, Tile,
};
pub use resolve::{resolve_solid_paths_only, Layout};

Expand Down
13 changes: 7 additions & 6 deletions crates/encoding/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ impl PathTag {
/// Path marker.
pub const PATH: Self = Self(0x10);

/// Line width setting.
pub const LINEWIDTH: Self = Self(0x40);
/// Style setting.
pub const STYLE: Self = Self(0x40);

/// Bit for path segments that are represented as f32 values. If unset
/// they are represented as i16.
Expand Down Expand Up @@ -316,8 +316,8 @@ pub struct PathMonoid {
pub pathseg_ix: u32,
/// Offset into path segment stream.
pub pathseg_offset: u32,
/// Index into linewidth stream.
pub linewidth_ix: u32,
/// Index into style stream.
pub style_ix: u32,
/// Index of containing path.
pub path_ix: u32,
}
Expand All @@ -337,7 +337,8 @@ impl Monoid for PathMonoid {
a += a >> 16;
c.pathseg_offset = a & 0xff;
c.path_ix = (tag_word & (PathTag::PATH.0 as u32 * 0x1010101)).count_ones();
c.linewidth_ix = (tag_word & (PathTag::LINEWIDTH.0 as u32 * 0x1010101)).count_ones();
let style_size = (std::mem::size_of::<Style>() / std::mem::size_of::<u32>()) as u32;
c.style_ix = (tag_word & (PathTag::STYLE.0 as u32 * 0x1010101)).count_ones() * style_size;
c
}

Expand All @@ -347,7 +348,7 @@ impl Monoid for PathMonoid {
trans_ix: self.trans_ix + other.trans_ix,
pathseg_ix: self.pathseg_ix + other.pathseg_ix,
pathseg_offset: self.pathseg_offset + other.pathseg_offset,
linewidth_ix: self.linewidth_ix + other.linewidth_ix,
style_ix: self.style_ix + other.style_ix,
path_ix: self.path_ix + other.path_ix,
}
}
Expand Down
34 changes: 17 additions & 17 deletions crates/encoding/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use bytemuck::{Pod, Zeroable};

use super::{DrawTag, Encoding, PathTag, StreamOffsets, Transform};
use super::{DrawTag, Encoding, PathTag, StreamOffsets, Style, Transform};

#[cfg(feature = "full")]
use {
Expand Down Expand Up @@ -38,8 +38,8 @@ pub struct Layout {
pub draw_data_base: u32,
/// Start of transform stream.
pub transform_base: u32,
/// Start of linewidth stream.
pub linewidth_base: u32,
/// Start of style stream.
pub style_base: u32,
}

impl Layout {
Expand Down Expand Up @@ -92,13 +92,13 @@ impl Layout {
/// Returns the transform stream.
pub fn transforms<'a>(&self, data: &'a [u8]) -> &'a [Transform] {
let start = self.transform_base as usize * 4;
let end = self.linewidth_base as usize * 4;
let end = self.style_base as usize * 4;
bytemuck::cast_slice(&data[start..end])
}

/// Returns the linewidth stream.
pub fn linewidths<'a>(&self, data: &'a [u8]) -> &'a [f32] {
let start = self.linewidth_base as usize * 4;
/// Returns the style stream.
pub fn styles<'a>(&self, data: &'a [u8]) -> &'a [Style] {
let start = self.style_base as usize * 4;
bytemuck::cast_slice(&data[start..])
}
}
Expand Down Expand Up @@ -150,9 +150,9 @@ pub fn resolve_solid_paths_only(encoding: &Encoding, packed: &mut Vec<u8>) -> La
// Transform stream
layout.transform_base = size_to_words(data.len());
data.extend_from_slice(bytemuck::cast_slice(&encoding.transforms));
// Linewidth stream
layout.linewidth_base = size_to_words(data.len());
data.extend_from_slice(bytemuck::cast_slice(&encoding.linewidths));
// Style stream
layout.style_base = size_to_words(data.len());
data.extend_from_slice(bytemuck::cast_slice(&encoding.styles));
layout.n_draw_objects = layout.n_paths;
assert_eq!(buffer_size, data.len());
layout
Expand Down Expand Up @@ -359,21 +359,21 @@ impl Resolver {
data.extend_from_slice(bytemuck::cast_slice(&stream[pos..]));
}
}
// Linewidth stream
layout.linewidth_base = size_to_words(data.len());
// Style stream
layout.style_base = size_to_words(data.len());
{
let mut pos = 0;
let stream = &encoding.linewidths;
let stream = &encoding.styles;
for patch in &self.patches {
if let ResolvedPatch::GlyphRun { index, glyphs, .. } = patch {
let stream_offset = resources.glyph_runs[*index].stream_offsets.linewidths;
let stream_offset = resources.glyph_runs[*index].stream_offsets.styles;
if pos < stream_offset {
data.extend_from_slice(bytemuck::cast_slice(&stream[pos..stream_offset]));
pos = stream_offset;
}
for glyph in &self.glyph_ranges[glyphs.clone()] {
let glyph_data = &self.glyph_cache.encoding.linewidths
[glyph.start.linewidths..glyph.end.linewidths];
let glyph_data =
&self.glyph_cache.encoding.styles[glyph.start.styles..glyph.end.styles];
data.extend_from_slice(bytemuck::cast_slice(glyph_data));
}
}
Expand Down Expand Up @@ -612,7 +612,7 @@ impl SceneBufferSizes {
)
+ slice_size_in_bytes(&encoding.draw_data, patch_sizes.draw_data)
+ slice_size_in_bytes(&encoding.transforms, patch_sizes.transforms)
+ slice_size_in_bytes(&encoding.linewidths, patch_sizes.linewidths);
+ slice_size_in_bytes(&encoding.styles, patch_sizes.styles);
Self {
buffer_size,
path_tag_padded,
Expand Down
8 changes: 7 additions & 1 deletion shader/flatten.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,13 @@ fn main(
var tag_byte = (tag_word >> shift) & 0xffu;

let out = &path_bboxes[tm.path_ix];
let linewidth = bitcast<f32>(scene[config.linewidth_base + tm.linewidth_ix]);
let style_flags = scene[config.style_base + tm.style_ix];
// TODO: We assume all paths are fills at the moment. This is where we will extract the stroke
// vs fill state using STYLE_FLAGS_STYLE_BIT.
// TODO: The downstream pipelines still use the old floating-point linewidth/fill encoding scheme
// This will change to represent the fill rule as a single bit inside the bounding box and draw
// info data structures.
let linewidth = select(-2.0, -1.0, (style_flags & STYLE_FLAGS_FILL_BIT) == 0u);
if (tag_byte & PATH_TAG_PATH) != 0u {
(*out).linewidth = linewidth;
(*out).trans_ix = tm.trans_ix;
Expand Down
2 changes: 1 addition & 1 deletion shader/shared/config.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct Config {
drawdata_base: u32,

transform_base: u32,
linewidth_base: u32,
style_base: u32,

// Sizes of bump allocated buffers (in element size units)
binning_size: u32,
Expand Down
15 changes: 11 additions & 4 deletions shader/shared/pathtag.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct TagMonoid {
pathseg_ix: u32,
pathseg_offset: u32,
#ifdef full
linewidth_ix: u32,
style_ix: u32,
path_ix: u32,
#endif
}
Expand All @@ -19,9 +19,16 @@ let PATH_TAG_F32 = 8u;
let PATH_TAG_TRANSFORM = 0x20u;
#ifdef full
let PATH_TAG_PATH = 0x10u;
let PATH_TAG_LINEWIDTH = 0x40u;
let PATH_TAG_STYLE = 0x40u;
#endif

// Size of the `Style` data structure in words
let STYLE_SIZE_IN_WORDS: u32 = 2u;
let STYLE_FLAGS_STYLE_BIT: u32 = 0x80000000u;
let STYLE_FLAGS_FILL_BIT: u32 = 0x40000000u;

// TODO: Declare the remaining STYLE flags here.

fn tag_monoid_identity() -> TagMonoid {
return TagMonoid();
}
Expand All @@ -32,7 +39,7 @@ fn combine_tag_monoid(a: TagMonoid, b: TagMonoid) -> TagMonoid {
c.pathseg_ix = a.pathseg_ix + b.pathseg_ix;
c.pathseg_offset = a.pathseg_offset + b.pathseg_offset;
#ifdef full
c.linewidth_ix = a.linewidth_ix + b.linewidth_ix;
c.style_ix = a.style_ix + b.style_ix;
c.path_ix = a.path_ix + b.path_ix;
#endif
return c;
Expand All @@ -50,7 +57,7 @@ fn reduce_tag(tag_word: u32) -> TagMonoid {
c.pathseg_offset = a & 0xffu;
#ifdef full
c.path_ix = countOneBits(tag_word & (PATH_TAG_PATH * 0x1010101u));
c.linewidth_ix = countOneBits(tag_word & (PATH_TAG_LINEWIDTH * 0x1010101u));
c.style_ix = countOneBits(tag_word & (PATH_TAG_STYLE * 0x1010101u)) * STYLE_SIZE_IN_WORDS;
#endif
return c;
}
18 changes: 14 additions & 4 deletions src/cpu_shader/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use crate::cpu_dispatch::CpuBinding;

use super::util::{Transform, Vec2};
use vello_encoding::{BumpAllocators, ConfigUniform, LineSoup, Monoid, PathBbox, PathMonoid};
use vello_encoding::{
BumpAllocators, ConfigUniform, LineSoup, Monoid, PathBbox, PathMonoid, Style,
};

fn to_minus_one_quarter(x: f32) -> f32 {
// could also be written x.powf(-0.25)
Expand Down Expand Up @@ -211,11 +213,19 @@ fn flatten_main(
if tag_byte != 0 {
tm = tag_monoids[ix >> 2].combine(&tm);
}
let linewidth =
f32::from_bits(scene[(config.layout.linewidth_base + tm.linewidth_ix) as usize]);
let style_flags = scene[(config.layout.style_base + tm.style_ix) as usize];
if (tag_byte & PATH_TAG_PATH) != 0 {
let out = &mut path_bboxes[tm.path_ix as usize];
out.linewidth = linewidth;
// TODO: We assume all paths are fills at the moment. This is where we will extract the
// stroke vs fill state using STYLE_FLAGS_STYLE_BIT.
// TODO: The downstream pipelines still use the old floating-point linewidth/fill
// encoding scheme. This will change to represent the fill rule as a single bit inside
// the bounding box and draw info data structures.
out.linewidth = if (style_flags & Style::FLAGS_FILL_BIT) == 0 {
-1.0
} else {
-2.0
};
out.trans_ix = tm.trans_ix;
}
let seg_type = tag_byte & PATH_TAG_SEG_TYPE;
Expand Down

0 comments on commit d2715d2

Please sign in to comment.