diff --git a/piet-gpu-types/src/annotated.rs b/piet-gpu-types/src/annotated.rs new file mode 100644 index 0000000..247ab12 --- /dev/null +++ b/piet-gpu-types/src/annotated.rs @@ -0,0 +1,46 @@ +use piet_gpu_derive::piet_gpu; + +piet_gpu! { + #[gpu_write] + mod annotated { + struct AnnoLineSeg { + p0: [f32; 2], + p1: [f32; 2], + // halfwidth in both x and y for binning + stroke: [f32; 2], + } + struct AnnoQuadSeg { + p0: [f32; 2], + p1: [f32; 2], + p2: [f32; 2], + stroke: [f32; 2], + } + struct AnnoCubicSeg { + p0: [f32; 2], + p1: [f32; 2], + p2: [f32; 2], + p3: [f32; 2], + stroke: [f32; 2], + } + struct AnnoFill { + rgba_color: u32, + bbox: [f32; 4], + } + struct AnnoStroke { + rgba_color: u32, + bbox: [f32; 4], + // For the nonuniform scale case, this needs to be a 2x2 matrix. + // That's expected to be uncommon, so we could special-case it. + linewidth: f32, + } + enum Annotated { + Nop, + // The segments need a flag to indicate fill/stroke + Line(AnnoLineSeg), + Quad(AnnoQuadSeg), + Cubic(AnnoCubicSeg), + Stroke(AnnoStroke), + Fill(AnnoFill), + } + } +} diff --git a/piet-gpu-types/src/lib.rs b/piet-gpu-types/src/lib.rs index 288f71c..1759c4d 100644 --- a/piet-gpu-types/src/lib.rs +++ b/piet-gpu-types/src/lib.rs @@ -1,3 +1,4 @@ +pub mod annotated; pub mod encoder; pub mod fill_seg; pub mod ptcl; diff --git a/piet-gpu-types/src/main.rs b/piet-gpu-types/src/main.rs index 033bec4..68e6487 100644 --- a/piet-gpu-types/src/main.rs +++ b/piet-gpu-types/src/main.rs @@ -6,6 +6,7 @@ fn main() { match mod_name.as_str() { "scene" => print!("{}", piet_gpu_types::scene::gen_gpu_scene()), "state" => print!("{}", piet_gpu_types::state::gen_gpu_state()), + "annotated" => print!("{}", piet_gpu_types::annotated::gen_gpu_annotated()), "tilegroup" => print!("{}", piet_gpu_types::tilegroup::gen_gpu_tilegroup()), "segment" => print!("{}", piet_gpu_types::segment::gen_gpu_segment()), "fill_seg" => print!("{}", piet_gpu_types::fill_seg::gen_gpu_fill_seg()), diff --git a/piet-gpu/shader/annotated.h b/piet-gpu/shader/annotated.h new file mode 100644 index 0000000..a3fc464 --- /dev/null +++ b/piet-gpu/shader/annotated.h @@ -0,0 +1,290 @@ +// Code auto-generated by piet-gpu-derive + +struct AnnoLineSegRef { + uint offset; +}; + +struct AnnoQuadSegRef { + uint offset; +}; + +struct AnnoCubicSegRef { + uint offset; +}; + +struct AnnoFillRef { + uint offset; +}; + +struct AnnoStrokeRef { + uint offset; +}; + +struct AnnotatedRef { + uint offset; +}; + +struct AnnoLineSeg { + vec2 p0; + vec2 p1; + vec2 stroke; +}; + +#define AnnoLineSeg_size 24 + +AnnoLineSegRef AnnoLineSeg_index(AnnoLineSegRef ref, uint index) { + return AnnoLineSegRef(ref.offset + index * AnnoLineSeg_size); +} + +struct AnnoQuadSeg { + vec2 p0; + vec2 p1; + vec2 p2; + vec2 stroke; +}; + +#define AnnoQuadSeg_size 32 + +AnnoQuadSegRef AnnoQuadSeg_index(AnnoQuadSegRef ref, uint index) { + return AnnoQuadSegRef(ref.offset + index * AnnoQuadSeg_size); +} + +struct AnnoCubicSeg { + vec2 p0; + vec2 p1; + vec2 p2; + vec2 p3; + vec2 stroke; +}; + +#define AnnoCubicSeg_size 40 + +AnnoCubicSegRef AnnoCubicSeg_index(AnnoCubicSegRef ref, uint index) { + return AnnoCubicSegRef(ref.offset + index * AnnoCubicSeg_size); +} + +struct AnnoFill { + uint rgba_color; + vec4 bbox; +}; + +#define AnnoFill_size 20 + +AnnoFillRef AnnoFill_index(AnnoFillRef ref, uint index) { + return AnnoFillRef(ref.offset + index * AnnoFill_size); +} + +struct AnnoStroke { + uint rgba_color; + vec4 bbox; + float linewidth; +}; + +#define AnnoStroke_size 24 + +AnnoStrokeRef AnnoStroke_index(AnnoStrokeRef ref, uint index) { + return AnnoStrokeRef(ref.offset + index * AnnoStroke_size); +} + +#define Annotated_Nop 0 +#define Annotated_Line 1 +#define Annotated_Quad 2 +#define Annotated_Cubic 3 +#define Annotated_Stroke 4 +#define Annotated_Fill 5 +#define Annotated_size 44 + +AnnotatedRef Annotated_index(AnnotatedRef ref, uint index) { + return AnnotatedRef(ref.offset + index * Annotated_size); +} + +AnnoLineSeg AnnoLineSeg_read(AnnoLineSegRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = annotated[ix + 0]; + uint raw1 = annotated[ix + 1]; + uint raw2 = annotated[ix + 2]; + uint raw3 = annotated[ix + 3]; + uint raw4 = annotated[ix + 4]; + uint raw5 = annotated[ix + 5]; + AnnoLineSeg s; + s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); + s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); + s.stroke = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); + return s; +} + +void AnnoLineSeg_write(AnnoLineSegRef ref, AnnoLineSeg s) { + uint ix = ref.offset >> 2; + annotated[ix + 0] = floatBitsToUint(s.p0.x); + annotated[ix + 1] = floatBitsToUint(s.p0.y); + annotated[ix + 2] = floatBitsToUint(s.p1.x); + annotated[ix + 3] = floatBitsToUint(s.p1.y); + annotated[ix + 4] = floatBitsToUint(s.stroke.x); + annotated[ix + 5] = floatBitsToUint(s.stroke.y); +} + +AnnoQuadSeg AnnoQuadSeg_read(AnnoQuadSegRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = annotated[ix + 0]; + uint raw1 = annotated[ix + 1]; + uint raw2 = annotated[ix + 2]; + uint raw3 = annotated[ix + 3]; + uint raw4 = annotated[ix + 4]; + uint raw5 = annotated[ix + 5]; + uint raw6 = annotated[ix + 6]; + uint raw7 = annotated[ix + 7]; + AnnoQuadSeg s; + s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); + s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); + s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); + s.stroke = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7)); + return s; +} + +void AnnoQuadSeg_write(AnnoQuadSegRef ref, AnnoQuadSeg s) { + uint ix = ref.offset >> 2; + annotated[ix + 0] = floatBitsToUint(s.p0.x); + annotated[ix + 1] = floatBitsToUint(s.p0.y); + annotated[ix + 2] = floatBitsToUint(s.p1.x); + annotated[ix + 3] = floatBitsToUint(s.p1.y); + annotated[ix + 4] = floatBitsToUint(s.p2.x); + annotated[ix + 5] = floatBitsToUint(s.p2.y); + annotated[ix + 6] = floatBitsToUint(s.stroke.x); + annotated[ix + 7] = floatBitsToUint(s.stroke.y); +} + +AnnoCubicSeg AnnoCubicSeg_read(AnnoCubicSegRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = annotated[ix + 0]; + uint raw1 = annotated[ix + 1]; + uint raw2 = annotated[ix + 2]; + uint raw3 = annotated[ix + 3]; + uint raw4 = annotated[ix + 4]; + uint raw5 = annotated[ix + 5]; + uint raw6 = annotated[ix + 6]; + uint raw7 = annotated[ix + 7]; + uint raw8 = annotated[ix + 8]; + uint raw9 = annotated[ix + 9]; + AnnoCubicSeg s; + s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); + s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); + s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); + s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7)); + s.stroke = vec2(uintBitsToFloat(raw8), uintBitsToFloat(raw9)); + return s; +} + +void AnnoCubicSeg_write(AnnoCubicSegRef ref, AnnoCubicSeg s) { + uint ix = ref.offset >> 2; + annotated[ix + 0] = floatBitsToUint(s.p0.x); + annotated[ix + 1] = floatBitsToUint(s.p0.y); + annotated[ix + 2] = floatBitsToUint(s.p1.x); + annotated[ix + 3] = floatBitsToUint(s.p1.y); + annotated[ix + 4] = floatBitsToUint(s.p2.x); + annotated[ix + 5] = floatBitsToUint(s.p2.y); + annotated[ix + 6] = floatBitsToUint(s.p3.x); + annotated[ix + 7] = floatBitsToUint(s.p3.y); + annotated[ix + 8] = floatBitsToUint(s.stroke.x); + annotated[ix + 9] = floatBitsToUint(s.stroke.y); +} + +AnnoFill AnnoFill_read(AnnoFillRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = annotated[ix + 0]; + uint raw1 = annotated[ix + 1]; + uint raw2 = annotated[ix + 2]; + uint raw3 = annotated[ix + 3]; + uint raw4 = annotated[ix + 4]; + AnnoFill s; + s.rgba_color = raw0; + s.bbox = vec4(uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3), uintBitsToFloat(raw4)); + return s; +} + +void AnnoFill_write(AnnoFillRef ref, AnnoFill s) { + uint ix = ref.offset >> 2; + annotated[ix + 0] = s.rgba_color; + annotated[ix + 1] = floatBitsToUint(s.bbox.x); + annotated[ix + 2] = floatBitsToUint(s.bbox.y); + annotated[ix + 3] = floatBitsToUint(s.bbox.z); + annotated[ix + 4] = floatBitsToUint(s.bbox.w); +} + +AnnoStroke AnnoStroke_read(AnnoStrokeRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = annotated[ix + 0]; + uint raw1 = annotated[ix + 1]; + uint raw2 = annotated[ix + 2]; + uint raw3 = annotated[ix + 3]; + uint raw4 = annotated[ix + 4]; + uint raw5 = annotated[ix + 5]; + AnnoStroke s; + s.rgba_color = raw0; + s.bbox = vec4(uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3), uintBitsToFloat(raw4)); + s.linewidth = uintBitsToFloat(raw5); + return s; +} + +void AnnoStroke_write(AnnoStrokeRef ref, AnnoStroke s) { + uint ix = ref.offset >> 2; + annotated[ix + 0] = s.rgba_color; + annotated[ix + 1] = floatBitsToUint(s.bbox.x); + annotated[ix + 2] = floatBitsToUint(s.bbox.y); + annotated[ix + 3] = floatBitsToUint(s.bbox.z); + annotated[ix + 4] = floatBitsToUint(s.bbox.w); + annotated[ix + 5] = floatBitsToUint(s.linewidth); +} + +uint Annotated_tag(AnnotatedRef ref) { + return annotated[ref.offset >> 2]; +} + +AnnoLineSeg Annotated_Line_read(AnnotatedRef ref) { + return AnnoLineSeg_read(AnnoLineSegRef(ref.offset + 4)); +} + +AnnoQuadSeg Annotated_Quad_read(AnnotatedRef ref) { + return AnnoQuadSeg_read(AnnoQuadSegRef(ref.offset + 4)); +} + +AnnoCubicSeg Annotated_Cubic_read(AnnotatedRef ref) { + return AnnoCubicSeg_read(AnnoCubicSegRef(ref.offset + 4)); +} + +AnnoStroke Annotated_Stroke_read(AnnotatedRef ref) { + return AnnoStroke_read(AnnoStrokeRef(ref.offset + 4)); +} + +AnnoFill Annotated_Fill_read(AnnotatedRef ref) { + return AnnoFill_read(AnnoFillRef(ref.offset + 4)); +} + +void Annotated_Nop_write(AnnotatedRef ref) { + annotated[ref.offset >> 2] = Annotated_Nop; +} + +void Annotated_Line_write(AnnotatedRef ref, AnnoLineSeg s) { + annotated[ref.offset >> 2] = Annotated_Line; + AnnoLineSeg_write(AnnoLineSegRef(ref.offset + 4), s); +} + +void Annotated_Quad_write(AnnotatedRef ref, AnnoQuadSeg s) { + annotated[ref.offset >> 2] = Annotated_Quad; + AnnoQuadSeg_write(AnnoQuadSegRef(ref.offset + 4), s); +} + +void Annotated_Cubic_write(AnnotatedRef ref, AnnoCubicSeg s) { + annotated[ref.offset >> 2] = Annotated_Cubic; + AnnoCubicSeg_write(AnnoCubicSegRef(ref.offset + 4), s); +} + +void Annotated_Stroke_write(AnnotatedRef ref, AnnoStroke s) { + annotated[ref.offset >> 2] = Annotated_Stroke; + AnnoStroke_write(AnnoStrokeRef(ref.offset + 4), s); +} + +void Annotated_Fill_write(AnnotatedRef ref, AnnoFill s) { + annotated[ref.offset >> 2] = Annotated_Fill; + AnnoFill_write(AnnoFillRef(ref.offset + 4), s); +} + diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 5cede7c..1061fab 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -12,13 +12,21 @@ layout(set = 0, binding = 0) readonly buffer SceneBuf { uint[] scene; }; -// This will be used for inter-wprkgroup aggregates +// This will be used for inter-workgroup aggregates. In the +// meantime, for development, it has been used to store the +// scan of the state objects. layout(set = 0, binding = 1) buffer StateBuf { uint[] state; }; +// The annotated results are stored here. +layout(set = 0, binding = 2) buffer AnnotatedBuf { + uint[] annotated; +}; + #include "scene.h" #include "state.h" +#include "annotated.h" #define FLAG_SET_LINEWIDTH 1 #define FLAG_RESET_BBOX 2 @@ -93,6 +101,12 @@ State map_element(ElementRef ref) { return c; } +// Get the bounding box of a circle transformed by the matrix into an ellipse. +vec2 get_linewidth(State st) { + // See https://www.iquilezles.org/www/articles/ellipses/ellipses.htm + return 0.5 * st.linewidth * vec2(length(st.mat.xz), length(st.mat.yw)); +} + // We should be able to use an array of structs but the NV shader compiler // doesn't seem to like it :/ //shared State sh_state[WG_SIZE]; @@ -165,9 +179,38 @@ void main() { row = combine_state(row, other); } for (uint i = 0; i < N_ROWS; i++) { - State this_state = combine_state(row, th_state[i]); + State st = combine_state(row, th_state[i]); // We write the state now for development purposes, but the // actual goal is to write transformed and annotated elements. - State_write(StateRef((ix + i) * State_size), this_state); + //State_write(StateRef((ix + i) * State_size), st); + + // Here we read again from the original scene. There may be + // gains to be had from stashing in shared memory or possibly + // registers (though register pressure is an issue). + ElementRef this_ref = Element_index(ref, i); + AnnotatedRef out_ref = AnnotatedRef((ix + i) * Annotated_size); + uint tag = Element_tag(this_ref); + switch (tag) { + case Element_Line: + LineSeg line = Element_Line_read(this_ref); + AnnoLineSeg anno_line; + anno_line.p0 = st.mat.xz * line.p0.x + st.mat.yw * line.p0.y + st.translate; + anno_line.p1 = st.mat.xz * line.p1.x + st.mat.yw * line.p1.y + st.translate; + anno_line.stroke = get_linewidth(st); + Annotated_Line_write(out_ref, anno_line); + break; + case Element_Stroke: + Stroke stroke = Element_Stroke_read(this_ref); + AnnoStroke anno_stroke; + anno_stroke.rgba_color = stroke.rgba_color; + vec2 lw = get_linewidth(st); + anno_stroke.bbox = st.bbox + vec4(-lw, lw); + anno_stroke.linewidth = st.linewidth * sqrt(st.mat.x * st.mat.w - st.mat.y * st.mat.z); + Annotated_Stroke_write(out_ref, anno_stroke); + break; + default: + Annotated_Nop_write(out_ref); + break; + } } } diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index e97226c..41d9bc1 100644 Binary files a/piet-gpu/shader/elements.spv and b/piet-gpu/shader/elements.spv differ diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 82b20c8..0753054 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -113,6 +113,7 @@ pub struct Renderer { scene_dev: D::Buffer, pub state_buf: D::Buffer, + pub anno_buf: D::Buffer, el_pipeline: D::Pipeline, el_ds: D::DescriptorSet, @@ -156,14 +157,15 @@ impl Renderer { .unwrap(); device.write_buffer(&scene_buf, &scene)?; - let state_buf = device.create_buffer(4 * 1024 * 1024, dev)?; + let state_buf = device.create_buffer(64 * 1024 * 1024, dev)?; + let anno_buf = device.create_buffer(64 * 1024 * 1024, dev)?; let image_dev = device.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?; let el_code = include_bytes!("../shader/elements.spv"); - let el_pipeline = device.create_simple_compute_pipeline(el_code, 2, 0)?; + let el_pipeline = device.create_simple_compute_pipeline(el_code, 3, 0)?; let el_ds = device.create_descriptor_set( &el_pipeline, - &[&scene_dev, &state_buf], + &[&scene_dev, &state_buf, &anno_buf], &[], )?; @@ -252,6 +254,7 @@ impl Renderer { el_pipeline, el_ds, state_buf, + anno_buf, n_elements, }) } diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index ad84a60..e01a6ae 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -199,7 +199,7 @@ impl RenderContext for PietGpuRenderContext { impl PietGpuRenderContext { fn encode_path(&mut self, path: impl Iterator) { - let flatten = false; + let flatten = true; if flatten { let mut start_pt = None; let mut last_pt = None;