From f2145badbbb762b4a718c81e4aeaec0412e631ec Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 23 Mar 2023 06:24:33 +0200 Subject: [PATCH 1/4] example-runner-wpgu: use `window.performance.now()` on wasm. --- examples/runners/wgpu/src/graphics.rs | 51 +++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/examples/runners/wgpu/src/graphics.rs b/examples/runners/wgpu/src/graphics.rs index 5d1cb202e5..b6851a54c0 100644 --- a/examples/runners/wgpu/src/graphics.rs +++ b/examples/runners/wgpu/src/graphics.rs @@ -22,6 +22,53 @@ mod shaders { include!(concat!(env!("OUT_DIR"), "/entry_points.rs")); } +/// Abstraction for getting timestamps even when `std::time` isn't supported. +enum PortableInstant { + #[cfg(not(target_arch = "wasm32"))] + Native(std::time::Instant), + + #[cfg(target_arch = "wasm32")] + Web { + performance_timestamp_ms: f64, + + // HACK(eddyb) cached `window().performance()` to speed up/simplify `elapsed`. + cached_window_performance: web_sys::Performance, + }, +} + +impl PortableInstant { + fn now() -> Self { + #[cfg(not(target_arch = "wasm32"))] + { + Self::Native(std::time::Instant::now()) + } + #[cfg(target_arch = "wasm32")] + { + let performance = web_sys::window() + .expect("missing window") + .performance() + .expect("missing window.performance"); + Self::Web { + performance_timestamp_ms: performance.now(), + cached_window_performance: performance, + } + } + } + + fn elapsed_secs_f32(&self) -> f32 { + match self { + #[cfg(not(target_arch = "wasm32"))] + Self::Native(instant) => instant.elapsed().as_secs_f32(), + + #[cfg(target_arch = "wasm32")] + Self::Web { + performance_timestamp_ms, + cached_window_performance, + } => ((cached_window_performance.now() - performance_timestamp_ms) / 1000.0) as f32, + } + } +} + fn mouse_button_index(button: MouseButton) -> usize { match button { MouseButton::Left => 0, @@ -137,7 +184,7 @@ async fn run( compiled_shader_modules, ); - let start = std::time::Instant::now(); + let start = PortableInstant::now(); let (mut cursor_x, mut cursor_y) = (0.0, 0.0); let (mut drag_start_x, mut drag_start_y) = (0.0, 0.0); @@ -232,7 +279,7 @@ async fn run( depth_stencil_attachment: None, }); - let time = start.elapsed().as_secs_f32(); + let time = start.elapsed_secs_f32(); for (i, press_time) in mouse_button_press_time.iter_mut().enumerate() { if (mouse_button_press_since_last_frame & (1 << i)) != 0 { *press_time = time; From 492160c6893a6a017a5e18a251958ed53bcb4ef7 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 22 Mar 2023 18:41:15 +0200 Subject: [PATCH 2/4] `run-wasm` helper (`cargo-run-wasm`) for testing the wgpu runner on the web. --- .cargo/config | 4 + Cargo.lock | 239 +++++++++++++++++++++++++++++----- Cargo.toml | 1 + deny.toml | 1 + examples/run-wasm/Cargo.toml | 12 ++ examples/run-wasm/src/main.rs | 3 + 6 files changed, 226 insertions(+), 34 deletions(-) create mode 100644 examples/run-wasm/Cargo.toml create mode 100644 examples/run-wasm/src/main.rs diff --git a/.cargo/config b/.cargo/config index 22dcbe588c..fe7fd9ebac 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,5 +1,9 @@ [alias] compiletest = "run --release -p compiletests --" +run-wasm = ["run", "--release", "-p", "run-wasm", "--"] + +[target.'cfg(target_arch = "wasm32")'] +rustflags = ["--cfg=web_sys_unstable_apis"] [target.'cfg(all())'] rustflags = [ diff --git a/Cargo.lock b/Cargo.lock index dd3223f113..6abe25e31a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,6 +201,16 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] + [[package]] name = "base64" version = "0.13.0" @@ -282,7 +292,7 @@ checksum = "5fe233b960f12f8007e3db2d136e3cb1c291bfd7396e384ee76025fc1a3932b4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -304,6 +314,18 @@ dependencies = [ "vec_map", ] +[[package]] +name = "cargo-run-wasm" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1e37cf14ef470ed74ec2a8b95e51b8623bcf6f76d24f233ebaeb209f766230" +dependencies = [ + "devserver_lib", + "pico-args", + "serde_json", + "wasm-bindgen-cli-support", +] + [[package]] name = "cc" version = "1.0.72" @@ -569,7 +591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -597,7 +619,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -610,9 +632,15 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 1.0.105", ] +[[package]] +name = "devserver_lib" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf215dbb8cb1409cca7645aaed35f9e39fb0a21855bba1ac48bc0334903bf66" + [[package]] name = "diff" version = "0.1.12" @@ -883,7 +911,7 @@ checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -1090,6 +1118,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "indexmap" version = "1.9.2" @@ -1242,6 +1276,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" version = "0.2.140" @@ -1600,7 +1640,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -1736,6 +1776,12 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project-lite" version = "0.2.7" @@ -1769,7 +1815,7 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225" dependencies = [ - "base64", + "base64 0.13.0", "indexmap", "line-wrap", "serde", @@ -1820,7 +1866,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.105", "version_check", ] @@ -1852,9 +1898,9 @@ checksum = "9926767b8b8244d7b6b64546585121d193c3d0b4856ccd656b7bfa9deb91ab6a" [[package]] name = "quote" -version = "1.0.14" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -2002,6 +2048,13 @@ dependencies = [ "spirv", ] +[[package]] +name = "run-wasm" +version = "0.0.0" +dependencies = [ + "cargo-run-wasm", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -2039,7 +2092,7 @@ dependencies = [ "smallvec", "spirt", "spirv-tools", - "syn", + "syn 1.0.105", "tempfile", ] @@ -2181,29 +2234,29 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.156" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.32", ] [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa 1.0.1", "ryu", @@ -2339,7 +2392,7 @@ dependencies = [ "proc-macro2", "quote", "spirv-std-types", - "syn", + "syn 1.0.105", ] [[package]] @@ -2411,7 +2464,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -2433,7 +2486,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.105", ] [[package]] @@ -2447,6 +2500,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tempfile" version = "3.4.0" @@ -2519,7 +2583,7 @@ checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.105", ] [[package]] @@ -2625,6 +2689,32 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "walrus" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8" +dependencies = [ + "anyhow", + "id-arena", + "leb128", + "log", + "walrus-macro", + "wasmparser", +] + +[[package]] +name = "walrus-macro" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.105", +] + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -2633,9 +2723,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2643,19 +2733,51 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.32", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-cli-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2252adf46913da7b729caf556b81cedd1335165576e6446d84618e8835d89dd" +dependencies = [ + "anyhow", + "base64 0.9.3", + "log", + "rustc-demangle", + "serde_json", + "tempfile", + "unicode-ident", + "walrus", + "wasm-bindgen-externref-xform", + "wasm-bindgen-multi-value-xform", + "wasm-bindgen-shared", + "wasm-bindgen-threads-xform", + "wasm-bindgen-wasm-conventions", + "wasm-bindgen-wasm-interpreter", +] + +[[package]] +name = "wasm-bindgen-externref-xform" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f3b73cf8fcb86da78c6649c74acef205723f57af99b9f549b2609c83fe7815" +dependencies = [ + "anyhow", + "walrus", +] + [[package]] name = "wasm-bindgen-futures" version = "0.4.34" @@ -2670,9 +2792,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2680,22 +2802,71 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.32", "wasm-bindgen-backend", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-multi-value-xform" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930dd8e8226379aebb7d512f31b9241a3c59a1801452932e5a15bebfd3b708fb" +dependencies = [ + "anyhow", + "walrus", +] + [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "wasm-bindgen-threads-xform" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759b1e9784f903a7890bcf147aa7c8c529a6318a2db05f88c054194a3e6c6d57" +dependencies = [ + "anyhow", + "walrus", + "wasm-bindgen-wasm-conventions", +] + +[[package]] +name = "wasm-bindgen-wasm-conventions" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc12bc175c837239520b8aa9dcfb68a025fcf56a718a02551a75a972711c816" +dependencies = [ + "anyhow", + "walrus", +] + +[[package]] +name = "wasm-bindgen-wasm-interpreter" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5510ab88377b4e3160a7e5d90a876d0a1da2d9b9b67495f437246714c0980f" +dependencies = [ + "anyhow", + "log", + "walrus", + "wasm-bindgen-wasm-conventions", +] + +[[package]] +name = "wasmparser" +version = "0.77.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "5fe3d5405e9ea6c1317a656d6e0820912d8b7b3607823a7596117c8f666daf6f" [[package]] name = "wayland-client" diff --git a/Cargo.toml b/Cargo.toml index 70f266ee50..d279e089cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "examples/shaders/compute-shader", "examples/shaders/mouse-shader", "examples/multibuilder", + "examples/run-wasm", "crates/rustc_codegen_spirv", "crates/rustc_codegen_spirv-types", diff --git a/deny.toml b/deny.toml index c878c007ad..f4ff6d7db2 100644 --- a/deny.toml +++ b/deny.toml @@ -36,6 +36,7 @@ skip-tree = [ { name = "example-runner-ash", version = "0.0.0", depth = 20 }, { name = "example-runner-cpu", version = "0.0.0", depth = 20 }, { name = "example-runner-wgpu", version = "0.0.0", depth = 20 }, + { name = "run-wasm", version = "0.0.0", depth = 20 }, { name = "compiletests", version = "0.0.0", depth = 20 }, { name = "compiletests-deps-helper", version = "0.0.0", depth = 20 }, ] diff --git a/examples/run-wasm/Cargo.toml b/examples/run-wasm/Cargo.toml new file mode 100644 index 0000000000..c3baa1b20d --- /dev/null +++ b/examples/run-wasm/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "run-wasm" +description = "cargo-run-wasm helper/wrapper (see cargo-run-wasm docs)" +version = "0.0.0" +publish = false +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +cargo-run-wasm = "0.3.2" diff --git a/examples/run-wasm/src/main.rs b/examples/run-wasm/src/main.rs new file mode 100644 index 0000000000..6961358d9b --- /dev/null +++ b/examples/run-wasm/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + cargo_run_wasm::run_wasm_with_css("body { margin: 0px; }"); +} From d02b56521616d1e0ff182bcc270723e4195a7798 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2023 12:46:51 +0300 Subject: [PATCH 3/4] example-runner-wpgu: force sRGB, even on wasm->WebGPU. --- examples/runners/wgpu/src/graphics.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/runners/wgpu/src/graphics.rs b/examples/runners/wgpu/src/graphics.rs index b6851a54c0..6241d41ff8 100644 --- a/examples/runners/wgpu/src/graphics.rs +++ b/examples/runners/wgpu/src/graphics.rs @@ -149,6 +149,12 @@ async fn run( ) }); + // HACK(eddyb) this (alongside `.add_srgb_suffix()` calls elsewhere) + // forces sRGB output, even on WebGPU (which handles it differently). + surface_config + .view_formats + .push(surface_config.format.add_srgb_suffix()); + // FIXME(eddyb) should this be toggled by a CLI arg? // NOTE(eddyb) VSync was disabled in the past, but without VSync, // especially for simpler shaders, you can easily hit thousands @@ -179,7 +185,7 @@ async fn run( &pipeline_layout, surface_with_config.as_ref().map_or_else( |pending| pending.preferred_format, - |(_, surface_config)| surface_config.format, + |(_, surface_config)| surface_config.format.add_srgb_suffix(), ), compiled_shader_modules, ); @@ -260,9 +266,10 @@ async fn run( return; } }; - let output_view = output - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); + let output_view = output.texture.create_view(&wgpu::TextureViewDescriptor { + format: Some(surface_config.format.add_srgb_suffix()), + ..wgpu::TextureViewDescriptor::default() + }); let mut encoder = device .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); { From dcc05bc244230deb13719671cc1ad170678cd649 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 18 Apr 2023 20:02:54 +0300 Subject: [PATCH 4/4] example-runner-wpgu: emulate push constants on wasm/WebGPU. --- examples/runners/wgpu/src/graphics.rs | 113 +++++++++++++++++++++++--- examples/runners/wgpu/src/lib.rs | 12 ++- 2 files changed, 112 insertions(+), 13 deletions(-) diff --git a/examples/runners/wgpu/src/graphics.rs b/examples/runners/wgpu/src/graphics.rs index 6241d41ff8..4785de2cb9 100644 --- a/examples/runners/wgpu/src/graphics.rs +++ b/examples/runners/wgpu/src/graphics.rs @@ -1,6 +1,7 @@ use crate::{maybe_watch, CompiledShaderModules, Options}; use shared::ShaderConstants; +use std::slice; use winit::{ event::{ElementState, Event, KeyboardInput, MouseButton, VirtualKeyCode, WindowEvent}, event_loop::{ControlFlow, EventLoop, EventLoopBuilder}, @@ -168,15 +169,60 @@ async fn run( let mut surface_with_config = initial_surface .map(|surface| auto_configure_surface(&adapter, &device, surface, window.inner_size())); - // Load the shaders from disk + // Describe the pipeline layout and build the initial pipeline. + let push_constants_or_rossbo_emulation = { + const PUSH_CONSTANTS_SIZE: usize = std::mem::size_of::(); + let stages = wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT; + if !options.emulate_push_constants_with_storage_buffer { + Ok(wgpu::PushConstantRange { + stages, + range: 0..PUSH_CONSTANTS_SIZE as u32, + }) + } else { + let buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: PUSH_CONSTANTS_SIZE as u64, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let binding0 = wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: stages, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: Some((PUSH_CONSTANTS_SIZE as u64).try_into().unwrap()), + }, + count: None, + }; + let bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[binding0], + }); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + Err((buffer, bind_group_layout, bind_group)) + } + }; let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, - bind_group_layouts: &[], - push_constant_ranges: &[wgpu::PushConstantRange { - stages: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - range: 0..std::mem::size_of::() as u32, - }], + bind_group_layouts: push_constants_or_rossbo_emulation + .as_ref() + .err() + .map(|(_, layout, _)| layout) + .as_ref() + .map_or(&[], slice::from_ref), + push_constant_ranges: push_constants_or_rossbo_emulation + .as_ref() + .map_or(&[], slice::from_ref), }); let mut render_pipeline = create_pipeline( @@ -309,11 +355,23 @@ async fn run( }; rpass.set_pipeline(render_pipeline); - rpass.set_push_constants( - wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - 0, - bytemuck::bytes_of(&push_constants), - ); + let (push_constant_offset, push_constant_bytes) = + (0, bytemuck::bytes_of(&push_constants)); + match &push_constants_or_rossbo_emulation { + Ok(_) => rpass.set_push_constants( + wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + push_constant_offset as u32, + push_constant_bytes, + ), + Err((buffer, _, bind_group)) => { + queue.write_buffer( + buffer, + push_constant_offset, + push_constant_bytes, + ); + rpass.set_bind_group(0, bind_group, &[]); + } + } rpass.draw(0..3, 0..1); } @@ -389,8 +447,39 @@ fn create_pipeline( device: &wgpu::Device, pipeline_layout: &wgpu::PipelineLayout, surface_format: wgpu::TextureFormat, - compiled_shader_modules: CompiledShaderModules, + mut compiled_shader_modules: CompiledShaderModules, ) -> wgpu::RenderPipeline { + if options.emulate_push_constants_with_storage_buffer { + let (ds, b) = (0, 0); + + for (_, shader_module_descr) in &mut compiled_shader_modules.named_spv_modules { + let w = shader_module_descr.source.to_mut(); + assert_eq!((w[0], w[4]), (0x07230203, 0)); + let mut last_op_decorate_start = None; + let mut i = 5; + while i < w.len() { + let (op, len) = (w[i] & 0xffff, w[i] >> 16); + match op { + 71 => last_op_decorate_start = Some(i), + 32 if w[i + 2] == 9 => w[i + 2] = 12, + 59 if w[i + 3] == 9 => { + w[i + 3] = 12; + let id = w[i + 2]; + let j = last_op_decorate_start.expect("no OpDecorate?"); + w.splice( + j..j, + [0x4_0047, id, 34, ds, 0x4_0047, id, 33, b, 0x3_0047, id, 24], + ); + i += 11; + } + 54 => break, + _ => {} + } + i += len as usize; + } + } + } + // FIXME(eddyb) automate this decision by default. let create_module = |module| { if options.force_spirv_passthru { diff --git a/examples/runners/wgpu/src/lib.rs b/examples/runners/wgpu/src/lib.rs index 2fe3fa7bcf..e96ddab67e 100644 --- a/examples/runners/wgpu/src/lib.rs +++ b/examples/runners/wgpu/src/lib.rs @@ -219,19 +219,29 @@ pub struct Options { #[structopt(long)] force_spirv_passthru: bool, + + #[structopt(long)] + emulate_push_constants_with_storage_buffer: bool, } #[cfg_attr(target_os = "android", export_name = "android_main")] pub fn main( #[cfg(target_os = "android")] android_app: winit::platform::android::activity::AndroidApp, ) { - let options: Options = Options::from_args(); + let mut options: Options = Options::from_args(); #[cfg(not(any(target_os = "android", target_arch = "wasm32")))] if options.shader == RustGPUShader::Compute { return compute::start(&options); } + // HACK(eddyb) force push constant emulation using (read-only) SSBOs, on + // wasm->WebGPU, as push constants are currently not supported. + // FIXME(eddyb) could push constant support be automatically detected at runtime? + if cfg!(target_arch = "wasm32") { + options.emulate_push_constants_with_storage_buffer = true; + } + graphics::start( #[cfg(target_os = "android")] android_app,