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 dd4bbc8..e05c8c0 100644 Binary files a/piet-gpu/shader/image.spv and b/piet-gpu/shader/image.spv differ diff --git a/piet-gpu/shader/scene.h b/piet-gpu/shader/scene.h new file mode 100644 index 0000000..eb99bd4 --- /dev/null +++ b/piet-gpu/shader/scene.h @@ -0,0 +1,200 @@ +// Code auto-generated by piet-gpu-derive + +struct BboxRef { + uint offset; +}; + +struct PointRef { + uint offset; +}; + +struct SimpleGroupRef { + uint offset; +}; + +struct PietStrokeLineRef { + uint offset; +}; + +struct PietFillRef { + uint offset; +}; + +struct PietStrokePolyLineRef { + uint offset; +}; + +struct PietItemRef { + uint offset; +}; + +struct Bbox { + uvec4 bbox; +}; + +#define Bbox_size 8 + +BboxRef Bbox_index(BboxRef ref, uint index) { + return BboxRef(ref.offset + index * Bbox_size); +} + +struct Point { + vec2 xy; +}; + +#define Point_size 8 + +PointRef Point_index(PointRef ref, uint index) { + return PointRef(ref.offset + index * Point_size); +} + +struct SimpleGroup { + uint n_items; + PietItemRef items; + BboxRef bboxes; +}; + +#define SimpleGroup_size 12 + +SimpleGroupRef SimpleGroup_index(SimpleGroupRef ref, uint index) { + return SimpleGroupRef(ref.offset + index * SimpleGroup_size); +} + +struct PietStrokeLine { + uint flags; + uint rgba_color; + float width; + Point start; + Point end; +}; + +#define PietStrokeLine_size 28 + +PietStrokeLineRef PietStrokeLine_index(PietStrokeLineRef ref, uint index) { + return PietStrokeLineRef(ref.offset + index * PietStrokeLine_size); +} + +struct PietFill { + uint flags; + uint rgba_color; + uint n_points; + PointRef points; +}; + +#define PietFill_size 16 + +PietFillRef PietFill_index(PietFillRef ref, uint index) { + return PietFillRef(ref.offset + index * PietFill_size); +} + +struct PietStrokePolyLine { + uint rgba_color; + float width; + uint n_points; + PointRef points; +}; + +#define PietStrokePolyLine_size 16 + +PietStrokePolyLineRef PietStrokePolyLine_index(PietStrokePolyLineRef ref, uint index) { + return PietStrokePolyLineRef(ref.offset + index * PietStrokePolyLine_size); +} + +#define PietItem_Circle 0 +#define PietItem_Line 1 +#define PietItem_Fill 2 +#define PietItem_Poly 3 +#define PietItem_size 32 + +PietItemRef PietItem_index(PietItemRef ref, uint index) { + return PietItemRef(ref.offset + index * PietItem_size); +} + +Bbox Bbox_read(BboxRef ref) { + uint ix = ref.offset >> 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)); +} +