From e1c0e448ef6692ed6b4476ea58cbbd3f36155d63 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 24 Apr 2020 13:06:47 -0700 Subject: [PATCH] Encode stroke in scene This just adds the first step of polyline stroking, which is adding it to the scene. Also just a bit of cleaning up of dimensions into one header file. --- Cargo.lock | 4 +- Cargo.toml | 4 ++ piet-gpu/Cargo.toml | 1 + piet-gpu/shader/build.ninja | 6 +-- piet-gpu/shader/kernel1.comp | 8 +--- piet-gpu/shader/kernel3.comp | 14 +----- piet-gpu/shader/kernel4.comp | 8 +--- piet-gpu/shader/kernel4.spv | Bin 5704 -> 5704 bytes piet-gpu/shader/setup.h | 25 +++++++++++ piet-gpu/src/main.rs | 9 ++-- piet-gpu/src/render_ctx.rs | 81 ++++++++++++++++++++++++++++++----- 11 files changed, 113 insertions(+), 47 deletions(-) create mode 100644 piet-gpu/shader/setup.h diff --git a/Cargo.lock b/Cargo.lock index 3683e79..f19cf3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,8 +93,7 @@ dependencies = [ [[package]] name = "kurbo" version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf50e17a1697110c694d47c5b1a6b64faf5eb3ffe5a286df23fb8cd516e33be6" +source = "git+https://github.com/linebender/kurbo?rev=7bd7e66bd137e757305d170a0f9f2b4f7beeb299#7bd7e66bd137e757305d170a0f9f2b4f7beeb299" dependencies = [ "arrayvec", ] @@ -128,6 +127,7 @@ dependencies = [ name = "piet-gpu" version = "0.1.0" dependencies = [ + "kurbo", "piet", "piet-gpu-hal", "piet-gpu-types", diff --git a/Cargo.toml b/Cargo.toml index f71f2de..efa5f88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,7 @@ members = [ "piet-gpu-hal", "piet-gpu-types" ] + +# TODO: remove when the flatten feature is published +[patch.crates-io] +kurbo = { git = "https://github.com/linebender/kurbo", rev = "7bd7e66bd137e757305d170a0f9f2b4f7beeb299" } diff --git a/piet-gpu/Cargo.toml b/piet-gpu/Cargo.toml index bf68ea3..b082868 100644 --- a/piet-gpu/Cargo.toml +++ b/piet-gpu/Cargo.toml @@ -13,6 +13,7 @@ path = "../piet-gpu-hal" path = "../piet-gpu-types" [dependencies] +kurbo = "0.5.11" piet = "0.0.12" png = "0.16.2" rand = "0.7.3" diff --git a/piet-gpu/shader/build.ninja b/piet-gpu/shader/build.ninja index cd79d16..7509062 100644 --- a/piet-gpu/shader/build.ninja +++ b/piet-gpu/shader/build.ninja @@ -9,8 +9,8 @@ rule glsl build image.spv: glsl image.comp | scene.h -build kernel1.spv: glsl kernel1.comp | scene.h tilegroup.h +build kernel1.spv: glsl kernel1.comp | scene.h tilegroup.h setup.h -build kernel3.spv: glsl kernel3.comp | scene.h tilegroup.h ptcl.h +build kernel3.spv: glsl kernel3.comp | scene.h tilegroup.h ptcl.h setup.h -build kernel4.spv: glsl kernel4.comp | ptcl.h +build kernel4.spv: glsl kernel4.comp | ptcl.h setup.h diff --git a/piet-gpu/shader/kernel1.comp b/piet-gpu/shader/kernel1.comp index 3a4156c..dbdd492 100644 --- a/piet-gpu/shader/kernel1.comp +++ b/piet-gpu/shader/kernel1.comp @@ -28,13 +28,7 @@ layout(set = 0, binding = 1) buffer TilegroupBuf { #include "scene.h" #include "tilegroup.h" -// TODO: compute this -#define WIDTH_IN_TILEGROUPS 4 - -#define TILEGROUP_WIDTH_PX 512 -#define TILEGROUP_HEIGHT_PX 16 - -#define TILEGROUP_INITIAL_ALLOC 1024 +#include "setup.h" #define MAX_STACK 8 diff --git a/piet-gpu/shader/kernel3.comp b/piet-gpu/shader/kernel3.comp index 4ccfa1a..cb344c0 100644 --- a/piet-gpu/shader/kernel3.comp +++ b/piet-gpu/shader/kernel3.comp @@ -24,19 +24,7 @@ layout(set = 0, binding = 2) buffer PtclBuf { #include "tilegroup.h" #include "ptcl.h" -// TODO: compute all these - -#define WIDTH_IN_TILEGROUPS 4 -#define WIDTH_IN_TILES 128 -#define TILEGROUP_WIDTH_TILES 32 -#define TILE_WIDTH_PX 16 -#define TILE_HEIGHT_PX 16 - -// Must be the same as kernel1. Might be a good idea to move these particular -// constants to their own .h file. -#define TILEGROUP_INITIAL_ALLOC 1024 - -#define PTCL_INITIAL_ALLOC 4096 +#include "setup.h" void main() { uint tile_ix = gl_GlobalInvocationID.y * WIDTH_IN_TILES + gl_GlobalInvocationID.x; diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index ab4a0a7..6e2392b 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -20,13 +20,7 @@ layout(set = 0, binding = 1) buffer ImageBuf { #include "ptcl.h" -// TODO: make the image size dynamic. -#define IMAGE_WIDTH 2048 -#define IMAGE_HEIGHT 1535 - -#define WIDTH_IN_TILES 128 - -#define PTCL_INITIAL_ALLOC 4096 +#include "setup.h" void main() { uint tile_ix = gl_WorkGroupID.y * WIDTH_IN_TILES + gl_WorkGroupID.x; diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index a959633bc2ab51da18e70eeb9cd988f5e80894f1..c2cb755c8ffd098c3a905f3c048bbe5fa95ad2fa 100644 GIT binary patch delta 15 XcmX@1b3$iB06Wv_Rhxs@zwrS8H01_Y delta 15 WcmX@1b3$iB06UZ7@y$W(-}nGA%?0WJ diff --git a/piet-gpu/shader/setup.h b/piet-gpu/shader/setup.h new file mode 100644 index 0000000..f04462b --- /dev/null +++ b/piet-gpu/shader/setup.h @@ -0,0 +1,25 @@ +// Various constants for the sizes of groups and tiles. + +// Much of this will be made dynamic in various ways, but for now it's easiest +// to hardcode and keep all in one place. + +// TODO: make the image size dynamic. +#define IMAGE_WIDTH 2048 +#define IMAGE_HEIGHT 1536 + +// TODO: compute this +#define WIDTH_IN_TILEGROUPS 4 + +#define TILEGROUP_WIDTH_PX 512 +#define TILEGROUP_HEIGHT_PX 16 + +#define TILEGROUP_INITIAL_ALLOC 1024 + +// TODO: compute all these + +#define WIDTH_IN_TILES 128 +#define TILEGROUP_WIDTH_TILES 32 +#define TILE_WIDTH_PX 16 +#define TILE_HEIGHT_PX 16 + +#define PTCL_INITIAL_ALLOC 4096 diff --git a/piet-gpu/src/main.rs b/piet-gpu/src/main.rs index e7d2d19..6a243e9 100644 --- a/piet-gpu/src/main.rs +++ b/piet-gpu/src/main.rs @@ -4,13 +4,12 @@ use std::path::Path; use rand::{Rng, RngCore}; -use piet::{Color, RenderContext}; use piet::kurbo::{Circle, Point}; +use piet::{Color, RenderContext}; use piet_gpu_hal::vulkan::VkInstance; use piet_gpu_hal::{CmdBuf, Device, MemFlags}; - mod render_ctx; use render_ctx::PietGpuRenderContext; @@ -27,8 +26,10 @@ fn render_scene(rc: &mut impl RenderContext) { let mut rng = rand::thread_rng(); for _ in 0..N_CIRCLES { let color = Color::from_rgba32_u32(rng.next_u32()); - let center = Point::new(rng.gen_range(0.0, WIDTH as f64), - rng.gen_range(0.0, HEIGHT as f64)); + let center = Point::new( + rng.gen_range(0.0, WIDTH as f64), + rng.gen_range(0.0, HEIGHT as f64), + ); let radius = rng.gen_range(0.0, 50.0); let circle = Circle::new(center, radius); rc.fill(circle, &color); diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index dfb3cd2..4e9a567 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -1,10 +1,10 @@ use std::borrow::Cow; -use piet_gpu_types::encoder::{Encode, Encoder}; +use piet_gpu_types::encoder::{Encode, Encoder, Ref}; use piet_gpu_types::scene; -use piet_gpu_types::scene::{Bbox, PietCircle, PietItem, SimpleGroup}; +use piet_gpu_types::scene::{Bbox, PietCircle, PietItem, PietStrokePolyLine, SimpleGroup}; -use piet::kurbo::{Affine, Point, Rect, Shape}; +use piet::kurbo::{Affine, PathEl, Point, Rect, Shape}; use piet::{ Color, Error, FixedGradient, Font, FontBuilder, HitTestPoint, HitTestTextPosition, ImageFormat, @@ -39,6 +39,8 @@ pub enum PietGpuBrush { Gradient, } +const TOLERANCE: f64 = 0.1; + impl PietGpuRenderContext { pub fn new() -> PietGpuRenderContext { let mut encoder = Encoder::new(); @@ -104,7 +106,24 @@ impl RenderContext for PietGpuRenderContext { fn clear(&mut self, _color: Color) {} - fn stroke(&mut self, _shape: impl Shape, _brush: &impl IntoBrush, _width: f64) {} + fn stroke(&mut self, shape: impl Shape, brush: &impl IntoBrush, width: f64) { + let bbox = shape.bounding_box(); + let brush = brush.make_brush(self, || bbox).into_owned(); + let path = shape.to_bez_path(TOLERANCE); + let (n_points, points) = flatten_shape(&mut self.encoder, path); + match brush { + PietGpuBrush::Solid(rgba_color) => { + let poly_line = PietStrokePolyLine { + rgba_color, + width: width as f32, + n_points, + points, + }; + self.push_item(PietItem::Poly(poly_line), bbox); + } + _ => (), + } + } fn stroke_styled( &mut self, @@ -116,13 +135,7 @@ impl RenderContext for PietGpuRenderContext { } fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush) { - let dummy_closure = || Rect { - x0: 0.0, - x1: 0.0, - y0: 0.0, - y1: 0.0, - }; - let brush = brush.make_brush(self, dummy_closure).into_owned(); + let brush = brush.make_brush(self, || shape.bounding_box()).into_owned(); match shape.as_circle() { Some(circle) => match brush { @@ -212,6 +225,45 @@ impl RenderContext for PietGpuRenderContext { } } +fn flatten_shape( + encoder: &mut Encoder, + path: impl Iterator, +) -> (u32, Ref) { + let mut points = Vec::new(); + let mut start_pt = None; + let mut last_pt = None; + kurbo::flatten(path, TOLERANCE, |el| { + match el { + PathEl::MoveTo(p) => { + let scene_pt = to_scene_point(p); + start_pt = Some(clone_scene_pt(&scene_pt)); + if !points.is_empty() { + points.push(scene::Point { xy: [std::f32::NAN, std::f32::NAN ]}); + } + last_pt = Some(clone_scene_pt(&scene_pt)); + points.push(scene_pt); + } + PathEl::LineTo(p) => { + let scene_pt = to_scene_point(p); + last_pt = Some(clone_scene_pt(&scene_pt)); + points.push(scene_pt); + } + PathEl::ClosePath => { + if let (Some(start), Some(last)) = (start_pt.take(), last_pt.take()) { + if start.xy != last.xy { + points.push(start); + } + } + } + _ => (), + } + println!("{:?}", el); + }); + let n_points = points.len() as u32; + let points_ref = points.encode(encoder).transmute(); + (n_points, points_ref) +} + impl Text for PietGpuText { type Font = PietGpuFont; type FontBuilder = PietGpuFontBuilder; @@ -295,3 +347,10 @@ fn to_scene_point(point: Point) -> scene::Point { xy: [point.x as f32, point.y as f32], } } + +// TODO: allow #[derive(Clone)] in piet-gpu-derive. +fn clone_scene_pt(p: &scene::Point) -> scene::Point { + scene::Point { + xy: p.xy + } +}