Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encode path_data and draw_data directly as u32 #817

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions vello_encoding/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ 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 +333,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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, I think.

self.draw_data.push(rgba);
}

/// Encodes a linear gradient brush.
Expand All @@ -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)));
}
}
}
Expand All @@ -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)));
}
}
}
Expand All @@ -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)));
}
}
}
Expand All @@ -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.
Expand All @@ -437,21 +440,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
14 changes: 9 additions & 5 deletions vello_encoding/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,31 +270,35 @@ 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 {
index,
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]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is slightly confusing then being u8 still and just required some extra thought.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes... I don't think there's really a cleaner way to express this, because data is still byte-wise. Happy to change it if needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is somewhat confusing, but am also not sure there's a great way around it.

pos = *draw_data_offset + 8;
pos = *draw_data_offset + 2;
}
}
}
Expand Down