Use 'C style' preprocessing in piet-wgsl (#194)

This lets us use https://github.com/wgsl-analyzer/wgsl-analyzer for writing the wgsl files.
The imports (for wgsl-analyzer) have to be machine specific at the moment - to use this you need to configure .vscode/settings.json yourself. The alternative is to point them at static files on GitHub, which is tempting to make things easier, but would potentially go out of sync with what is actually used.
This commit is contained in:
Daniel McNab 2022-10-27 15:27:46 +01:00 committed by GitHub
parent b42679c675
commit afa706bd7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 167 additions and 247 deletions

10
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
"wgsl-analyzer.customImports": {
// Update as appropriate to proper path
// temporary solution
// "config": "file:C:\\Users\\Daniel\\Documents\\repositories\\linebender\\piet-gpu\\piet-wgsl\\shader\\shared\\config.wgsl",
// "segment": "file:C:\\Users\\Daniel\\Documents\\repositories\\linebender\\piet-gpu\\piet-wgsl\\shader\\shared\\segment.wgsl",
// "pathtag": "file:C:\\Users\\Daniel\\Documents\\repositories\\linebender\\piet-gpu\\piet-wgsl\\shader\\shared\\pathtag.wgsl"
},
"wgsl-analyzer.diagnostics.nagaVersion": "main"
}

189
Cargo.lock generated
View file

