From 897dea6d991d4639aa08503d2512626ead33e850 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:16:05 +0000 Subject: [PATCH 1/4] Use rayon when resolving glyphs --- Cargo.lock | 47 ++++++ vello_encoding/Cargo.toml | 4 +- vello_encoding/src/encoding.rs | 2 +- vello_encoding/src/glyph_cache.rs | 243 ++++++++++++++++++++---------- vello_encoding/src/path.rs | 3 +- vello_encoding/src/resolve.rs | 60 +++++--- 6 files changed, 255 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c78eda1..9b4ce1af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -535,6 +535,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -595,6 +614,12 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "env_filter" version = "0.1.2" @@ -1866,6 +1891,26 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "read-fonts" version = "0.25.0" @@ -2518,8 +2563,10 @@ dependencies = [ "bytemuck", "guillotiere", "peniko", + "rayon", "skrifa", "smallvec", + "tracing", ] [[package]] diff --git a/vello_encoding/Cargo.toml b/vello_encoding/Cargo.toml index cc684ffe..5bb352a5 100644 --- a/vello_encoding/Cargo.toml +++ b/vello_encoding/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vello_encoding" -version.workspace = true # We mimic Vello's version +version.workspace = true # We mimic Vello's version description = "Vello types that represent the data that needs to be rendered." categories = ["rendering", "graphics"] keywords = ["2d", "vector-graphics"] @@ -30,3 +30,5 @@ skrifa = { workspace = true } peniko = { workspace = true } guillotiere = { version = "0.6.2" } smallvec = { workspace = true } +rayon = "1.10.0" +tracing = { default-features = false, version = "0.1.41" } diff --git a/vello_encoding/src/encoding.rs b/vello_encoding/src/encoding.rs index d581acd4..d6b223d7 100644 --- a/vello_encoding/src/encoding.rs +++ b/vello_encoding/src/encoding.rs @@ -186,7 +186,7 @@ impl Encoding { self.encode_style(Style::from_stroke(stroke)); } - fn encode_style(&mut self, style: Style) { + pub(crate) fn encode_style(&mut self, style: Style) { if self.flags & Self::FORCE_NEXT_STYLE != 0 || self.styles.last() != Some(&style) { self.path_tags.push(PathTag::STYLE); self.styles.push(style); diff --git a/vello_encoding/src/glyph_cache.rs b/vello_encoding/src/glyph_cache.rs index c0933506..974ec11f 100644 --- a/vello_encoding/src/glyph_cache.rs +++ b/vello_encoding/src/glyph_cache.rs @@ -7,19 +7,19 @@ use std::sync::Arc; use super::{Encoding, StreamOffsets}; use peniko::{Font, Style}; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use skrifa::instance::{NormalizedCoord, Size}; use skrifa::outline::{HintingInstance, HintingOptions, OutlineGlyphFormat}; use skrifa::{GlyphId, MetadataProvider, OutlineGlyphCollection}; #[derive(Default)] pub(crate) struct GlyphCache { - free_list: Vec<Arc<Encoding>>, map: GlyphMap, var_map: HashMap<VarKey, GlyphMap>, cached_count: usize, - hinting: HintCache, serial: u64, last_prune_serial: u64, + unresolved: Vec<(VarKey, GlyphKey, Font)>, } impl GlyphCache { @@ -33,7 +33,6 @@ impl GlyphCache { ) -> Option<GlyphCacheSession<'a>> { let font_id = font.data.id(); let font_index = font.index; - let font = skrifa::FontRef::from_index(font.data.as_ref(), font.index).ok()?; let map = if !coords.is_empty() { // This is still ugly in rust. Choices are: // 1. multiple lookups in the hashmap (implemented here) @@ -48,20 +47,7 @@ impl GlyphCache { } else { &mut self.map }; - let outlines = font.outline_glyphs(); let size = Size::new(size); - let hinter = if hint { - let key = HintKey { - font_id, - font_index, - outlines: &outlines, - size, - coords, - }; - self.hinting.get(&key) - } else { - None - }; // TODO: we're ignoring dashing for now let style_bits = match style { Style::Fill(fill) => super::path::Style::from_fill(*fill), @@ -69,32 +55,27 @@ impl GlyphCache { }; let style_bits: [u32; 2] = bytemuck::cast(style_bits); Some(GlyphCacheSession { - free_list: &mut self.free_list, map, font_id, font_index, coords, - size, size_bits: size.ppem().unwrap().to_bits(), - style, style_bits, - outlines, - hinter, + hint, + font, serial: self.serial, - cached_count: &mut self.cached_count, + unresolved: &mut self.unresolved, }) } pub(crate) fn maintain(&mut self) { + self.unresolved.clear(); // Maximum number of resolve phases where we'll retain an unused glyph const MAX_ENTRY_AGE: u64 = 64; // Maximum number of resolve phases before we force a prune const PRUNE_FREQUENCY: u64 = 64; // Always prune if the cached count is greater than this value const CACHED_COUNT_THRESHOLD: usize = 256; - // Number of encoding buffers we'll keep on the free list - const MAX_FREE_LIST_SIZE: usize = 32; - let free_list = &mut self.free_list; let serial = self.serial; self.serial += 1; // Don't iterate over the whole cache every frame @@ -106,9 +87,6 @@ impl GlyphCache { self.last_prune_serial = serial; self.map.retain(|_, entry| { if serial - entry.serial > MAX_ENTRY_AGE { - if free_list.len() < MAX_FREE_LIST_SIZE { - free_list.push(entry.encoding.clone()); - } self.cached_count -= 1; false } else { @@ -118,9 +96,6 @@ impl GlyphCache { self.var_map.retain(|_, map| { map.retain(|_, entry| { if serial - entry.serial > MAX_ENTRY_AGE { - if free_list.len() < MAX_FREE_LIST_SIZE { - free_list.push(entry.encoding.clone()); - } self.cached_count -= 1; false } else { @@ -130,81 +105,175 @@ impl GlyphCache { !map.is_empty() }); } + pub(crate) fn resolve_in_parallel(&mut self) { + tracing::trace_span!("Resolving glyph outlines", count = self.unresolved.len()); + let result = self + .unresolved + .par_iter() + .map_init(HintCache::default, |hint_cache, (coords, glyph, font)| { + tracing::trace_span!("Resolving single glyph"); + ( + resolve_single_glyph(hint_cache, coords, glyph, font), + coords, + glyph, + ) + }) + .collect_vec_list(); + for (result, coords, glyph) in result.into_iter().flatten() { + let map = if !coords.is_empty() { + self.var_map.get_mut(coords).unwrap() + } else { + &mut self.map + }; + let (encoding, offsets) = result.unwrap_or_default(); + map.get_mut(glyph).unwrap().status = GlyphEntryStatus::Resolved { + encoding, + stream_sizes: offsets, + }; + } + } + pub(crate) fn get_resolved(&mut self, idx: usize) -> (Arc<Encoding>, StreamOffsets) { + let (coords, glyph, _) = &mut self.unresolved[idx]; + let map = if !coords.is_empty() { + self.var_map.get_mut(coords).unwrap() + } else { + &mut self.map + }; + match &mut map.get_mut(glyph).unwrap().status { + GlyphEntryStatus::Resolved { + encoding, + stream_sizes, + } => (encoding.clone(), *stream_sizes), + GlyphEntryStatus::Unresolved { .. } => unreachable!(), + } + } +} + +fn resolve_single_glyph( + hint_cache: &mut HintCache, + coords: &smallvec::SmallVec<[skrifa::raw::types::F2Dot14; 8]>, + glyph: &GlyphKey, + font: &Font, +) -> Option<(Arc<Encoding>, StreamOffsets)> { + let font_id = font.data.id(); + let font_index = font.index; + let font = skrifa::FontRef::from_index(font.data.as_ref(), font.index).ok()?; + let outlines = font.outline_glyphs(); + let size = Size::new(f32::from_bits(glyph.font_size_bits)); + let outline = outlines.get(GlyphId::new(glyph.glyph_id))?; + let mut encoding = Encoding::default(); + encoding.reset(); + let style: crate::Style = bytemuck::cast(glyph.style_bits); + encoding.encode_style(style); + let is_fill = style.is_fill(); + use skrifa::outline::DrawSettings; + let mut path = encoding.encode_path(is_fill); + let hinter = if glyph.hint { + let key = HintKey { + font_id, + font_index, + outlines: &outlines, + size, + coords, + }; + hint_cache.get(&key) + } else { + None + }; + let draw_settings = if let Some(hinter) = hinter { + DrawSettings::hinted(hinter, false) + } else { + DrawSettings::unhinted(size, &**coords) + }; + outline.draw(draw_settings, &mut path).ok()?; + if path.finish(false) == 0 { + encoding.reset(); + } + let stream_sizes = encoding.stream_offsets(); + let arc_encoding = Arc::new(encoding); + Some((arc_encoding, stream_sizes)) } pub(crate) struct GlyphCacheSession<'a> { - free_list: &'a mut Vec<Arc<Encoding>>, map: &'a mut GlyphMap, font_id: u64, font_index: u32, coords: &'a [NormalizedCoord], - size: Size, size_bits: u32, - style: &'a Style, style_bits: [u32; 2], - outlines: OutlineGlyphCollection<'a>, - hinter: Option<&'a HintingInstance>, + font: &'a Font, serial: u64, - cached_count: &'a mut usize, + hint: bool, + unresolved: &'a mut Vec<(VarKey, GlyphKey, Font)>, } impl GlyphCacheSession<'_> { - pub(crate) fn get_or_insert( - &mut self, - glyph_id: u32, - ) -> Option<(Arc<Encoding>, StreamOffsets)> { + pub(crate) fn get_or_insert(&mut self, glyph_id: u32) -> GlyphEntryStatus { let key = GlyphKey { font_id: self.font_id, font_index: self.font_index, glyph_id, font_size_bits: self.size_bits, style_bits: self.style_bits, - hint: self.hinter.is_some(), + hint: self.hint, }; if let Some(entry) = self.map.get_mut(&key) { entry.serial = self.serial; - return Some((entry.encoding.clone(), entry.stream_sizes)); + return entry.status.clone(); } - let outline = self.outlines.get(GlyphId::new(key.glyph_id))?; - let mut encoding = self.free_list.pop().unwrap_or_default(); - let encoding_ptr = Arc::make_mut(&mut encoding); - encoding_ptr.reset(); - let is_fill = match &self.style { - Style::Fill(fill) => { - encoding_ptr.encode_fill_style(*fill); - true - } - Style::Stroke(stroke) => { - encoding_ptr.encode_stroke_style(stroke); - false - } - }; - use skrifa::outline::DrawSettings; - let mut path = encoding_ptr.encode_path(is_fill); - let draw_settings = if key.hint { - if let Some(hinter) = self.hinter { - DrawSettings::hinted(hinter, false) - } else { - DrawSettings::unhinted(self.size, self.coords) - } - } else { - DrawSettings::unhinted(self.size, self.coords) - }; - outline.draw(draw_settings, &mut path).ok()?; - if path.finish(false) == 0 { - encoding_ptr.reset(); - } - let stream_sizes = encoding_ptr.stream_offsets(); + let index = self.unresolved.len(); + self.unresolved + .push((self.coords.into(), key, self.font.clone())); + let result = GlyphEntryStatus::Unresolved { index }; self.map.insert( key, GlyphEntry { - encoding: encoding.clone(), - stream_sizes, + status: result.clone(), serial: self.serial, }, ); - *self.cached_count += 1; - Some((encoding, stream_sizes)) + result + + // let outline = self.outlines.get(GlyphId::new(key.glyph_id))?; + // let mut encoding = Encoding::default(); + // encoding.reset(); + // let is_fill = match &self.style { + // Style::Fill(fill) => { + // encoding.encode_fill_style(*fill); + // true + // } + // Style::Stroke(stroke) => { + // encoding.encode_stroke_style(stroke); + // false + // } + // }; + // use skrifa::outline::DrawSettings; + // let mut path = encoding.encode_path(is_fill); + // let draw_settings = if key.hint { + // if let Some(hinter) = self.hinter { + // DrawSettings::hinted(hinter, false) + // } else { + // DrawSettings::unhinted(self.size, self.coords) + // } + // } else { + // DrawSettings::unhinted(self.size, self.coords) + // }; + // outline.draw(draw_settings, &mut path).ok()?; + // if path.finish(false) == 0 { + // encoding.reset(); + // } + // let stream_sizes = encoding.stream_offsets(); + // let arc_encoding = Arc::new(encoding); + // self.map.insert( + // key, + // GlyphEntry { + // encoding: arc_encoding.clone(), + // stream_sizes, + // serial: self.serial, + // }, + // ); + // *self.cached_count += 1; + // Some((arc_encoding, stream_sizes)) } } @@ -225,18 +294,28 @@ type VarKey = smallvec::SmallVec<[NormalizedCoord; 8]>; type GlyphMap = HashMap<GlyphKey, GlyphEntry>; -#[derive(Clone, Default)] +// #[derive(Clone, Default)] struct GlyphEntry { - encoding: Arc<Encoding>, - stream_sizes: StreamOffsets, + status: GlyphEntryStatus, /// Last use of this entry. serial: u64, } +#[derive(Clone)] +pub(crate) enum GlyphEntryStatus { + Resolved { + encoding: Arc<Encoding>, + stream_sizes: StreamOffsets, + }, + Unresolved { + index: usize, + }, +} + /// We keep this small to enable a simple LRU cache with a linear /// search. Regenerating hinting data is low to medium cost so it's fine /// to redo it occasionally. -const MAX_CACHED_HINT_INSTANCES: usize = 8; +const MAX_CACHED_HINT_INSTANCES: usize = 2; pub(crate) struct HintKey<'a> { font_id: u64, @@ -264,7 +343,7 @@ const HINTING_OPTIONS: HintingOptions = HintingOptions { }; #[derive(Default)] -struct HintCache { +pub(crate) struct HintCache { // Split caches for glyf/cff because the instance type can reuse // internal memory when reconfigured for the same format. glyf_entries: Vec<HintEntry>, diff --git a/vello_encoding/src/path.rs b/vello_encoding/src/path.rs index a1703ce0..98703a16 100644 --- a/vello_encoding/src/path.rs +++ b/vello_encoding/src/path.rs @@ -175,8 +175,7 @@ impl Style { Some((self.flags_and_miter_limit & Self::MITER_LIMIT_MASK) as u16) } - #[cfg(test)] - fn is_fill(self) -> bool { + pub(crate) fn is_fill(self) -> bool { (self.flags_and_miter_limit & Self::FLAGS_STYLE_BIT) == 0 } } diff --git a/vello_encoding/src/resolve.rs b/vello_encoding/src/resolve.rs index 44c03e3f..2c9d5ee6 100644 --- a/vello_encoding/src/resolve.rs +++ b/vello_encoding/src/resolve.rs @@ -157,7 +157,7 @@ pub fn resolve_solid_paths_only(encoding: &Encoding, packed: &mut Vec<u8>) -> La #[derive(Default)] pub struct Resolver { glyph_cache: GlyphCache, - glyphs: Vec<Arc<Encoding>>, + glyphs: Vec<Option<Arc<Encoding>>>, ramp_cache: RampCache, image_cache: ImageCache, pending_images: Vec<PendingImage>, @@ -211,7 +211,9 @@ impl Resolver { } for glyph in &self.glyphs[glyphs.clone()] { data.extend_from_slice(bytemuck::bytes_of(&PathTag::TRANSFORM)); - data.extend_from_slice(bytemuck::cast_slice(&glyph.path_tags)); + data.extend_from_slice(bytemuck::cast_slice( + &glyph.as_ref().unwrap().path_tags, + )); } data.extend_from_slice(bytemuck::bytes_of(&PathTag::PATH)); } @@ -239,7 +241,9 @@ impl Resolver { pos = stream_offset; } for glyph in &self.glyphs[glyphs.clone()] { - data.extend_from_slice(bytemuck::cast_slice(&glyph.path_data)); + data.extend_from_slice(bytemuck::cast_slice( + &glyph.as_ref().unwrap().path_data, + )); } } } @@ -361,7 +365,9 @@ impl Resolver { pos = stream_offset; } for glyph in &self.glyphs[glyphs.clone()] { - data.extend_from_slice(bytemuck::cast_slice(&glyph.styles)); + data.extend_from_slice(bytemuck::cast_slice( + &glyph.as_ref().unwrap().styles, + )); } } } @@ -382,6 +388,7 @@ impl Resolver { self.image_cache.clear(); self.pending_images.clear(); self.patches.clear(); + let mut unresolved = Vec::new(); let mut sizes = StreamOffsets::default(); let resources = &encoding.resources; for patch in &resources.patches { @@ -398,9 +405,9 @@ impl Resolver { extend: *extend, }); } - Patch::GlyphRun { index } => { + Patch::GlyphRun { index: run_index } => { let mut run_sizes = StreamOffsets::default(); - let run = &resources.glyph_runs[*index]; + let run = &resources.glyph_runs[*run_index]; let glyphs = &resources.glyphs[run.glyphs.clone()]; let coords = &resources.normalized_coords[run.normalized_coords.clone()]; let mut hint = run.hint; @@ -429,24 +436,33 @@ impl Resolver { continue; }; let glyph_start = self.glyphs.len(); - for glyph in glyphs { - let (encoding, stream_sizes) = - session.get_or_insert(glyph.id).unwrap_or_else(|| { - // HACK: We pretend that the encoding was empty. - // In theory, we should be able to skip this glyph, but there is also - // a corresponding entry in `resources`, which means that we would - // need to make the patching process skip this glyph. - (Arc::new(Encoding::new()), StreamOffsets::default()) - }); - run_sizes.add(&stream_sizes); - self.glyphs.push(encoding); + for glyph in glyphs.iter() { + let status = session.get_or_insert(glyph.id); + match status { + crate::glyph_cache::GlyphEntryStatus::Resolved { + encoding, + stream_sizes, + } => { + run_sizes.add(&stream_sizes); + self.glyphs.push(Some(encoding)); + } + crate::glyph_cache::GlyphEntryStatus::Unresolved { + index: resolved_index, + } => { + unresolved.push((resolved_index, self.glyphs.len())); + self.glyphs.push(None); + } + } } let glyph_end = self.glyphs.len(); run_sizes.path_tags += glyphs.len() + 1; run_sizes.transforms += glyphs.len(); + if run_sizes.draw_data > 0 { + panic!("We would corrupt the images or gradients."); + } sizes.add(&run_sizes); self.patches.push(ResolvedPatch::GlyphRun { - index: *index, + index: *run_index, glyphs: glyph_start..glyph_end, transform, scale, @@ -468,6 +484,14 @@ impl Resolver { } } } + + self.glyph_cache.resolve_in_parallel(); + for (resolved_index, glyphs_idx) in unresolved { + let (encoding, stream_size) = self.glyph_cache.get_resolved(resolved_index); + sizes.add(&stream_size); + self.glyphs[glyphs_idx] = Some(encoding); + } + sizes } From 8f2534f5d91287bf983d02f03be5e1def8d570c7 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:33:34 +0000 Subject: [PATCH 2/4] Actually enter the spans --- vello_encoding/src/glyph_cache.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vello_encoding/src/glyph_cache.rs b/vello_encoding/src/glyph_cache.rs index 974ec11f..0ee4ca23 100644 --- a/vello_encoding/src/glyph_cache.rs +++ b/vello_encoding/src/glyph_cache.rs @@ -106,12 +106,13 @@ impl GlyphCache { }); } pub(crate) fn resolve_in_parallel(&mut self) { - tracing::trace_span!("Resolving glyph outlines", count = self.unresolved.len()); + let _span = tracing::info_span!("Resolving glyph outlines", count = self.unresolved.len()) + .entered(); let result = self .unresolved .par_iter() .map_init(HintCache::default, |hint_cache, (coords, glyph, font)| { - tracing::trace_span!("Resolving single glyph"); + let _span = tracing::trace_span!("Resolving single glyph").entered(); ( resolve_single_glyph(hint_cache, coords, glyph, font), coords, From 5c0d094d1dc2b2ff31fd405a8845b51cef37aa88 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:41:49 +0000 Subject: [PATCH 3/4] Add more profiling info --- vello_encoding/src/glyph_cache.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/vello_encoding/src/glyph_cache.rs b/vello_encoding/src/glyph_cache.rs index 0ee4ca23..86c8467b 100644 --- a/vello_encoding/src/glyph_cache.rs +++ b/vello_encoding/src/glyph_cache.rs @@ -159,16 +159,26 @@ fn resolve_single_glyph( let font_id = font.data.id(); let font_index = font.index; let font = skrifa::FontRef::from_index(font.data.as_ref(), font.index).ok()?; - let outlines = font.outline_glyphs(); + + let outlines = { + let _span = tracing::trace_span!("Getting font outline builder").entered(); + font.outline_glyphs() + }; let size = Size::new(f32::from_bits(glyph.font_size_bits)); - let outline = outlines.get(GlyphId::new(glyph.glyph_id))?; + let outline = { + let _span = tracing::trace_span!("Getting Glyph Outline").entered(); + outlines.get(GlyphId::new(glyph.glyph_id))? + }; let mut encoding = Encoding::default(); encoding.reset(); let style: crate::Style = bytemuck::cast(glyph.style_bits); encoding.encode_style(style); let is_fill = style.is_fill(); use skrifa::outline::DrawSettings; - let mut path = encoding.encode_path(is_fill); + let mut path = { + let _span = tracing::trace_span!("Encoding path").entered(); + encoding.encode_path(is_fill) + }; let hinter = if glyph.hint { let key = HintKey { font_id, @@ -186,7 +196,10 @@ fn resolve_single_glyph( } else { DrawSettings::unhinted(size, &**coords) }; - outline.draw(draw_settings, &mut path).ok()?; + { + let _span = tracing::trace_span!("Drawing span").entered(); + outline.draw(draw_settings, &mut path).ok()?; + } if path.finish(false) == 0 { encoding.reset(); } From 7cc7a9760d7ed45a47a33f9b75aa49de86eae707 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Fri, 10 Jan 2025 08:50:10 +0000 Subject: [PATCH 4/4] Add a span around the hinter --- vello_encoding/src/glyph_cache.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vello_encoding/src/glyph_cache.rs b/vello_encoding/src/glyph_cache.rs index 86c8467b..12f34b5d 100644 --- a/vello_encoding/src/glyph_cache.rs +++ b/vello_encoding/src/glyph_cache.rs @@ -180,6 +180,7 @@ fn resolve_single_glyph( encoding.encode_path(is_fill) }; let hinter = if glyph.hint { + let _span = tracing::trace_span!("Getting hinter").entered(); let key = HintKey { font_id, font_index,