diff --git a/Cargo.lock b/Cargo.lock index 3ba133e..3683e79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + [[package]] name = "ash" version = "0.30.0" @@ -84,6 +90,15 @@ dependencies = [ "adler32", ] +[[package]] +name = "kurbo" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf50e17a1697110c694d47c5b1a6b64faf5eb3ffe5a286df23fb8cd516e33be6" +dependencies = [ + "arrayvec", +] + [[package]] name = "libc" version = "0.2.69" @@ -100,10 +115,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "piet" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29420eccb68d6b9ad2f8dd87caf9c3bcd3bbd056bfe67871c48b6efab9316b79" +dependencies = [ + "kurbo", +] + [[package]] name = "piet-gpu" version = "0.1.0" dependencies = [ + "piet", "piet-gpu-hal", "piet-gpu-types", "png", diff --git a/piet-gpu/Cargo.toml b/piet-gpu/Cargo.toml index 4b7a7e9..bf68ea3 100644 --- a/piet-gpu/Cargo.toml +++ b/piet-gpu/Cargo.toml @@ -13,5 +13,6 @@ path = "../piet-gpu-hal" path = "../piet-gpu-types" [dependencies] +piet = "0.0.12" png = "0.16.2" rand = "0.7.3" diff --git a/piet-gpu/src/main.rs b/piet-gpu/src/main.rs index 1439d0e..e7d2d19 100644 --- a/piet-gpu/src/main.rs +++ b/piet-gpu/src/main.rs @@ -4,11 +4,16 @@ use std::path::Path; use rand::{Rng, RngCore}; +use piet::{Color, RenderContext}; +use piet::kurbo::{Circle, Point}; + use piet_gpu_hal::vulkan::VkInstance; use piet_gpu_hal::{CmdBuf, Device, MemFlags}; -use piet_gpu_types::encoder::{Encode, Encoder}; -use piet_gpu_types::scene::{Bbox, PietCircle, PietItem, Point, SimpleGroup}; + +mod render_ctx; + +use render_ctx::PietGpuRenderContext; const WIDTH: usize = 2048; const HEIGHT: usize = 1536; @@ -18,50 +23,16 @@ const TILE_H: usize = 16; const N_CIRCLES: usize = 3000; -fn make_scene() -> Vec { +fn render_scene(rc: &mut impl RenderContext) { let mut rng = rand::thread_rng(); - let mut encoder = Encoder::new(); - let _reserve_root = encoder.alloc_chunk(PietItem::fixed_size() as u32); - - let mut items = Vec::new(); - let mut bboxes = Vec::new(); for _ in 0..N_CIRCLES { - let circle = PietCircle { - rgba_color: rng.next_u32(), - center: Point { - xy: [ - rng.gen_range(0.0, WIDTH as f32), - rng.gen_range(0.0, HEIGHT as f32), - ], - }, - radius: rng.gen_range(0.0, 50.0), - }; - let bbox = Bbox { - bbox: [ - (circle.center.xy[0] - circle.radius).floor() as i16, - (circle.center.xy[1] - circle.radius).floor() as i16, - (circle.center.xy[0] + circle.radius).ceil() as i16, - (circle.center.xy[1] + circle.radius).ceil() as i16, - ], - }; - items.push(PietItem::Circle(circle)); - bboxes.push(bbox); + 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 radius = rng.gen_range(0.0, 50.0); + let circle = Circle::new(center, radius); + rc.fill(circle, &color); } - - let n_items = bboxes.len() as u32; - let bboxes = bboxes.encode(&mut encoder).transmute(); - let items = items.encode(&mut encoder).transmute(); - let offset = Point { xy: [0.0, 0.0] }; - let simple_group = SimpleGroup { - n_items, - bboxes, - items, - offset, - }; - let root_item = PietItem::Group(simple_group); - root_item.encode_to(&mut encoder.buf_mut()[0..PietItem::fixed_size()]); - // We should avoid this clone. - encoder.buf().to_owned() } #[allow(unused)] @@ -88,7 +59,9 @@ fn main() { let device = instance.device().unwrap(); let host = MemFlags::host_coherent(); let dev = MemFlags::device_local(); - let scene = make_scene(); + let mut ctx = PietGpuRenderContext::new(); + render_scene(&mut ctx); + let scene = ctx.get_scene_buf(); //dump_scene(&scene); let scene_buf = device .create_buffer(std::mem::size_of_val(&scene[..]) as u64, host) @@ -98,8 +71,8 @@ fn main() { .unwrap(); device.write_buffer(&scene_buf, &scene).unwrap(); // These should only be on the host if we're going to examine them from Rust. - let tilegroup_buf = device.create_buffer(384 * 1024, host).unwrap(); - let ptcl_buf = device.create_buffer(12 * 1024 * 4096, host).unwrap(); + let tilegroup_buf = device.create_buffer(384 * 1024, dev).unwrap(); + let ptcl_buf = device.create_buffer(12 * 1024 * 4096, dev).unwrap(); let image_buf = device .create_buffer((WIDTH * HEIGHT * 4) as u64, host) .unwrap(); diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs new file mode 100644 index 0000000..dfb3cd2 --- /dev/null +++ b/piet-gpu/src/render_ctx.rs @@ -0,0 +1,297 @@ +use std::borrow::Cow; + +use piet_gpu_types::encoder::{Encode, Encoder}; +use piet_gpu_types::scene; +use piet_gpu_types::scene::{Bbox, PietCircle, PietItem, SimpleGroup}; + +use piet::kurbo::{Affine, Point, Rect, Shape}; + +use piet::{ + Color, Error, FixedGradient, Font, FontBuilder, HitTestPoint, HitTestTextPosition, ImageFormat, + InterpolationMode, IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, + TextLayoutBuilder, +}; + +pub struct PietGpuImage; + +pub struct PietGpuFont; + +pub struct PietGpuFontBuilder; + +#[derive(Clone)] +pub struct PietGpuTextLayout; + +pub struct PietGpuTextLayoutBuilder; + +pub struct PietGpuText; + +pub struct PietGpuRenderContext { + encoder: Encoder, + bboxes: Vec, + items: Vec, + // Will probably need direct accesss to hal Device to create images etc. + inner_text: PietGpuText, +} + +#[derive(Clone)] +pub enum PietGpuBrush { + Solid(u32), + Gradient, +} + +impl PietGpuRenderContext { + pub fn new() -> PietGpuRenderContext { + let mut encoder = Encoder::new(); + let _reserve_root = encoder.alloc_chunk(PietItem::fixed_size() as u32); + let bboxes = Vec::new(); + let items = Vec::new(); + let inner_text = PietGpuText; + PietGpuRenderContext { + encoder, + bboxes, + items, + inner_text, + } + } + + pub fn get_scene_buf(&mut self) -> &[u8] { + let n_items = self.bboxes.len() as u32; + let bboxes = self.bboxes.encode(&mut self.encoder).transmute(); + let items = self.items.encode(&mut self.encoder).transmute(); + let offset = scene::Point { xy: [0.0, 0.0] }; + let simple_group = SimpleGroup { + n_items, + bboxes, + items, + offset, + }; + let root_item = PietItem::Group(simple_group); + root_item.encode_to(&mut self.encoder.buf_mut()[0..PietItem::fixed_size()]); + self.encoder.buf() + } + + fn push_item(&mut self, item: PietItem, bbox: Rect) { + let scene_bbox = Bbox { + bbox: [ + bbox.x0.floor() as i16, + bbox.y0.floor() as i16, + bbox.x1.ceil() as i16, + bbox.y1.ceil() as i16, + ], + }; + self.items.push(item); + self.bboxes.push(scene_bbox); + } +} + +impl RenderContext for PietGpuRenderContext { + type Brush = PietGpuBrush; + type Image = PietGpuImage; + type Text = PietGpuText; + type TextLayout = PietGpuTextLayout; + + fn status(&mut self) -> Result<(), Error> { + Ok(()) + } + + fn solid_brush(&mut self, color: Color) -> Self::Brush { + PietGpuBrush::Solid(color.as_rgba_u32()) + } + + fn gradient(&mut self, _gradient: impl Into) -> Result { + Ok(Self::Brush::Gradient) + } + + fn clear(&mut self, _color: Color) {} + + fn stroke(&mut self, _shape: impl Shape, _brush: &impl IntoBrush, _width: f64) {} + + fn stroke_styled( + &mut self, + _shape: impl Shape, + _brush: &impl IntoBrush, + _width: f64, + _style: &StrokeStyle, + ) { + } + + 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(); + + match shape.as_circle() { + Some(circle) => match brush { + PietGpuBrush::Solid(rgba_color) => { + let piet_circle = PietCircle { + rgba_color, + center: to_scene_point(circle.center), + radius: circle.radius as f32, + }; + let bbox = circle.bounding_box(); + self.push_item(PietItem::Circle(piet_circle), bbox); + } + _ => {} + }, + None => {} + } + } + + fn fill_even_odd(&mut self, _shape: impl Shape, _brush: &impl IntoBrush) {} + + fn clip(&mut self, _shape: impl Shape) {} + + fn text(&mut self) -> &mut Self::Text { + &mut self.inner_text + } + + fn draw_text( + &mut self, + _layout: &Self::TextLayout, + pos: impl Into, + brush: &impl IntoBrush, + ) { + let _pos = pos.into(); + + let brush: PietGpuBrush = brush.make_brush(self, || Rect::ZERO).into_owned(); + + match brush { + PietGpuBrush::Solid(_rgba) => { + // TODO: draw text + } + _ => {} + } + } + + fn save(&mut self) -> Result<(), Error> { + Ok(()) + } + fn restore(&mut self) -> Result<(), Error> { + Ok(()) + } + fn finish(&mut self) -> Result<(), Error> { + Ok(()) + } + fn transform(&mut self, _transform: Affine) {} + + fn make_image( + &mut self, + _width: usize, + _height: usize, + _buf: &[u8], + _format: ImageFormat, + ) -> Result { + Ok(PietGpuImage) + } + + fn draw_image( + &mut self, + _image: &Self::Image, + _rect: impl Into, + _interp: InterpolationMode, + ) { + } + + fn draw_image_area( + &mut self, + _image: &Self::Image, + _src_rect: impl Into, + _dst_rect: impl Into, + _interp: InterpolationMode, + ) { + } + + fn blurred_rect(&mut self, _rect: Rect, _blur_radius: f64, _brush: &impl IntoBrush) {} + + fn current_transform(&self) -> Affine { + Default::default() + } +} + +impl Text for PietGpuText { + type Font = PietGpuFont; + type FontBuilder = PietGpuFontBuilder; + type TextLayout = PietGpuTextLayout; + type TextLayoutBuilder = PietGpuTextLayoutBuilder; + + fn new_font_by_name(&mut self, _name: &str, _size: f64) -> Self::FontBuilder { + unimplemented!(); + } + + fn new_text_layout( + &mut self, + _font: &Self::Font, + _text: &str, + _width: f64, + ) -> Self::TextLayoutBuilder { + unimplemented!(); + } +} + +impl Font for PietGpuFont {} + +impl FontBuilder for PietGpuFontBuilder { + type Out = PietGpuFont; + + fn build(self) -> Result { + unimplemented!(); + } +} + +impl TextLayoutBuilder for PietGpuTextLayoutBuilder { + type Out = PietGpuTextLayout; + + fn build(self) -> Result { + unimplemented!() + } +} + +impl TextLayout for PietGpuTextLayout { + fn width(&self) -> f64 { + 0.0 + } + + fn update_width(&mut self, _new_width: f64) -> Result<(), Error> { + unimplemented!() + } + + fn line_text(&self, _line_number: usize) -> Option<&str> { + unimplemented!() + } + + fn line_metric(&self, _line_number: usize) -> Option { + unimplemented!() + } + + fn line_count(&self) -> usize { + unimplemented!() + } + + fn hit_test_point(&self, _point: Point) -> HitTestPoint { + unimplemented!() + } + + fn hit_test_text_position(&self, _text_position: usize) -> Option { + unimplemented!() + } +} + +impl IntoBrush for PietGpuBrush { + fn make_brush<'b>( + &'b self, + _piet: &mut PietGpuRenderContext, + _bbox: impl FnOnce() -> Rect, + ) -> std::borrow::Cow<'b, PietGpuBrush> { + Cow::Borrowed(self) + } +} + +fn to_scene_point(point: Point) -> scene::Point { + scene::Point { + xy: [point.x as f32, point.y as f32], + } +}