From afa706bd7e670c69bf555c353ac3081b7b09e120 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Thu, 27 Oct 2022 15:27:46 +0100 Subject: [PATCH] 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. --- .vscode/settings.json | 10 + Cargo.lock | 189 ++---------------- piet-wgsl/Cargo.toml | 3 - .../shader/{backdrop.twgsl => backdrop.wgsl} | 8 +- piet-wgsl/shader/{fine.twgsl => fine.wgsl} | 6 +- .../{path_coarse.twgsl => path_coarse.wgsl} | 22 +- ...thtag_reduce.twgsl => pathtag_reduce.wgsl} | 4 +- .../{pathtag_scan.twgsl => pathtag_scan.wgsl} | 2 +- .../{config.twgsl => shared/config.wgsl} | 0 .../{pathtag.twgsl => shared/pathtag.wgsl} | 0 .../{segment.twgsl => shared/segment.wgsl} | 0 piet-wgsl/src/main.rs | 1 - piet-wgsl/src/shaders.rs | 32 +-- piet-wgsl/src/shaders/preprocess.rs | 100 +++++++++ piet-wgsl/src/template.rs | 37 ---- 15 files changed, 167 insertions(+), 247 deletions(-) create mode 100644 .vscode/settings.json rename piet-wgsl/shader/{backdrop.twgsl => backdrop.wgsl} (92%) rename piet-wgsl/shader/{fine.twgsl => fine.wgsl} (98%) rename piet-wgsl/shader/{path_coarse.twgsl => path_coarse.wgsl} (98%) rename piet-wgsl/shader/{pathtag_reduce.twgsl => pathtag_reduce.wgsl} (98%) rename piet-wgsl/shader/{pathtag_scan.twgsl => pathtag_scan.wgsl} (99%) rename piet-wgsl/shader/{config.twgsl => shared/config.wgsl} (100%) rename piet-wgsl/shader/{pathtag.twgsl => shared/pathtag.wgsl} (100%) rename piet-wgsl/shader/{segment.twgsl => shared/segment.wgsl} (100%) create mode 100644 piet-wgsl/src/shaders/preprocess.rs delete mode 100644 piet-wgsl/src/template.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e619026 --- /dev/null +++ b/.vscode/settings.json @@ -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" +} diff --git a/Cargo.lock b/Cargo.lock index bcfd743..f2669e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/piet-wgsl/Cargo.toml b/piet-wgsl/Cargo.toml index 020ba92..e7fa42d 100644 --- a/piet-wgsl/Cargo.toml +++ b/piet-wgsl/Cargo.toml @@ -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" } diff --git a/piet-wgsl/shader/backdrop.twgsl b/piet-wgsl/shader/backdrop.wgsl similarity index 92% rename from piet-wgsl/shader/backdrop.twgsl rename to piet-wgsl/shader/backdrop.wgsl index 1618ae4..75cb54c 100644 --- a/piet-wgsl/shader/backdrop.twgsl +++ b/piet-wgsl/shader/backdrop.wgsl @@ -20,7 +20,7 @@ struct Tile { segments: u32, } -{{> config}} +#import config @group(0) @binding(0) var 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; } } diff --git a/piet-wgsl/shader/fine.twgsl b/piet-wgsl/shader/fine.wgsl similarity index 98% rename from piet-wgsl/shader/fine.twgsl rename to piet-wgsl/shader/fine.wgsl index 203c320..92fdafe 100644 --- a/piet-wgsl/shader/fine.twgsl +++ b/piet-wgsl/shader/fine.wgsl @@ -20,8 +20,8 @@ struct Tile { segments: u32, } -{{> segment}} -{{> config}} +#import segment +#import config @group(0) @binding(0) var 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; diff --git a/piet-wgsl/shader/path_coarse.twgsl b/piet-wgsl/shader/path_coarse.wgsl similarity index 98% rename from piet-wgsl/shader/path_coarse.twgsl rename to piet-wgsl/shader/path_coarse.wgsl index a34d5b1..fa24952 100644 --- a/piet-wgsl/shader/path_coarse.twgsl +++ b/piet-wgsl/shader/path_coarse.wgsl @@ -14,7 +14,7 @@ // // Also licensed under MIT license, at your choice. -{{> pathtag}} +#import pathtag @group(0) @binding(0) var path_tags: array; @@ -26,18 +26,18 @@ var tag_monoids: array; @group(0) @binding(2) var path_data: array; -{{#if cubics_out}} +#ifdef cubics_out @group(0) @binding(3) var output: array>; -{{else}} -{{> config}} +#else +#import config struct Tile { backdrop: atomic, segments: atomic, } -{{> segment}} +#import segment // Should probably be uniform binding @group(0) @binding(3) @@ -48,7 +48,7 @@ var tiles: array; @group(0) @binding(5) var segments: array; -{{/if}} +#endif fn read_f32_point(ix: u32) -> vec2 { let x = bitcast(path_data[ix]); @@ -63,7 +63,7 @@ fn read_i16_point(ix: u32) -> vec2 { return vec2(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 } } diff --git a/piet-wgsl/shader/pathtag_reduce.twgsl b/piet-wgsl/shader/pathtag_reduce.wgsl similarity index 98% rename from piet-wgsl/shader/pathtag_reduce.twgsl rename to piet-wgsl/shader/pathtag_reduce.wgsl index 188f780..92bf20d 100644 --- a/piet-wgsl/shader/pathtag_reduce.twgsl +++ b/piet-wgsl/shader/pathtag_reduce.wgsl @@ -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; } -} \ No newline at end of file +} diff --git a/piet-wgsl/shader/pathtag_scan.twgsl b/piet-wgsl/shader/pathtag_scan.wgsl similarity index 99% rename from piet-wgsl/shader/pathtag_scan.twgsl rename to piet-wgsl/shader/pathtag_scan.wgsl index 5d5db59..058ce04 100644 --- a/piet-wgsl/shader/pathtag_scan.twgsl +++ b/piet-wgsl/shader/pathtag_scan.wgsl @@ -14,7 +14,7 @@ // // Also licensed under MIT license, at your choice. -{{> pathtag}} +#import pathtag @group(0) @binding(0) var path_tags: array; diff --git a/piet-wgsl/shader/config.twgsl b/piet-wgsl/shader/shared/config.wgsl similarity index 100% rename from piet-wgsl/shader/config.twgsl rename to piet-wgsl/shader/shared/config.wgsl diff --git a/piet-wgsl/shader/pathtag.twgsl b/piet-wgsl/shader/shared/pathtag.wgsl similarity index 100% rename from piet-wgsl/shader/pathtag.twgsl rename to piet-wgsl/shader/shared/pathtag.wgsl diff --git a/piet-wgsl/shader/segment.twgsl b/piet-wgsl/shader/shared/segment.wgsl similarity index 100% rename from piet-wgsl/shader/segment.twgsl rename to piet-wgsl/shader/shared/segment.wgsl diff --git a/piet-wgsl/src/main.rs b/piet-wgsl/src/main.rs index 95361cd..5cf960d 100644 --- a/piet-wgsl/src/main.rs +++ b/piet-wgsl/src/main.rs @@ -27,7 +27,6 @@ use wgpu::{Device, Queue}; mod engine; mod render; mod shaders; -mod template; mod test_scene; async fn run() -> Result<(), Box> { diff --git a/piet-wgsl/src/shaders.rs b/piet-wgsl/src/shaders.rs index 04d6cc4..64e022d 100644 --- a/piet-wgsl/src/shaders.rs +++ b/piet-wgsl/src/shaders.rs @@ -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 { - 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 HashMap { + 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, + imports: &HashMap, +) -> 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 +} diff --git a/piet-wgsl/src/template.rs b/piet-wgsl/src/template.rs deleted file mode 100644 index 3525298..0000000 --- a/piet-wgsl/src/template.rs +++ /dev/null @@ -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() - } -}