blob: 0aa779e5c7b96f9ffcc309c4631855855515ef6b [file] [log] [blame] [edit]
// Copyright 2023 The Vello authors
// SPDX-License-Identifier: Apache-2.0 OR MIT OR Unlicense
use vello_encoding::{Clip, ConfigUniform, DrawMonoid, DrawTag, Monoid, PathBbox};
use crate::cpu_dispatch::CpuBinding;
use super::util::{read_draw_tag_from_scene, Transform, Vec2};
const WG_SIZE: usize = 256;
fn draw_leaf_main(
n_wg: u32,
config: &ConfigUniform,
scene: &[u32],
reduced: &[DrawMonoid],
path_bbox: &[PathBbox],
draw_monoid: &mut [DrawMonoid],
info: &mut [u32],
clip_inp: &mut [Clip],
) {
let mut prefix = DrawMonoid::default();
for i in 0..n_wg {
let mut m = prefix;
for j in 0..WG_SIZE {
let ix = i * WG_SIZE as u32 + j as u32;
let tag_raw = read_draw_tag_from_scene(config, scene, ix);
let tag_word = DrawTag(tag_raw);
// store exclusive prefix sum
if ix < config.layout.n_draw_objects {
draw_monoid[ix as usize] = m;
}
let m_next = m.combine(&DrawMonoid::new(tag_word));
let dd = config.layout.draw_data_base + m.scene_offset;
let di = m.info_offset as usize;
if tag_word == DrawTag::COLOR
|| tag_word == DrawTag::LINEAR_GRADIENT
|| tag_word == DrawTag::RADIAL_GRADIENT
|| tag_word == DrawTag::IMAGE
|| tag_word == DrawTag::BEGIN_CLIP
{
let bbox = path_bbox[m.path_ix as usize];
let transform = Transform::read(config.layout.transform_base, bbox.trans_ix, scene);
let linewidth = bbox.linewidth;
match tag_word {
DrawTag::COLOR => {
info[di] = f32::to_bits(linewidth);
}
DrawTag::LINEAR_GRADIENT => {
info[di] = f32::to_bits(linewidth);
let p0 = Vec2::new(
f32::from_bits(scene[dd as usize + 1]),
f32::from_bits(scene[dd as usize + 2]),
);
let p1 = Vec2::new(
f32::from_bits(scene[dd as usize + 3]),
f32::from_bits(scene[dd as usize + 4]),
);
let p0 = transform.apply(p0);
let p1 = transform.apply(p1);
let dxy = p1 - p0;
let scale = 1.0 / dxy.dot(dxy);
let line_xy = dxy * scale;
let line_c = -p0.dot(line_xy);
info[di + 1] = f32::to_bits(line_xy.x);
info[di + 2] = f32::to_bits(line_xy.y);
info[di + 3] = f32::to_bits(line_c);
}
DrawTag::RADIAL_GRADIENT => {
info[di] = f32::to_bits(linewidth);
let p0 = Vec2::new(
f32::from_bits(scene[dd as usize + 1]),
f32::from_bits(scene[dd as usize + 2]),
);
let p1 = Vec2::new(
f32::from_bits(scene[dd as usize + 3]),
f32::from_bits(scene[dd as usize + 4]),
);
let r0 = f32::from_bits(scene[dd as usize + 5]);
let r1 = f32::from_bits(scene[dd as usize + 6]);
let z = transform.0;
let inv_det = (z[0] * z[3] - z[1] * z[2]).recip();
let inv_mat = [
z[3] * inv_det,
-z[1] * inv_det,
-z[2] * inv_det,
z[0] * inv_det,
];
let inv_tr = [
-(inv_mat[0] * z[4] + inv_mat[2] * z[5]) - p0.x,
-(inv_mat[1] * z[4] + inv_mat[3] * z[5]) - p0.y,
];
let center1 = p1 - p0;
let rr = r1 / (r1 - r0);
let ra_inv = rr / (r1 * r1 - center1.dot(center1));
let c1 = center1 * ra_inv;
let ra = rr * ra_inv;
let roff = rr - 1.0;
info[di + 1] = f32::to_bits(inv_mat[0]);
info[di + 2] = f32::to_bits(inv_mat[1]);
info[di + 3] = f32::to_bits(inv_mat[2]);
info[di + 4] = f32::to_bits(inv_mat[3]);
info[di + 5] = f32::to_bits(inv_tr[0]);
info[di + 6] = f32::to_bits(inv_tr[1]);
info[di + 7] = f32::to_bits(c1.x);
info[di + 8] = f32::to_bits(c1.y);
info[di + 9] = f32::to_bits(ra);
info[di + 19] = f32::to_bits(roff);
}
DrawTag::IMAGE => {
info[di] = f32::to_bits(linewidth);
let z = transform.0;
let inv_det = (z[0] * z[3] - z[1] * z[2]).recip();
let inv_mat = [
z[3] * inv_det,
-z[1] * inv_det,
-z[2] * inv_det,
z[0] * inv_det,
];
let inv_tr = [
-(inv_mat[0] * z[4] + inv_mat[2] * z[5]),
-(inv_mat[1] * z[4] + inv_mat[3] * z[5]),
];
info[di + 1] = f32::to_bits(inv_mat[0]);
info[di + 2] = f32::to_bits(inv_mat[1]);
info[di + 3] = f32::to_bits(inv_mat[2]);
info[di + 4] = f32::to_bits(inv_mat[3]);
info[di + 5] = f32::to_bits(inv_tr[0]);
info[di + 6] = f32::to_bits(inv_tr[1]);
info[di + 7] = scene[dd as usize];
info[di + 8] = scene[dd as usize + 1];
}
DrawTag::BEGIN_CLIP => (),
_ => todo!("unhandled draw tag {:x}", tag_word.0),
}
}
if tag_word == DrawTag::BEGIN_CLIP {
let path_ix = m.path_ix as i32;
clip_inp[m.clip_ix as usize] = Clip { ix, path_ix };
} else if tag_word == DrawTag::END_CLIP {
let path_ix = !ix as i32;
clip_inp[m.clip_ix as usize] = Clip { ix, path_ix };
}
m = m_next;
}
prefix = prefix.combine(&reduced[i as usize]);
}
}
pub fn draw_leaf(n_wg: u32, resources: &[CpuBinding]) {
let config = resources[0].as_typed();
let scene = resources[1].as_slice();
let reduced = resources[2].as_slice();
let path_bbox = resources[3].as_slice();
let mut draw_monoid = resources[4].as_slice_mut();
let mut info = resources[5].as_slice_mut();
let mut clip_inp = resources[6].as_slice_mut();
draw_leaf_main(
n_wg,
&config,
&scene,
&reduced,
&path_bbox,
&mut draw_monoid,
&mut info,
&mut clip_inp,
);
}