diff --git a/vello_encoding/src/encoding.rs b/vello_encoding/src/encoding.rs index e08dc6878..e5cd4f375 100644 --- a/vello_encoding/src/encoding.rs +++ b/vello_encoding/src/encoding.rs @@ -22,11 +22,13 @@ pub struct Encoding { /// The path tag stream. pub path_tags: Vec, /// The path data stream. - pub path_data: Vec, + /// Stores all coordinates on paths. + /// Stored as `u32` as all comparisons are performed bitwise. + pub path_data: Vec, /// The draw tag stream. pub draw_tags: Vec, /// The draw data stream. - pub draw_data: Vec, + pub draw_data: Vec, /// The transform stream. pub transforms: Vec, /// The style stream @@ -331,7 +333,8 @@ impl Encoding { pub fn encode_color(&mut self, color: impl Into) { let color = color.into(); self.draw_tags.push(DrawTag::COLOR); - self.draw_data.extend_from_slice(bytemuck::bytes_of(&color)); + let DrawColor { rgba } = color; + self.draw_data.push(rgba); } /// Encodes a linear gradient brush. @@ -350,7 +353,7 @@ impl Encoding { RampStops::Many => { self.draw_tags.push(DrawTag::LINEAR_GRADIENT); self.draw_data - .extend_from_slice(bytemuck::bytes_of(&gradient)); + .extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of(&gradient))); } } } @@ -375,7 +378,7 @@ impl Encoding { RampStops::Many => { self.draw_tags.push(DrawTag::RADIAL_GRADIENT); self.draw_data - .extend_from_slice(bytemuck::bytes_of(&gradient)); + .extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of(&gradient))); } } } @@ -399,7 +402,7 @@ impl Encoding { RampStops::Many => { self.draw_tags.push(DrawTag::SWEEP_GRADIENT); self.draw_data - .extend_from_slice(bytemuck::bytes_of(&gradient)); + .extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of(&gradient))); } } } @@ -416,14 +419,14 @@ impl Encoding { }); self.draw_tags.push(DrawTag::IMAGE); self.draw_data - .extend_from_slice(bytemuck::bytes_of(&DrawImage { + .extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of(&DrawImage { xy: 0, width_height: (image.width << 16) | (image.height & 0xFFFF), sample_alpha: ((image.quality as u32) << 12) | ((image.x_extend as u32) << 10) | ((image.y_extend as u32) << 8) | alpha as u32, - })); + }))); } // Encodes a blurred rounded rectangle brush. @@ -437,13 +440,15 @@ impl Encoding { ) { self.draw_tags.push(DrawTag::BLUR_RECT); self.draw_data - .extend_from_slice(bytemuck::bytes_of(&DrawBlurRoundedRect { - color: color.into(), - width, - height, - radius, - std_dev, - })); + .extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of( + &DrawBlurRoundedRect { + color: color.into(), + width, + height, + radius, + std_dev, + }, + ))); } /// Encodes a begin clip command. @@ -451,7 +456,9 @@ impl Encoding { use super::DrawBeginClip; self.draw_tags.push(DrawTag::BEGIN_CLIP); self.draw_data - .extend_from_slice(bytemuck::bytes_of(&DrawBeginClip::new(blend_mode, alpha))); + .extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of( + &DrawBeginClip::new(blend_mode, alpha), + ))); self.n_clips += 1; self.n_open_clips += 1; } diff --git a/vello_encoding/src/path.rs b/vello_encoding/src/path.rs index a1703ce0d..c975fe8b6 100644 --- a/vello_encoding/src/path.rs +++ b/vello_encoding/src/path.rs @@ -418,7 +418,7 @@ pub struct Tile { /// Encoder for path segments. pub struct PathEncoder<'a> { tags: &'a mut Vec, - data: &'a mut Vec, + data: &'a mut Vec, n_segments: &'a mut u32, n_paths: &'a mut u32, first_point: [f32; 2], @@ -474,7 +474,7 @@ impl<'a> PathEncoder<'a> { /// line-to), the thread draws nothing. pub fn new( tags: &'a mut Vec, - data: &'a mut Vec, + data: &'a mut Vec, n_segments: &'a mut u32, n_paths: &'a mut u32, is_fill: bool, @@ -497,10 +497,8 @@ impl<'a> PathEncoder<'a> { if self.is_fill { self.close(); } - let buf = [x, y]; - let bytes = bytemuck::bytes_of(&buf); if self.state == PathState::MoveTo { - let new_len = self.data.len() - 8; + let new_len = self.data.len() - 2; self.data.truncate(new_len); } else if self.state == PathState::NonemptySubpath { if !self.is_fill { @@ -510,7 +508,9 @@ impl<'a> PathEncoder<'a> { tag.set_subpath_end(); } } - self.first_point = buf; + self.first_point = [x, y]; + let buf = self.first_point.map(f32::to_le_bytes); + let bytes = bytemuck::cast_slice(&buf); self.data.extend_from_slice(bytes); self.state = PathState::MoveTo; } @@ -537,8 +537,8 @@ impl<'a> PathEncoder<'a> { if self.is_zero_length_segment((x, y), None, None) { return; } - let buf = [x, y]; - let bytes = bytemuck::bytes_of(&buf); + let buf = [x, y].map(f32::to_le_bytes); + let bytes = bytemuck::cast_slice(&buf); self.data.extend_from_slice(bytes); self.tags.push(PathTag::LINE_TO_F32); self.state = PathState::NonemptySubpath; @@ -565,8 +565,8 @@ impl<'a> PathEncoder<'a> { if self.is_zero_length_segment((x1, y1), Some((x2, y2)), None) { return; } - let buf = [x1, y1, x2, y2]; - let bytes = bytemuck::bytes_of(&buf); + let buf = [x1, y1, x2, y2].map(f32::to_le_bytes); + let bytes = bytemuck::cast_slice(&buf); self.data.extend_from_slice(bytes); self.tags.push(PathTag::QUAD_TO_F32); self.state = PathState::NonemptySubpath; @@ -593,8 +593,8 @@ impl<'a> PathEncoder<'a> { if self.is_zero_length_segment((x1, y1), Some((x2, y2)), Some((x3, y3))) { return; } - let buf = [x1, y1, x2, y2, x3, y3]; - let bytes = bytemuck::bytes_of(&buf); + let buf = [x1, y1, x2, y2, x3, y3].map(f32::to_le_bytes); + let bytes = bytemuck::cast_slice(&buf); self.data.extend_from_slice(bytes); self.tags.push(PathTag::CUBIC_TO_F32); self.state = PathState::NonemptySubpath; @@ -603,8 +603,8 @@ impl<'a> PathEncoder<'a> { /// Encodes an empty path (as placeholder for begin clip). pub(crate) fn empty_path(&mut self) { - let coords = [0.0_f32, 0., 0., 0.]; - let bytes = bytemuck::bytes_of(&coords); + let buf = [0., 0., 0., 0.].map(f32::to_le_bytes); + let bytes = bytemuck::cast_slice(&buf); self.data.extend_from_slice(bytes); self.tags.push(PathTag::LINE_TO_F32); self.n_encoded_segments += 1; @@ -615,7 +615,8 @@ impl<'a> PathEncoder<'a> { match self.state { PathState::Start => return, PathState::MoveTo => { - let new_len = self.data.len() - 8; + // If we close a new-opened path, delete it. + let new_len = self.data.len() - 2; self.data.truncate(new_len); self.state = PathState::Start; return; @@ -623,12 +624,15 @@ impl<'a> PathEncoder<'a> { PathState::NonemptySubpath => (), } let len = self.data.len(); - if len < 8 { - // can't happen + if len < 2 { + if cfg!(debug_assertions) { + unreachable!("There is an open path, so there must be data.") + } return; } - let first_bytes = bytemuck::bytes_of(&self.first_point); - if &self.data[len - 8..len] != first_bytes { + let buf = self.first_point.map(f32::to_le_bytes); + let first_bytes = bytemuck::cast_slice(&buf); + if &self.data[len - 2..len] != first_bytes { self.data.extend_from_slice(first_bytes); self.tags.push(PathTag::LINE_TO_F32); self.n_encoded_segments += 1; @@ -722,12 +726,12 @@ impl<'a> PathEncoder<'a> { fn last_point(&self) -> Option<(f32, f32)> { let len = self.data.len(); - if len < 8 { + if len < 2 { return None; } Some(( - bytemuck::pod_read_unaligned::(&self.data[len - 8..len - 4]), - bytemuck::pod_read_unaligned::(&self.data[len - 4..len]), + f32::from_le_bytes(self.data[len - 2].to_ne_bytes()), + f32::from_le_bytes(self.data[len - 1].to_ne_bytes()), )) } diff --git a/vello_encoding/src/resolve.rs b/vello_encoding/src/resolve.rs index 782493559..a0ab26026 100644 --- a/vello_encoding/src/resolve.rs +++ b/vello_encoding/src/resolve.rs @@ -270,11 +270,13 @@ impl Resolver { extend, } => { if pos < *draw_data_offset { - data.extend_from_slice(&encoding.draw_data[pos..*draw_data_offset]); + data.extend_from_slice(bytemuck::cast_slice( + &encoding.draw_data[pos..*draw_data_offset], + )); } let index_mode = (ramp_id << 2) | *extend as u32; data.extend_from_slice(bytemuck::bytes_of(&index_mode)); - pos = *draw_data_offset + 4; + pos = *draw_data_offset + 1; } ResolvedPatch::GlyphRun { .. } => {} ResolvedPatch::Image { @@ -282,19 +284,21 @@ impl Resolver { draw_data_offset, } => { if pos < *draw_data_offset { - data.extend_from_slice(&encoding.draw_data[pos..*draw_data_offset]); + data.extend_from_slice(bytemuck::cast_slice( + &encoding.draw_data[pos..*draw_data_offset], + )); } if let Some((x, y)) = self.pending_images[*index].xy { let xy = (x << 16) | y; data.extend_from_slice(bytemuck::bytes_of(&xy)); - pos = *draw_data_offset + 4; + pos = *draw_data_offset + 1; } else { // If we get here, we failed to allocate a slot for this image in the atlas. // In this case, let's zero out the dimensions so we don't attempt to render // anything. // TODO: a better strategy: texture array? downsample large images? data.extend_from_slice(&[0_u8; 8]); - pos = *draw_data_offset + 8; + pos = *draw_data_offset + 2; } } }