@ -122,15 +122,6 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.11.1"
@ -230,9 +221,9 @@ dependencies = [
[[package]]
name = "clap"
version = "3.2.22"
version = "3.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750"
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
dependencies = [
"atty",
"bitflags",
@ -240,7 +231,7 @@ dependencies = [
"indexmap",
"strsim 0.10.0",
"termcolor",
"textwrap 0.15.1",
"textwrap 0.16.0",
]
[[package]]
@ -334,15 +325,6 @@ dependencies = [
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
@ -352,16 +334,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "cty"
version = "0.2.2"
@ -449,16 +421,6 @@ dependencies = [
"syn",
]
[[package]]
name = "digest"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "dispatch"
version = "0.2.0"
@ -559,16 +521,6 @@ dependencies = [
"byteorder",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -648,21 +600,6 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
version = "4.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "433e4ab33f1213cdc25b5fa45c76881240cfe79284cf2b395e8b9e312a30a2fd"
dependencies = [
"log",
"pest",
"pest_derive",
"serde",
"serde_json",
"thiserror",
"walkdir",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -885,14 +822,14 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.4"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.36.1",
"windows-sys 0.42.0",
]
[[package]]
@ -1137,50 +1074,6 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a"
dependencies = [
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d"
dependencies = [
"once_cell",
"pest",
"sha1",
]
[[package]]
name = "pgpu-render"
version = "0.1.0"
@ -1199,7 +1092,7 @@ name = "piet-gpu"
version = "0.1.0"
dependencies = [
"bytemuck",
"clap 3.2.22",
"clap 3.2.23",
"kurbo 0.8.3",
"ndk 0.3.0",
"ndk-glue 0.3.0",
@ -1249,7 +1142,7 @@ name = "piet-gpu-tests"
version = "0.1.0"
dependencies = [
"bytemuck",
"clap 3.2.22",
"clap 3.2.23",
"kurbo 0.7.1",
"piet-gpu",
"piet-gpu-hal",
@ -1281,13 +1174,10 @@ dependencies = [
"bytemuck",
"env_logger",
"futures-intrusive",
"handlebars",
"parking_lot",
"piet-scene",
"png",
"pollster",
"serde",
"serde_json",
"wgpu",
]
@ -1550,15 +1440,6 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
@ -1573,18 +1454,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.145"
version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.145"
version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
dependencies = [
"proc-macro2",
"quote",
@ -1593,26 +1474,15 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.86"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "slotmap"
version = "1.0.6"
@ -1726,9 +1596,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.15.1"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
@ -1759,18 +1629,6 @@ dependencies = [
"serde",
]
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "ucd-trie"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "unicode-ident"
version = "1.0.5"
@ -1807,17 +1665,6 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
@ -2206,9 +2053,9 @@ checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "winit"
version = "0.27.4"
version = "0.27.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37f64802920c4c35d12a53dad5e0c55bbc3004d8dc4f2e4dd64ad02c5665d7aa"
checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c"
dependencies = [
"bitflags",
"cocoa",

View file

@ -12,9 +12,6 @@ pollster = "0.2.5"
futures-intrusive = "0.4.1"
parking_lot = "0.12"
bytemuck = { version = "1.12.1", features = ["derive"] }
handlebars = { version = "4.3.5", features = ["dir_source"] }
serde_json = "1"
serde = { version = "1", features = ["derive"] }
png = "0.17.6"
piet-scene = { path = "../piet-scene" }

View file

@ -20,7 +20,7 @@ struct Tile {
segments: u32,
}
{{> config}}
#import config
@group(0) @binding(0)
var<storage> config: Config;
@ -42,20 +42,20 @@ fn main(
let width_in_tiles = config.width_in_tiles;
let ix = wg_id.x * width_in_tiles + local_id.x;
var backdrop = 0;
if local_id.x < width_in_tiles {
if (local_id.x < width_in_tiles) {
backdrop = tiles[ix].backdrop;
}
sh_backdrop[local_id.x] = backdrop;
// iterate log2(WG_SIZE) times
for (var i = 0u; i < firstTrailingBit(WG_SIZE); i += 1u) {
workgroupBarrier();
if local_id.x >= (1u << i) {
if (local_id.x >= (1u << i)) {
backdrop += sh_backdrop[local_id.x - (1u << i)];
}
workgroupBarrier();
sh_backdrop[local_id.x] = backdrop;
}
if local_id.x < width_in_tiles {
if (local_id.x < width_in_tiles) {
tiles[ix].backdrop = backdrop;
}
}

View file

@ -20,8 +20,8 @@ struct Tile {
segments: u32,
}
{{> segment}}
{{> config}}
#import segment
#import config
@group(0) @binding(0)
var<storage> config: Config;
@ -59,7 +59,7 @@ fn main(
let y0 = clamp(y, 0.0, 1.0);
let y1 = clamp(y + segment.delta.y, 0.0, 1.0);
let dy = y0 - y1;
if dy != 0.0 {
if (dy != 0.0) {
let vec_y_recip = 1.0 / segment.delta.y;
let t0 = (y0 - y) * vec_y_recip;
let t1 = (y1 - y) * vec_y_recip;

View file

@ -14,7 +14,7 @@
//
// Also licensed under MIT license, at your choice.
{{> pathtag}}
#import pathtag
@group(0) @binding(0)
var<storage> path_tags: array<u32>;
@ -26,18 +26,18 @@ var<storage> tag_monoids: array<TagMonoid>;
@group(0) @binding(2)
var<storage> path_data: array<u32>;
{{#if cubics_out}}
#ifdef cubics_out
@group(0) @binding(3)
var<storage, read_write> output: array<vec2<f32>>;
{{else}}
{{> config}}
#else
#import config
struct Tile {
backdrop: atomic<i32>,
segments: atomic<u32>,
}
{{> segment}}
#import segment
// Should probably be uniform binding
@group(0) @binding(3)
@ -48,7 +48,7 @@ var<storage, read_write> tiles: array<Tile>;
@group(0) @binding(5)
var<storage, read_write> segments: array<Segment>;
{{/if}}
#endif
fn read_f32_point(ix: u32) -> vec2<f32> {
let x = bitcast<f32>(path_data[ix]);
@ -63,7 +63,7 @@ fn read_i16_point(ix: u32) -> vec2<f32> {
return vec2<f32>(x, y);
}
{{#unless cubics_out}}
#ifndef cubics_out
let TILE_WIDTH = 16u;
let TILE_HEIGHT = 16u;
@ -125,7 +125,7 @@ fn alloc_segment() -> u32 {
// TODO: separate small buffer binding for this?
return atomicAdd(&tiles[4096].segments, 1u) + 1u;
}
{{/unless}}
#endif
let MAX_QUADS = 16u;
@ -180,13 +180,13 @@ fn main(
p2 = mix(p1, p2, 1.0 / 3.0);
p1 = mix(p1, p0, 1.0 / 3.0);
}
{{#if cubics_out}}
#ifdef cubics_out
let out_ix = ix * 4u;
output[out_ix] = p0;
output[out_ix + 1u] = p1;
output[out_ix + 2u] = p2;
output[out_ix + 3u] = p3;
{{else}}
#else
let err_v = 3.0 * (p2 - p1) + p0 - p3;
let err = dot(err_v, err_v);
let ACCURACY = 0.25;
@ -323,6 +323,6 @@ fn main(
val_sum += params.val;
qp0 = qp2;
}
{{/if}}
#endif
}
}

View file

@ -14,7 +14,7 @@
//
// Also licensed under MIT license, at your choice.
{{> pathtag}}
#import pathtag
// Note: should have a single scene binding, path_tags are a slice
// in that; need a config uniform.
@ -50,4 +50,4 @@ fn main(
if local_id.x == 0u {
reduced[ix >> LG_WG_SIZE] = agg;
}
}
}

View file

@ -14,7 +14,7 @@
//
// Also licensed under MIT license, at your choice.
{{> pathtag}}
#import pathtag
@group(0) @binding(0)
var<storage> path_tags: array<u32>;

View file

@ -27,7 +27,6 @@ use wgpu::{Device, Queue};
mod engine;
mod render;
mod shaders;
mod template;
mod test_scene;
async fn run() -> Result<(), Box<dyn std::error::Error>> {

View file

@ -16,13 +16,13 @@
//! Load rendering shaders.
use serde_json::json;
mod preprocess;
use std::{collections::HashSet, fs, path::Path};
use wgpu::Device;
use crate::{
engine::{BindType, Engine, Error, ShaderId},
template::ShaderTemplate,
};
use crate::engine::{BindType, Engine, Error, ShaderId};
pub const PATHTAG_REDUCE_WG: u32 = 256;
pub const PATH_COARSE_WG: u32 = 256;
@ -36,27 +36,31 @@ pub struct Shaders {
}
pub fn init_shaders(device: &Device, engine: &mut Engine) -> Result<Shaders, Error> {
let shaders = ShaderTemplate::new();
let shader_dir = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/shader"));
let imports = preprocess::get_imports(shader_dir);
let read_shader =
|path: &str| fs::read_to_string(shader_dir.join(path.to_string() + ".wgsl")).unwrap();
let empty = HashSet::new();
let pathtag_reduce = engine.add_shader(
device,
shaders.get_shader("pathtag_reduce", &()).into(),
preprocess::preprocess(&read_shader("pathtag_reduce"), &empty, &imports).into(),
&[BindType::BufReadOnly, BindType::Buffer],
)?;
let pathtag_scan = engine.add_shader(
device,
shaders.get_shader("pathtag_scan", &()).into(),
preprocess::preprocess(&read_shader("pathtag_scan"), &empty, &imports).into(),
&[
BindType::BufReadOnly,
BindType::BufReadOnly,
BindType::Buffer,
],
)?;
let path_coarse_config = json!({"cubics_out": false});
let path_coarse_config = HashSet::new();
// path_coarse_config.add("cubics_out");
let path_coarse = engine.add_shader(
device,
shaders
.get_shader("path_coarse", &path_coarse_config)
.into(),
preprocess::preprocess(&read_shader("path_coarse"), &path_coarse_config, &imports).into(),
&[
BindType::BufReadOnly,
BindType::BufReadOnly,
@ -68,12 +72,12 @@ pub fn init_shaders(device: &Device, engine: &mut Engine) -> Result<Shaders, Err
)?;
let backdrop = engine.add_shader(
device,
shaders.get_shader("backdrop", &()).into(),
preprocess::preprocess(&read_shader("backdrop"), &empty, &imports).into(),
&[BindType::BufReadOnly, BindType::Buffer],
)?;
let fine = engine.add_shader(
device,
shaders.get_shader("fine", &()).into(),
preprocess::preprocess(&read_shader("fine"), &empty, &imports).into(),
&[
BindType::BufReadOnly,
BindType::BufReadOnly,

View file

@ -0,0 +1,100 @@
use std::{
collections::{HashMap, HashSet},
fs,
path::Path,
vec,
};
pub fn get_imports(shader_dir: &Path) -> HashMap<String, String> {
let mut imports = HashMap::new();
let imports_dir = shader_dir.join("shared");
for entry in imports_dir
.read_dir()
.expect("Can read shader import directory")
{
let entry = entry.expect("Can continue reading shader import directory");
if entry.file_type().unwrap().is_file() {
let file_name = entry.file_name();
if let Some(name) = file_name.to_str() {
let suffix = ".wgsl";
if name.ends_with(suffix) {
let import_name = name[..(name.len() - suffix.len())].to_owned();
let contents = fs::read_to_string(imports_dir.join(file_name))
.expect("Could read shader {import_name} contents");
imports.insert(import_name, contents);
}
}
}
}
imports
}
pub struct StackItem {
active: bool,
else_passed: bool,
}
pub fn preprocess(
input: &str,
defines: &HashSet<String>,
imports: &HashMap<String, String>,
) -> String {
let mut output = String::with_capacity(input.len());
let mut stack = vec![];
for (line_number, line) in input.lines().enumerate() {
let trimmed = line.trim();
if trimmed.starts_with("#") {
let trimmed = &trimmed[1..];
let val_idx = trimmed
.chars()
.take_while(|char| char.is_alphanumeric())
.map(char::len_utf8)
.sum();
let arg = trimmed[val_idx..].trim();
match &trimmed[..val_idx] {
x @ ("ifdef" | "ifndef") => {
let exists = defines.contains(arg);
let mode = x == "ifdef";
stack.push(StackItem {
active: mode == exists,
else_passed: false,
});
}
"else" => {
let item = stack.last_mut();
if let Some(item) = item {
if item.else_passed {
eprintln!("Second else for same ifdef/ifndef (line {line_number}); ignoring second else")
} else {
item.else_passed = true;
item.active = !item.active;
}
}
}
"endif" => {
if let None = stack.pop() {
eprintln!("Mismatched endif (line {line_number})");
}
}
"import" => {
let import = imports.get(arg);
if let Some(import) = import {
output.push_str(&preprocess(import, defines, imports));
} else {
eprintln!("Unkown import `{arg}` (line {line_number})");
}
}
val => {
eprintln!("Unknown preprocessor directive `{val}` (line {line_number})")
}
}
} else {
if stack.last().map(|x| x.active).unwrap_or(true) {
output.push_str(line);
output.push('\n');
}
}
}
output
}

View file

@ -1,37 +0,0 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Also licensed under MIT license, at your choice.
use handlebars::Handlebars;
use serde::Serialize;
pub struct ShaderTemplate {
handlebars: Handlebars<'static>,
}
impl ShaderTemplate {
pub fn new() -> ShaderTemplate {
let mut handlebars = Handlebars::new();
handlebars
.register_templates_directory("twgsl", concat!(env!("CARGO_MANIFEST_DIR"), "/shader"))
.unwrap();
handlebars.register_escape_fn(handlebars::no_escape);
ShaderTemplate { handlebars }
}
pub fn get_shader(&self, shader_name: &str, data: &impl Serialize) -> String {
self.handlebars.render(shader_name, data).unwrap()
}
}