From 46328c7a2c7ec449395b673d21cba7b27d5a80d6 Mon Sep 17 00:00:00 2001 From: Chad Brokaw Date: Tue, 2 May 2023 16:42:50 -0400 Subject: [PATCH] cleanup for review * rename resolve_simple to resolve_solid_paths_only to better capture the semantics of the function * move duplicated buffer size computation code to separate function * change Resolver::resolve to call resolve_solid_paths_only when encoding.patches.is_empty() is true. This is likely to be slightly faster and will ensure that the "simple" code path is actually used. --- crates/encoding/src/image_cache.rs | 1 + crates/encoding/src/lib.rs | 2 +- crates/encoding/src/resolve.rs | 88 ++++++++++++++++++------------ 3 files changed, 56 insertions(+), 35 deletions(-) diff --git a/crates/encoding/src/image_cache.rs b/crates/encoding/src/image_cache.rs index 85b658e..78f5cf7 100644 --- a/crates/encoding/src/image_cache.rs +++ b/crates/encoding/src/image_cache.rs @@ -8,6 +8,7 @@ use std::collections::{hash_map::Entry, HashMap}; const DEFAULT_ATLAS_SIZE: i32 = 1024; const MAX_ATLAS_SIZE: i32 = 8192; +#[derive(Default)] pub struct Images<'a> { pub width: u32, pub height: u32, diff --git a/crates/encoding/src/lib.rs b/crates/encoding/src/lib.rs index 529fdc6..748354c 100644 --- a/crates/encoding/src/lib.rs +++ b/crates/encoding/src/lib.rs @@ -35,4 +35,4 @@ pub use path::{ Cubic, Path, PathBbox, PathEncoder, PathMonoid, PathSegment, PathSegmentType, PathTag, Tile, }; pub use ramp_cache::Ramps; -pub use resolve::{resolve_simple, Layout, Patch, Resolver}; +pub use resolve::{resolve_solid_paths_only, Layout, Patch, Resolver}; diff --git a/crates/encoding/src/resolve.rs b/crates/encoding/src/resolve.rs index fa1a641..1a5ba9e 100644 --- a/crates/encoding/src/resolve.rs +++ b/crates/encoding/src/resolve.rs @@ -100,14 +100,16 @@ impl Layout { } } -/// Resolves and packs an encoding that doesn't contain late bound resources -/// (gradients, images and glyph runs). -pub fn resolve_simple(encoding: &Encoding, packed: &mut Vec) -> Layout { +/// Resolves and packs an encoding that contains only paths with solid color +/// fills. +/// +/// Panics if the encoding contains any late bound resources (gradients, images +/// or glyph runs). +pub fn resolve_solid_paths_only(encoding: &Encoding, packed: &mut Vec) -> Layout { assert!( encoding.patches.is_empty(), "this resolve function doesn't support late bound resources" ); - let sizes = StreamOffsets::default(); let data = packed; data.clear(); let mut layout = Layout { @@ -115,25 +117,18 @@ pub fn resolve_simple(encoding: &Encoding, packed: &mut Vec) -> Layout { n_clips: encoding.n_clips, ..Layout::default() }; - // Compute size of data buffer - let n_path_tags = encoding.path_tags.len() + sizes.path_tags + encoding.n_open_clips as usize; - let path_tag_padded = align_up(n_path_tags, 4 * crate::config::PATH_REDUCE_WG); - let capacity = path_tag_padded - + slice_size_in_bytes(&encoding.path_data, sizes.path_data) - + slice_size_in_bytes( - &encoding.draw_tags, - sizes.draw_tags + encoding.n_open_clips as usize, - ) - + slice_size_in_bytes(&encoding.draw_data, sizes.draw_data) - + slice_size_in_bytes(&encoding.transforms, sizes.transforms) - + slice_size_in_bytes(&encoding.linewidths, sizes.linewidths); - data.reserve(capacity); + let SceneBufferSizes { + buffer_size, + path_tag_padded, + } = SceneBufferSizes::new(encoding, &StreamOffsets::default()); + data.reserve(buffer_size); // Path tag stream layout.path_tag_base = size_to_words(data.len()); data.extend_from_slice(bytemuck::cast_slice(&encoding.path_tags)); for _ in 0..encoding.n_open_clips { data.extend_from_slice(bytemuck::bytes_of(&PathTag::PATH)); } + data.resize(path_tag_padded, 0); // Path data stream layout.path_data_base = size_to_words(data.len()); data.extend_from_slice(bytemuck::cast_slice(&encoding.path_data)); @@ -155,7 +150,7 @@ pub fn resolve_simple(encoding: &Encoding, packed: &mut Vec) -> Layout { layout.linewidth_base = size_to_words(data.len()); data.extend_from_slice(bytemuck::cast_slice(&encoding.linewidths)); layout.n_draw_objects = layout.n_paths; - assert_eq!(capacity, data.len()); + assert_eq!(buffer_size, data.len()); layout } @@ -184,7 +179,11 @@ impl Resolver { encoding: &Encoding, packed: &mut Vec, ) -> (Layout, Ramps<'a>, Images<'a>) { - let sizes = self.resolve_patches(encoding); + if encoding.patches.is_empty() { + let layout = resolve_solid_paths_only(encoding, packed); + return (layout, Ramps::default(), Images::default()); + } + let patch_sizes = self.resolve_patches(encoding); self.resolve_pending_images(); let data = packed; data.clear(); @@ -193,20 +192,11 @@ impl Resolver { n_clips: encoding.n_clips, ..Layout::default() }; - // Compute size of data buffer - let n_path_tags = - encoding.path_tags.len() + sizes.path_tags + encoding.n_open_clips as usize; - let path_tag_padded = align_up(n_path_tags, 4 * crate::config::PATH_REDUCE_WG); - let capacity = path_tag_padded - + slice_size_in_bytes(&encoding.path_data, sizes.path_data) - + slice_size_in_bytes( - &encoding.draw_tags, - sizes.draw_tags + encoding.n_open_clips as usize, - ) - + slice_size_in_bytes(&encoding.draw_data, sizes.draw_data) - + slice_size_in_bytes(&encoding.transforms, sizes.transforms) - + slice_size_in_bytes(&encoding.linewidths, sizes.linewidths); - data.reserve(capacity); + let SceneBufferSizes { + buffer_size, + path_tag_padded, + } = SceneBufferSizes::new(encoding, &patch_sizes); + data.reserve(buffer_size); // Path tag stream layout.path_tag_base = size_to_words(data.len()); { @@ -382,7 +372,7 @@ impl Resolver { } } layout.n_draw_objects = layout.n_paths; - assert_eq!(capacity, data.len()); + assert_eq!(buffer_size, data.len()); (layout, self.ramp_cache.ramps(), self.image_cache.images()) } @@ -577,6 +567,36 @@ enum ResolvedPatch { }, } +struct SceneBufferSizes { + /// Full size of the scene buffer in bytes. + buffer_size: usize, + /// Padded length of the path tag stream in bytes. + path_tag_padded: usize, +} + +impl SceneBufferSizes { + /// Computes common scene buffer sizes for the given encoding and patch + /// stream sizes. + fn new(encoding: &Encoding, patch_sizes: &StreamOffsets) -> Self { + let n_path_tags = + encoding.path_tags.len() + patch_sizes.path_tags + encoding.n_open_clips as usize; + let path_tag_padded = align_up(n_path_tags, 4 * crate::config::PATH_REDUCE_WG); + let buffer_size = path_tag_padded + + slice_size_in_bytes(&encoding.path_data, patch_sizes.path_data) + + slice_size_in_bytes( + &encoding.draw_tags, + patch_sizes.draw_tags + encoding.n_open_clips as usize, + ) + + 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); + Self { + buffer_size, + path_tag_padded, + } + } +} + fn slice_size_in_bytes(slice: &[T], extra: usize) -> usize { (slice.len() + extra) * std::mem::size_of::() }