Merge pull request #17 from linebender/cli_args

Command line arguments
This commit is contained in:
Raph Levien 2020-06-05 09:04:55 -07:00 committed by GitHub
commit feeaa31fd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 201 additions and 42 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"
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]]
name = "approx"
version = "0.3.2"
@ -59,6 +68,17 @@ dependencies = [
"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]]
name = "autocfg"
version = "1.0.0"
@ -106,6 +126,21 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "cloudabi"
version = "0.0.3"
@ -259,6 +294,15 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "inflate"
version = "0.4.5"
@ -525,6 +569,7 @@ dependencies = [
name = "piet-gpu"
version = "0.1.0"
dependencies = [
"clap",
"piet",
"piet-gpu-hal",
"piet-gpu-types",
@ -758,6 +803,12 @@ dependencies = [
"byteorder",
]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.17"
@ -769,6 +820,21 @@ dependencies = [
"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]]
name = "unicode-xid"
version = "0.1.0"
@ -781,6 +847,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "void"
version = "1.0.2"

View file

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

View file

@ -2,10 +2,12 @@ use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use clap::{Arg, App};
use piet_gpu_hal::vulkan::VkInstance;
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)]
fn dump_scene(buf: &[u8]) {
@ -152,6 +154,17 @@ fn trace_ptcl(buf: &[u32]) {
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)?;
unsafe {
let device = instance.device(None)?;
@ -161,7 +174,17 @@ fn main() -> Result<(), Error> {
let query_pool = device.create_query_pool(5)?;
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();
//dump_scene(&scene);

View file

@ -34,6 +34,17 @@ const N_CIRCLES: usize = 0;
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) {
let mut rng = rand::thread_rng();
for _ in 0..N_CIRCLES {
@ -177,13 +188,10 @@ impl<D: Device> Renderer<D> {
// TODO: constants
let bin_alloc_start = ((n_elements + 255) & !255) * 8;
device
.write_buffer(&bin_alloc_buf_host, &[
n_elements as u32,
0,
bin_alloc_start as u32,
])
?;
device.write_buffer(
&bin_alloc_buf_host,
&[n_elements as u32, 0, bin_alloc_start as u32],
)?;
let bin_code = include_bytes!("../shader/binning.spv");
let bin_pipeline = device.create_simple_compute_pipeline(bin_code, 4, 0)?;
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_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * PTCL_INITIAL_ALLOC;
device
.write_buffer(&coarse_alloc_buf_host, &[
n_elements as u32,
coarse_alloc_start as u32,
])
?;
device.write_buffer(
&coarse_alloc_buf_host,
&[n_elements as u32, coarse_alloc_start as u32],
)?;
let coarse_code = include_bytes!("../shader/coarse.spv");
let coarse_pipeline = device.create_simple_compute_pipeline(coarse_code, 4, 0)?;
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_pipeline = device.create_simple_compute_pipeline(k4_code, 1, 1)?;
let k4_ds = device.create_descriptor_set(
&k4_pipeline,
&[&ptcl_buf],
&[&image_dev],
)?;
let k4_ds = device.create_descriptor_set(&k4_pipeline, &[&ptcl_buf], &[&image_dev])?;
Ok(Renderer {
scene_buf,

View file

@ -2,7 +2,7 @@
use std::str::FromStr;
use roxmltree::Document;
use roxmltree::{Document, Node};
use piet::kurbo::{Affine, BezPath};
@ -28,31 +28,19 @@ pub struct FillItem {
path: BezPath,
}
struct Parser<'a> {
scale: f64,
items: &'a mut Vec<Item>,
}
impl PicoSvg {
pub fn load(xml_string: &str, scale: f64) -> Result<PicoSvg, Box<dyn std::error::Error>> {
let doc = Document::parse(xml_string)?;
let root = doc.root_element();
let g = root.first_element_child().ok_or("no root element")?;
let mut items = Vec::new();
for el in g.children() {
if el.is_element() {
let d = el.attribute("d").ok_or("missing 'd' attribute")?;
let bp = BezPath::from_svg(d)?;
let path = Affine::scale(scale) * bp;
if let Some(fill_color) = el.attribute("fill") {
let color = parse_color(fill_color);
items.push(Item::Fill(FillItem {
color,
path: path.clone(),
}));
}
if let Some(stroke_color) = el.attribute("stroke") {
let width =
scale * f64::from_str(el.attribute("stroke-width").ok_or("missing width")?)?;
let color = parse_color(stroke_color);
items.push(Item::Stroke(StrokeItem { width, color, path }));
}
}
let mut parser = Parser::new(&mut items, scale);
for node in root.children() {
parser.rec_parse(node)?;
}
Ok(PicoSvg { items })
}
@ -72,6 +60,59 @@ impl PicoSvg {
}
}
impl<'a> Parser<'a> {
fn new(items: &'a mut Vec<Item>, scale: f64) -> Parser<'a> {
Parser { scale, items }
}
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() {
match node.tag_name().name() {
"g" => {
for child in node.children() {
self.rec_parse(child)?;
}
}
"path" => {
let d = node.attribute("d").ok_or("missing 'd' attribute")?;
let bp = BezPath::from_svg(d)?;
let path = transform * bp;
// TODO: default fill color is black, but this is overridden in tiger to this logic.
if let Some(fill_color) = node.attribute("fill") {
if fill_color != "none" {
let color = parse_color(fill_color);
let color = modify_opacity(color, "fill-opacity", node);
self.items.push(Item::Fill(FillItem {
color,
path: path.clone(),
}));
}
}
if let Some(stroke_color) = node.attribute("stroke") {
if stroke_color != "none" {
let width = self.scale.abs()
* f64::from_str(
node.attribute("stroke-width").ok_or("missing width")?,
)?;
let color = parse_color(stroke_color);
let color = modify_opacity(color, "stroke-opacity", node);
self.items
.push(Item::Stroke(StrokeItem { width, color, path }));
}
}
}
_ => (),
}
}
Ok(())
}
}
fn parse_color(color: &str) -> Color {
if color.as_bytes()[0] == b'#' {
let mut hex = u32::from_str_radix(&color[1..], 16).unwrap();
@ -79,7 +120,27 @@ fn parse_color(color: &str) -> Color {
hex = (hex >> 8) * 0x110000 + ((hex >> 4) & 0xf) * 0x1100 + (hex & 0xf) * 0x11;
}
Color::from_rgba32_u32((hex << 8) + 0xff)
} else if color.starts_with("rgb(") {
let mut iter = color[4..color.len() - 1].split(',');
let r = u8::from_str(iter.next().unwrap()).unwrap();
let g = u8::from_str(iter.next().unwrap()).unwrap();
let b = u8::from_str(iter.next().unwrap()).unwrap();
Color::rgb8(r, g, b)
} else {
Color::from_rgba32_u32(0xff00ff80)
}
}
fn modify_opacity(color: Color, attr_name: &str, node: Node) -> Color {
if let Some(opacity) = node.attribute(attr_name) {
let alpha = if opacity.ends_with("%") {
let pctg = opacity[..opacity.len() - 1].parse().unwrap_or(100.0);
pctg * 0.01
} else {
opacity.parse().unwrap_or(1.0)
};
color.with_alpha(alpha)
} else {
color
}
}