Skip to content

Commit

Permalink
Encode path_data and draw_data directly as u32
Browse files Browse the repository at this point in the history
We already assume these are word-aligned, and so this would
catch a failure of that assumption much earller.

A future change would be to encode the full scene encoding as u32.
That would be useful for linebender#810, as the current code has an alignment hazard
  • Loading branch information
DJMcNab committed Feb 14, 2025
1 parent 782fb5a commit dd5dc9d
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 34 deletions.
40 changes: 24 additions & 16 deletions vello_encoding/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ pub struct Encoding {
/// The path tag stream.
pub path_tags: Vec<PathTag>,
/// The path data stream.
pub path_data: Vec<u8>,
///
/// Stores all coordinates on paths.
/// Stored as u32 as all comparisons are performed bitwise.
pub path_data: Vec<u32>,
/// The draw tag stream.
pub draw_tags: Vec<DrawTag>,
/// The draw data stream.
pub draw_data: Vec<u8>,
pub draw_data: Vec<u32>,
/// The transform stream.
pub transforms: Vec<Transform>,
/// The style stream
Expand Down Expand Up @@ -331,7 +334,8 @@ impl Encoding {
pub fn encode_color(&mut self, color: impl Into<DrawColor>) {
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.
Expand All @@ -350,7 +354,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)));
}
}
}
Expand All @@ -375,7 +379,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)));
}
}
}
Expand All @@ -399,7 +403,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)));
}
}
}
Expand All @@ -416,14 +420,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.
Expand All @@ -437,21 +441,25 @@ 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.
pub fn encode_begin_clip(&mut self, blend_mode: BlendMode, alpha: f32) {
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;
}
Expand Down
35 changes: 19 additions & 16 deletions vello_encoding/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ pub struct Tile {
/// Encoder for path segments.
pub struct PathEncoder<'a> {
tags: &'a mut Vec<PathTag>,
data: &'a mut Vec<u8>,
data: &'a mut Vec<u32>,
n_segments: &'a mut u32,
n_paths: &'a mut u32,
first_point: [f32; 2],
Expand Down Expand Up @@ -474,7 +474,7 @@ impl<'a> PathEncoder<'a> {
/// line-to), the thread draws nothing.
pub fn new(
tags: &'a mut Vec<PathTag>,
data: &'a mut Vec<u8>,
data: &'a mut Vec<u32>,
n_segments: &'a mut u32,
n_paths: &'a mut u32,
is_fill: bool,
Expand All @@ -498,9 +498,9 @@ impl<'a> PathEncoder<'a> {
self.close();
}
let buf = [x, y];
let bytes = bytemuck::bytes_of(&buf);
let bytes = bytemuck::cast_slice(&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 {
Expand Down Expand Up @@ -538,7 +538,7 @@ impl<'a> PathEncoder<'a> {
return;
}
let buf = [x, y];
let bytes = bytemuck::bytes_of(&buf);
let bytes = bytemuck::cast_slice(&buf);
self.data.extend_from_slice(bytes);
self.tags.push(PathTag::LINE_TO_F32);
self.state = PathState::NonemptySubpath;
Expand Down Expand Up @@ -566,7 +566,7 @@ impl<'a> PathEncoder<'a> {
return;
}
let buf = [x1, y1, x2, y2];
let bytes = bytemuck::bytes_of(&buf);
let bytes = bytemuck::cast_slice(&buf);
self.data.extend_from_slice(bytes);
self.tags.push(PathTag::QUAD_TO_F32);
self.state = PathState::NonemptySubpath;
Expand Down Expand Up @@ -594,7 +594,7 @@ impl<'a> PathEncoder<'a> {
return;
}
let buf = [x1, y1, x2, y2, x3, y3];
let bytes = bytemuck::bytes_of(&buf);
let bytes = bytemuck::cast_slice(&buf);
self.data.extend_from_slice(bytes);
self.tags.push(PathTag::CUBIC_TO_F32);
self.state = PathState::NonemptySubpath;
Expand All @@ -604,7 +604,7 @@ 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 bytes = bytemuck::cast_slice(&coords);
self.data.extend_from_slice(bytes);
self.tags.push(PathTag::LINE_TO_F32);
self.n_encoded_segments += 1;
Expand All @@ -615,20 +615,23 @@ 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;
}
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 first_bytes = bytemuck::cast_slice(&self.first_point);
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;
Expand Down Expand Up @@ -722,12 +725,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::<f32>(&self.data[len - 8..len - 4]),
bytemuck::pod_read_unaligned::<f32>(&self.data[len - 4..len]),
bytemuck::cast(self.data[len - 2]),
bytemuck::cast(self.data[len - 1]),
))
}

Expand Down
8 changes: 6 additions & 2 deletions vello_encoding/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,9 @@ 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));
Expand All @@ -282,7 +284,9 @@ 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;
Expand Down

0 comments on commit dd5dc9d

Please sign in to comment.