Add command line args for loading svg

This commit is contained in:
Raph Levien 2020-05-31 09:55:20 -07:00
parent c603cafc6c
commit f3cb904f86
5 changed files with 139 additions and 30 deletions

72
Cargo.lock generated
View file

@ -26,6 +26,15 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi 0.3.8",
]
[[package]] [[package]]
name = "approx" name = "approx"
version = "0.3.2" version = "0.3.2"
@ -59,6 +68,17 @@ dependencies = [
"raw-window-handle", "raw-window-handle",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi 0.3.8",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.0" version = "1.0.0"
@ -106,6 +126,21 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "clap"
version = "2.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]] [[package]]
name = "cloudabi" name = "cloudabi"
version = "0.0.3" version = "0.0.3"
@ -259,6 +294,15 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36b5f248235f45773d4944f555f83ea61fe07b18b561ccf99d7483d7381e54d" checksum = "f36b5f248235f45773d4944f555f83ea61fe07b18b561ccf99d7483d7381e54d"
[[package]]
name = "hermit-abi"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "inflate" name = "inflate"
version = "0.4.5" version = "0.4.5"
@ -525,6 +569,7 @@ dependencies = [
name = "piet-gpu" name = "piet-gpu"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap",
"piet", "piet",
"piet-gpu-hal", "piet-gpu-hal",
"piet-gpu-types", "piet-gpu-types",
@ -758,6 +803,12 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.17" version = "1.0.17"
@ -769,6 +820,21 @@ dependencies = [
"unicode-xid 0.2.0", "unicode-xid 0.2.0",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.1.0" version = "0.1.0"
@ -781,6 +847,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "void" name = "void"
version = "1.0.2" version = "1.0.2"

View file

@ -26,3 +26,4 @@ png = "0.16.2"
rand = "0.7.3" rand = "0.7.3"
roxmltree = "0.11" roxmltree = "0.11"
winit = "0.22" winit = "0.22"
clap = "2.33"

View file

@ -2,10 +2,12 @@ use std::fs::File;
use std::io::BufWriter; use std::io::BufWriter;
use std::path::Path; use std::path::Path;
use clap::{Arg, App};
use piet_gpu_hal::vulkan::VkInstance; use piet_gpu_hal::vulkan::VkInstance;
use piet_gpu_hal::{CmdBuf, Device, Error, MemFlags}; use piet_gpu_hal::{CmdBuf, Device, Error, MemFlags};
use piet_gpu::{render_scene, PietGpuRenderContext, Renderer, HEIGHT, WIDTH}; use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer, HEIGHT, WIDTH};
#[allow(unused)] #[allow(unused)]
fn dump_scene(buf: &[u8]) { fn dump_scene(buf: &[u8]) {
@ -152,6 +154,17 @@ fn trace_ptcl(buf: &[u32]) {
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
let matches = App::new("piet-gpu test")
.arg(Arg::with_name("INPUT")
.index(1))
.arg(Arg::with_name("flip")
.short("f")
.long("flip"))
.arg(Arg::with_name("scale")
.short("s")
.long("scale")
.takes_value(true))
.get_matches();
let (instance, _) = VkInstance::new(None)?; let (instance, _) = VkInstance::new(None)?;
unsafe { unsafe {
let device = instance.device(None)?; let device = instance.device(None)?;
@ -161,7 +174,17 @@ fn main() -> Result<(), Error> {
let query_pool = device.create_query_pool(5)?; let query_pool = device.create_query_pool(5)?;
let mut ctx = PietGpuRenderContext::new(); let mut ctx = PietGpuRenderContext::new();
render_scene(&mut ctx); if let Some(input) = matches.value_of("INPUT") {
let mut scale = matches.value_of("scale")
.map(|scale| scale.parse().unwrap())
.unwrap_or(8.0);
if matches.is_present("flip") {
scale = -scale;
}
render_svg(&mut ctx, input, scale);
} else {
render_scene(&mut ctx);
}
let scene = ctx.get_scene_buf(); let scene = ctx.get_scene_buf();
//dump_scene(&scene); //dump_scene(&scene);

View file

@ -34,6 +34,17 @@ const N_CIRCLES: usize = 0;
const N_WG: u32 = 16; const N_WG: u32 = 16;
pub fn render_svg(rc: &mut impl RenderContext, filename: &str, scale: f64) {
let xml_str = std::fs::read_to_string(filename).unwrap();
let start = std::time::Instant::now();
let svg = PicoSvg::load(&xml_str, scale).unwrap();
println!("parsing time: {:?}", start.elapsed());
let start = std::time::Instant::now();
svg.render(rc);
println!("flattening and encoding time: {:?}", start.elapsed());
}
pub fn render_scene(rc: &mut impl RenderContext) { pub fn render_scene(rc: &mut impl RenderContext) {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
for _ in 0..N_CIRCLES { for _ in 0..N_CIRCLES {
@ -138,7 +149,7 @@ pub struct Renderer<D: Device> {
k4_pipeline: D::Pipeline, k4_pipeline: D::Pipeline,
k4_ds: D::DescriptorSet, k4_ds: D::DescriptorSet,
n_elements: usize, n_elements: usize,
} }
@ -177,13 +188,10 @@ impl<D: Device> Renderer<D> {
// TODO: constants // TODO: constants
let bin_alloc_start = ((n_elements + 255) & !255) * 8; let bin_alloc_start = ((n_elements + 255) & !255) * 8;
device device.write_buffer(
.write_buffer(&bin_alloc_buf_host, &[ &bin_alloc_buf_host,
n_elements as u32, &[n_elements as u32, 0, bin_alloc_start as u32],
0, )?;
bin_alloc_start as u32,
])
?;
let bin_code = include_bytes!("../shader/binning.spv"); let bin_code = include_bytes!("../shader/binning.spv");
let bin_pipeline = device.create_simple_compute_pipeline(bin_code, 4, 0)?; let bin_pipeline = device.create_simple_compute_pipeline(bin_code, 4, 0)?;
let bin_ds = device.create_descriptor_set( let bin_ds = device.create_descriptor_set(
@ -196,12 +204,10 @@ impl<D: Device> Renderer<D> {
let coarse_alloc_buf_dev = device.create_buffer(8, dev)?; let coarse_alloc_buf_dev = device.create_buffer(8, dev)?;
let coarse_alloc_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * PTCL_INITIAL_ALLOC; let coarse_alloc_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * PTCL_INITIAL_ALLOC;
device device.write_buffer(
.write_buffer(&coarse_alloc_buf_host, &[ &coarse_alloc_buf_host,
n_elements as u32, &[n_elements as u32, coarse_alloc_start as u32],
coarse_alloc_start as u32, )?;
])
?;
let coarse_code = include_bytes!("../shader/coarse.spv"); let coarse_code = include_bytes!("../shader/coarse.spv");
let coarse_pipeline = device.create_simple_compute_pipeline(coarse_code, 4, 0)?; let coarse_pipeline = device.create_simple_compute_pipeline(coarse_code, 4, 0)?;
let coarse_ds = device.create_descriptor_set( let coarse_ds = device.create_descriptor_set(
@ -212,11 +218,7 @@ impl<D: Device> Renderer<D> {
let k4_code = include_bytes!("../shader/kernel4.spv"); let k4_code = include_bytes!("../shader/kernel4.spv");
let k4_pipeline = device.create_simple_compute_pipeline(k4_code, 1, 1)?; let k4_pipeline = device.create_simple_compute_pipeline(k4_code, 1, 1)?;
let k4_ds = device.create_descriptor_set( let k4_ds = device.create_descriptor_set(&k4_pipeline, &[&ptcl_buf], &[&image_dev])?;
&k4_pipeline,
&[&ptcl_buf],
&[&image_dev],
)?;
Ok(Renderer { Ok(Renderer {
scene_buf, scene_buf,

View file

@ -29,6 +29,7 @@ pub struct FillItem {
} }
struct Parser<'a> { struct Parser<'a> {
scale: f64,
items: &'a mut Vec<Item>, items: &'a mut Vec<Item>,
} }
@ -37,7 +38,7 @@ impl PicoSvg {
let doc = Document::parse(xml_string)?; let doc = Document::parse(xml_string)?;
let root = doc.root_element(); let root = doc.root_element();
let mut items = Vec::new(); let mut items = Vec::new();
let mut parser = Parser::new(&mut items); let mut parser = Parser::new(&mut items, scale);
for node in root.children() { for node in root.children() {
parser.rec_parse(node)?; parser.rec_parse(node)?;
} }
@ -60,13 +61,16 @@ impl PicoSvg {
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
fn new(items: &'a mut Vec<Item>) -> Parser<'a> { fn new(items: &'a mut Vec<Item>, scale: f64) -> Parser<'a> {
Parser { Parser { scale, items }
items
}
} }
fn rec_parse(&mut self, node: Node) -> Result<(), Box<dyn std::error::Error>> { fn rec_parse(&mut self, node: Node) -> Result<(), Box<dyn std::error::Error>> {
let transform = if self.scale >= 0.0 {
Affine::scale(self.scale)
} else {
Affine::new([-self.scale, 0.0, 0.0, self.scale, 0.0, 1536.0])
};
if node.is_element() { if node.is_element() {
match node.tag_name().name() { match node.tag_name().name() {
"g" => { "g" => {
@ -77,21 +81,28 @@ impl<'a> Parser<'a> {
"path" => { "path" => {
let d = node.attribute("d").ok_or("missing 'd' attribute")?; let d = node.attribute("d").ok_or("missing 'd' attribute")?;
let bp = BezPath::from_svg(d)?; let bp = BezPath::from_svg(d)?;
let path = Affine::new([1.5, 0.0, 0.0, -1.5, 0.0, 1500.0]) * bp; let path = transform * bp;
// TODO: default fill color is black, but this is overridden in tiger to this logic. // TODO: default fill color is black, but this is overridden in tiger to this logic.
if let Some(fill_color) = node.attribute("fill") { if let Some(fill_color) = node.attribute("fill") {
if fill_color != "none" { if fill_color != "none" {
let color = parse_color(fill_color); let color = parse_color(fill_color);
let color = modify_opacity(color, "fill-opacity", node); let color = modify_opacity(color, "fill-opacity", node);
self.items.push(Item::Fill(FillItem { color, path: path.clone() })); self.items.push(Item::Fill(FillItem {
color,
path: path.clone(),
}));
} }
} }
if let Some(stroke_color) = node.attribute("stroke") { if let Some(stroke_color) = node.attribute("stroke") {
if stroke_color != "none" { if stroke_color != "none" {
let width = 1.5 * f64::from_str(node.attribute("stroke-width").ok_or("missing width")?)?; let width = self.scale.abs()
* f64::from_str(
node.attribute("stroke-width").ok_or("missing width")?,
)?;
let color = parse_color(stroke_color); let color = parse_color(stroke_color);
let color = modify_opacity(color, "stroke-opacity", node); let color = modify_opacity(color, "stroke-opacity", node);
self.items.push(Item::Stroke(StrokeItem { width, color, path })); self.items
.push(Item::Stroke(StrokeItem { width, color, path }));
} }
} }
} }