From 228bfc88cd259f0c01a89b1c922c318284123e97 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Thu, 16 Apr 2020 18:14:09 -0700 Subject: [PATCH] Add scene types This patch adds a module that contains both scene and ptcl types (very lightly adapted from piet-metal), as well as infrastructure for encoding Rust-side. WIP, it's not wired up in either the shader or on the Rust side. --- Cargo.lock | 7 ++ Cargo.toml | 3 +- piet-gpu-derive/src/lib.rs | 2 +- piet-gpu-hal/src/lib.rs | 2 + piet-gpu-hal/src/vulkan.rs | 4 + piet-gpu-types/Cargo.toml | 11 ++ piet-gpu-types/src/encoder.rs | 151 +++++++++++++++++++++++++ piet-gpu-types/src/lib.rs | 3 + piet-gpu-types/src/main.rs | 8 ++ piet-gpu-types/src/ptcl.rs | 47 ++++++++ piet-gpu-types/src/scene.rs | 49 +++++++++ piet-gpu/shader/image.comp | 4 + piet-gpu/shader/image.spv | Bin 2552 -> 2624 bytes piet-gpu/shader/scene.h | 200 ++++++++++++++++++++++++++++++++++ 14 files changed, 489 insertions(+), 2 deletions(-) create mode 100644 piet-gpu-types/Cargo.toml create mode 100644 piet-gpu-types/src/encoder.rs create mode 100644 piet-gpu-types/src/lib.rs create mode 100644 piet-gpu-types/src/main.rs create mode 100644 piet-gpu-types/src/ptcl.rs create mode 100644 piet-gpu-types/src/scene.rs create mode 100644 piet-gpu/shader/scene.h diff --git a/Cargo.lock b/Cargo.lock index ec2aebd..eb8a5a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,13 @@ dependencies = [ "ash", ] +[[package]] +name = "piet-gpu-types" +version = "0.0.0" +dependencies = [ + "piet-gpu-derive", +] + [[package]] name = "png" version = "0.16.2" diff --git a/Cargo.toml b/Cargo.toml index 3098acc..f71f2de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,6 @@ members = [ "piet-gpu", "piet-gpu-derive", - "piet-gpu-hal" + "piet-gpu-hal", + "piet-gpu-types" ] diff --git a/piet-gpu-derive/src/lib.rs b/piet-gpu-derive/src/lib.rs index 220def1..43177de 100644 --- a/piet-gpu-derive/src/lib.rs +++ b/piet-gpu-derive/src/lib.rs @@ -19,7 +19,7 @@ pub fn piet_gpu(input: TokenStream) -> TokenStream { let glsl = glsl::gen_glsl(&layout); let gen_gpu_fn = format_ident!("gen_gpu_{}", layout.name); let mut expanded = quote! { - fn #gen_gpu_fn() -> String { + pub fn #gen_gpu_fn() -> String { #glsl.into() } }; diff --git a/piet-gpu-hal/src/lib.rs b/piet-gpu-hal/src/lib.rs index 7fa133a..54bced7 100644 --- a/piet-gpu-hal/src/lib.rs +++ b/piet-gpu-hal/src/lib.rs @@ -75,5 +75,7 @@ pub trait CmdBuf { } pub trait MemFlags: Sized + Clone + Copy { + fn device_local() -> Self; + fn host_coherent() -> Self; } diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index f250abc..ab3e724 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -455,6 +455,10 @@ impl crate::CmdBuf for CmdBuf { } impl crate::MemFlags for MemFlags { + fn device_local() -> Self { + MemFlags(vk::MemoryPropertyFlags::DEVICE_LOCAL) + } + fn host_coherent() -> Self { MemFlags(vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT) } diff --git a/piet-gpu-types/Cargo.toml b/piet-gpu-types/Cargo.toml new file mode 100644 index 0000000..6de92a5 --- /dev/null +++ b/piet-gpu-types/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "piet-gpu-types" +version = "0.0.0" +authors = ["Raph Levien "] +description = "The scene graph and internal GPU types for piet-gpu." +license = "MIT/Apache-2.0" +edition = "2018" +keywords = ["graphics", "2d"] + +[dependencies] +piet-gpu-derive = { path = "../piet-gpu-derive" } diff --git a/piet-gpu-types/src/encoder.rs b/piet-gpu-types/src/encoder.rs new file mode 100644 index 0000000..7ac8bbb --- /dev/null +++ b/piet-gpu-types/src/encoder.rs @@ -0,0 +1,151 @@ +// Copyright 2020 The xi-editor authors. + +//! New-style encoders (supporting proc macros) + +pub struct A; + +/// A reference to an encoded object within a buffer +#[derive(Clone, Copy, Debug)] +pub struct Ref { + offset: u32, + _phantom: std::marker::PhantomData, +} + +pub struct Encoder { + buf: Vec, +} + +// TODO: we probably do want to encode slices, get rid of Sized bound +pub trait Encode: Sized { + /// Size if it's a fixed-size object, otherwise 0. + fn fixed_size() -> usize; + + /// Encoded size, for both fixed and variable sized objects. + fn encoded_size(&self) -> usize { + Self::fixed_size() + } + + /// Encode into a buffer; panics if not appropriately sized. + fn encode_to(&self, buf: &mut [u8]); + + /// Allocate a chunk and encode, returning a reference. + fn encode(&self, encoder: &mut Encoder) -> Ref { + let size = self.encoded_size(); + let (offset, buf) = encoder.alloc_chunk(size as u32); + self.encode_to(buf); + Ref::new(offset) + } +} + +impl Ref { + fn new(offset: u32) -> Ref { + Ref { + offset, + _phantom: Default::default(), + } + } + + pub fn offset(&self) -> u32 { + self.offset + } + + pub fn transmute(&self) -> Ref { + Ref::new(self.offset) + } +} + +impl Encoder { + pub fn new() -> Encoder { + Encoder { buf: Vec::new() } + } + + pub fn alloc_chunk(&mut self, size: u32) -> (u32, &mut [u8]) { + let offset = self.buf.len(); + self.buf.resize(size as usize + offset, 0); + (offset as u32, &mut self.buf[offset..]) + } + + pub fn buf(&self) -> &[u8] { + &self.buf + } + + pub fn buf_mut(&mut self) -> &mut [u8] { + &mut self.buf + } +} + +impl Encode for Ref { + fn fixed_size() -> usize { + 4 + } + + fn encode_to(&self, buf: &mut [u8]) { + buf[0..4].copy_from_slice(&self.offset.to_le_bytes()); + } +} + +// Encode impls for scalar and small vector types are as needed; it's a finite set of +// possibilities, so we could do it all with macros, but by hand is expedient. + +impl Encode for u32 { + fn fixed_size() -> usize { + 4 + } + + fn encode_to(&self, buf: &mut [u8]) { + buf[0..4].copy_from_slice(&self.to_le_bytes()); + } +} + +impl Encode for f32 { + fn fixed_size() -> usize { + 4 + } + + fn encode_to(&self, buf: &mut [u8]) { + buf[0..4].copy_from_slice(&self.to_le_bytes()); + } +} + +impl Encode for [u16; 4] { + fn fixed_size() -> usize { + 8 + } + + fn encode_to(&self, buf: &mut [u8]) { + buf[0..2].copy_from_slice(&self[0].to_le_bytes()); + buf[2..4].copy_from_slice(&self[1].to_le_bytes()); + buf[4..6].copy_from_slice(&self[2].to_le_bytes()); + buf[6..8].copy_from_slice(&self[3].to_le_bytes()); + } +} + +impl Encode for [f32; 2] { + fn fixed_size() -> usize { + 8 + } + + fn encode_to(&self, buf: &mut [u8]) { + buf[0..4].copy_from_slice(&self[0].to_le_bytes()); + buf[4..8].copy_from_slice(&self[1].to_le_bytes()); + } +} + +// TODO: make this work for slices too, but need to deal with Sized bound +// +// Note: only works for vectors of fixed size objects. +impl Encode for Vec { + fn fixed_size() -> usize { + 0 + } + fn encoded_size(&self) -> usize { + self.len() * T::fixed_size() + } + + fn encode_to(&self, buf: &mut [u8]) { + let size = T::fixed_size(); + for (ix, val) in self.iter().enumerate() { + val.encode_to(&mut buf[ix * size..]); + } + } +} diff --git a/piet-gpu-types/src/lib.rs b/piet-gpu-types/src/lib.rs new file mode 100644 index 0000000..60c11ab --- /dev/null +++ b/piet-gpu-types/src/lib.rs @@ -0,0 +1,3 @@ +pub mod encoder; +pub mod ptcl; +pub mod scene; diff --git a/piet-gpu-types/src/main.rs b/piet-gpu-types/src/main.rs new file mode 100644 index 0000000..00a5d0b --- /dev/null +++ b/piet-gpu-types/src/main.rs @@ -0,0 +1,8 @@ +fn main() { + let mod_name = std::env::args().skip(1).next().expect("provide a module name"); + match mod_name.as_str() { + "scene" => print!("{}", piet_gpu_types::scene::gen_gpu_scene()), + "ptcl" => print!("{}", piet_gpu_types::ptcl::gen_gpu_ptcl()), + _ => println!("Oops, unknown module name"), + } +} diff --git a/piet-gpu-types/src/ptcl.rs b/piet-gpu-types/src/ptcl.rs new file mode 100644 index 0000000..f5e42af --- /dev/null +++ b/piet-gpu-types/src/ptcl.rs @@ -0,0 +1,47 @@ +use piet_gpu_derive::piet_gpu; + +piet_gpu! { + #[gpu_write] + mod ptcl { + struct CmdCircle { + // In existing code, this is packed; we might need an annotation for this. + bbox: [u16; 4], + } + struct CmdLine { + start: [f32; 2], + end: [f32; 2], + } + struct CmdStroke { + // In existing code, this is f16. Should we have support? + halfWidth: f32, + rgba_color: u32, + } + struct CmdFill { + start: [f32; 2], + end: [f32; 2], + } + struct CmdFillEdge { + // The sign is only one bit. + sign: i32, + y: f32, + } + struct CmdDrawFill { + backdrop: i32, + rgba_color: u32, + } + struct CmdSolid { + rgba_color: u32, + } + enum Cmd { + End, + Circle(CmdCircle), + Line(CmdLine), + Fill(CmdFill), + Stroke(CmdStroke), + FillEdge(CmdFillEdge), + DrawFill(CmdDrawFill), + Solid(CmdSolid), + Bail, + } + } +} diff --git a/piet-gpu-types/src/scene.rs b/piet-gpu-types/src/scene.rs new file mode 100644 index 0000000..d2cc466 --- /dev/null +++ b/piet-gpu-types/src/scene.rs @@ -0,0 +1,49 @@ +use piet_gpu_derive::piet_gpu; + +pub use self::scene::{ + Bbox, PietFill, PietItem, PietStrokeLine, PietStrokePolyLine, Point, SimpleGroup, +}; + +piet_gpu! { + #[rust_encode] + mod scene { + struct Bbox { + // TODO: this should be i16 + bbox: [u16; 4], + } + struct Point { + xy: [f32; 2], + } + struct SimpleGroup { + n_items: u32, + // Note: both of the following items are actually arrays + items: Ref, + bboxes: Ref, + } + struct PietStrokeLine { + flags: u32, + rgba_color: u32, + width: f32, + start: Point, + end: Point, + } + struct PietFill { + flags: u32, + rgba_color: u32, + n_points: u32, + points: Ref, + } + struct PietStrokePolyLine { + rgba_color: u32, + width: f32, + n_points: u32, + points: Ref, + } + enum PietItem { + Circle(), + Line(PietStrokeLine), + Fill(PietFill), + Poly(PietStrokePolyLine), + } + } +} diff --git a/piet-gpu/shader/image.comp b/piet-gpu/shader/image.comp index 2c35e74..5487366 100644 --- a/piet-gpu/shader/image.comp +++ b/piet-gpu/shader/image.comp @@ -4,6 +4,8 @@ // plan is to use a texture. This is because of limited support. #version 450 +#extension GL_GOOGLE_include_directive : enable + layout(local_size_x = 16, local_size_y = 16) in; layout(set = 0, binding = 0) readonly buffer SceneBuf { @@ -14,6 +16,8 @@ layout(set = 0, binding = 1) buffer ImageBuf { uint[] image; }; +#include "scene.h" + // TODO: make the image size dynamic. #define IMAGE_WIDTH 2048 #define IMAGE_HEIGHT 1535 diff --git a/piet-gpu/shader/image.spv b/piet-gpu/shader/image.spv index dd4bbc8df31821aa89bf7d2c2cca0ec4e346a6b2..e05c8c0b2c93bb8614f9adb4c529eac717fb9354 100644 GIT binary patch delta 82 zcmew%d_ZJEjXMhi7lXS`yt}`@yN_#pazR0SaYIQ#NoH9p0|N^K T2a>wXyyTqH6eI;3t7|y{ZL1s= delta 10 RcmX>g@> 2; + uint raw0 = scene[ix + 0]; + uint raw1 = scene[ix + 1]; + Bbox s; + s.bbox = uvec4(raw0 & 0xffff, raw0 >> 16, raw1 & 0xffff, raw1 >> 16); + return s; +} + +Point Point_read(PointRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = scene[ix + 0]; + uint raw1 = scene[ix + 1]; + Point s; + s.xy = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); + return s; +} + +SimpleGroup SimpleGroup_read(SimpleGroupRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = scene[ix + 0]; + uint raw1 = scene[ix + 1]; + uint raw2 = scene[ix + 2]; + SimpleGroup s; + s.n_items = raw0; + s.items = PietItemRef(raw1); + s.bboxes = BboxRef(raw2); + return s; +} + +PietStrokeLine PietStrokeLine_read(PietStrokeLineRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = scene[ix + 0]; + uint raw1 = scene[ix + 1]; + uint raw2 = scene[ix + 2]; + PietStrokeLine s; + s.flags = raw0; + s.rgba_color = raw1; + s.width = uintBitsToFloat(raw2); + s.start = Point_read(PointRef(ref.offset + 12)); + s.end = Point_read(PointRef(ref.offset + 20)); + return s; +} + +PietFill PietFill_read(PietFillRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = scene[ix + 0]; + uint raw1 = scene[ix + 1]; + uint raw2 = scene[ix + 2]; + uint raw3 = scene[ix + 3]; + PietFill s; + s.flags = raw0; + s.rgba_color = raw1; + s.n_points = raw2; + s.points = PointRef(raw3); + return s; +} + +PietStrokePolyLine PietStrokePolyLine_read(PietStrokePolyLineRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = scene[ix + 0]; + uint raw1 = scene[ix + 1]; + uint raw2 = scene[ix + 2]; + uint raw3 = scene[ix + 3]; + PietStrokePolyLine s; + s.rgba_color = raw0; + s.width = uintBitsToFloat(raw1); + s.n_points = raw2; + s.points = PointRef(raw3); + return s; +} + +uint PietItem_tag(PietItemRef ref) { + return scene[ref.offset >> 2]; +} + +PietStrokeLine PietItem_Line_read(PietItemRef ref) { + return PietStrokeLine_read(PietStrokeLineRef(ref.offset + 4)); +} + +PietFill PietItem_Fill_read(PietItemRef ref) { + return PietFill_read(PietFillRef(ref.offset + 4)); +} + +PietStrokePolyLine PietItem_Poly_read(PietItemRef ref) { + return PietStrokePolyLine_read(PietStrokePolyLineRef(ref.offset + 4)); +} +