diff --git a/.cargo/config.toml b/.cargo/config.toml index 624c0e4118..946679c088 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,10 @@ [alias] compiletest = "run --release -p compiletests --" difftest = "run --release -p difftests --" +run-wasm = ["run", "--release", "-p", "run-wasm", "--"] +[target.'cfg(target_arch = "wasm32")'] +rustflags = ["--cfg=web_sys_unstable_apis"] [target.x86_64-pc-windows-msvc] # Using Rust's LLD linker to avoid MSVC linker limitations diff --git a/Cargo.lock b/Cargo.lock index 52916d8edd..5f2bfe34cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,6 +368,18 @@ dependencies = [ "serde", ] +[[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 = "cargo-util-schemas" version = "0.8.2" @@ -738,6 +750,12 @@ dependencies = [ "syn", ] +[[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.13" @@ -859,7 +877,7 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9abf33c656a7256451ebb7d0082c5a471820c31269e49d807c538c252352186e" dependencies = [ - "indexmap", + "indexmap 2.11.0", "stable_deref_trait", ] @@ -965,6 +983,12 @@ dependencies = [ "spirv-builder", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1199,14 +1223,25 @@ dependencies = [ "wasi 0.14.4+wasi-0.2.4", ] +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator 0.2.0", + "indexmap 1.9.3", + "stable_deref_trait", +] + [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ - "fallible-iterator", - "indexmap", + "fallible-iterator 0.3.0", + "indexmap 2.11.0", "stable_deref_trait", ] @@ -1291,7 +1326,7 @@ checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ "bitflags 2.9.4", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.15.5", ] [[package]] @@ -1314,6 +1349,22 @@ dependencies = [ "num-traits", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "serde", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -1429,6 +1480,15 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +dependencies = [ + "rayon", +] + [[package]] name = "idna" version = "1.1.0" @@ -1450,6 +1510,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.11.0" @@ -1457,7 +1527,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.5", + "serde", ] [[package]] @@ -1637,6 +1708,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[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.175" @@ -1866,9 +1943,9 @@ dependencies = [ "cfg_aliases", "codespan-reporting", "half", - "hashbrown", + "hashbrown 0.15.5", "hexf-parse", - "indexmap", + "indexmap 2.11.0", "libm", "log", "num-traits", @@ -2225,8 +2302,8 @@ checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "flate2", - "hashbrown", - "indexmap", + "hashbrown 0.15.5", + "indexmap 2.11.0", "memchr", "ruzstd", ] @@ -2238,10 +2315,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "crc32fast", - "hashbrown", - "indexmap", + "hashbrown 0.15.5", + "indexmap 2.11.0", "memchr", - "wasmparser", + "wasmparser 0.236.1", ] [[package]] @@ -2348,10 +2425,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca" dependencies = [ "fixedbitset", - "hashbrown", - "indexmap", + "hashbrown 0.15.5", + "indexmap 2.11.0", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project" version = "1.1.10" @@ -2397,7 +2480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" dependencies = [ "base64", - "indexmap", + "indexmap 2.11.0", "quick-xml 0.38.3", "serde", "time", @@ -2666,6 +2749,13 @@ dependencies = [ "spirv", ] +[[package]] +name = "run-wasm" +version = "0.0.0" +dependencies = [ + "cargo-run-wasm", +] + [[package]] name = "rustc-demangle" version = "0.1.26" @@ -2686,7 +2776,7 @@ dependencies = [ "ar", "bytemuck", "either", - "indexmap", + "indexmap 2.11.0", "itertools 0.14.0", "lazy_static", "libc", @@ -3044,7 +3134,7 @@ dependencies = [ "bytemuck", "derive_more", "elsa", - "indexmap", + "indexmap 2.11.0", "internal-iterator", "itertools 0.10.5", "lazy_static", @@ -3309,8 +3399,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e9c1e705f82a260173f3eec93f2ff6d7807f23ad5a8cc2e7316a891733ea7a1" dependencies = [ - "gimli", - "hashbrown", + "gimli 0.31.1", + "hashbrown 0.15.5", "object 0.36.7", "tracing", ] @@ -3438,7 +3528,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap", + "indexmap 2.11.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -3645,6 +3735,35 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "walrus" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6481311b98508f4bc2d0abbfa5d42172e7a54b4b24d8f15e28b0dc650be0c59f" +dependencies = [ + "anyhow", + "gimli 0.26.2", + "id-arena", + "leb128", + "log", + "rayon", + "walrus-macro", + "wasm-encoder", + "wasmparser 0.214.0", +] + +[[package]] +name = "walrus-macro" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ad39ff894c43c9649fa724cdde9a6fc50b855d517ef071a93e5df82fe51d3" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3689,6 +3808,24 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-cli-support" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "861a035764c5019d0f7452ebe8bf4b291930200f78393476f72c45d5c427e8be" +dependencies = [ + "anyhow", + "base64", + "leb128", + "log", + "rustc-demangle", + "serde", + "serde_json", + "walrus", + "wasm-bindgen-shared", + "wasmparser 0.214.0", +] + [[package]] name = "wasm-bindgen-futures" version = "0.4.51" @@ -3734,6 +3871,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.214.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff694f02a8d7a50b6922b197ae03883fbf18cdb2ae9fbee7b6148456f5f44041" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmparser" +version = "0.214.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5309c1090e3e84dad0d382f42064e9933fdaedb87e468cc239f0eabea73ddcb6" +dependencies = [ + "ahash", + "bitflags 2.9.4", + "hashbrown 0.14.5", + "indexmap 2.11.0", + "semver", + "serde", +] + [[package]] name = "wasmparser" version = "0.236.1" @@ -3956,7 +4116,7 @@ dependencies = [ "cfg-if", "cfg_aliases", "document-features", - "hashbrown", + "hashbrown 0.15.5", "js-sys", "log", "naga", @@ -3987,8 +4147,8 @@ dependencies = [ "bytemuck", "cfg_aliases", "document-features", - "hashbrown", - "indexmap", + "hashbrown 0.15.5", + "indexmap 2.11.0", "log", "naga", "once_cell", @@ -4054,7 +4214,7 @@ dependencies = [ "gpu-alloc", "gpu-allocator", "gpu-descriptor", - "hashbrown", + "hashbrown 0.15.5", "js-sys", "khronos-egl", "libc", diff --git a/Cargo.toml b/Cargo.toml index f08b434a79..7cf0998410 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,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/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..6c4ce25332 --- /dev/null +++ b/examples/run-wasm/src/main.rs @@ -0,0 +1,13 @@ +fn main() { + cargo_run_wasm::run_wasm_with_css( + " + html, body, canvas { + outline: none; + overflow: clip; + margin: 0px; + width: 100%; + height: 100%; + } + ", + ); +} diff --git a/examples/runners/wgpu/Cargo.toml b/examples/runners/wgpu/Cargo.toml index 679c589cdb..9263d551ed 100644 --- a/examples/runners/wgpu/Cargo.toml +++ b/examples/runners/wgpu/Cargo.toml @@ -37,7 +37,7 @@ android_logger = "0.15.1" # to avoid specifying the dependency twice, but only applies to android builds. [target.'cfg(target_arch = "wasm32")'.dependencies] -web-sys = "0.3.60" -console_error_panic_hook = "0.1.6" +web-sys = { version = "0.3.78", features = ["Performance"] } +console_error_panic_hook = "0.1.7" console_log = "1.0.0" -wasm-bindgen-futures = "0.4.18" +wasm-bindgen-futures = "0.4.51" diff --git a/examples/runners/wgpu/src/graphics.rs b/examples/runners/wgpu/src/graphics.rs index be5323f7ea..0934197c33 100644 --- a/examples/runners/wgpu/src/graphics.rs +++ b/examples/runners/wgpu/src/graphics.rs @@ -2,6 +2,7 @@ use crate::{CompiledShaderModules, Options, maybe_watch}; use wgpu::ShaderModuleDescriptorPassthrough; use shared::ShaderConstants; +use std::slice; use winit::{ event::{ElementState, Event, MouseButton, WindowEvent}, event_loop::{ControlFlow, EventLoop}, @@ -23,6 +24,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, @@ -40,8 +88,10 @@ async fn run( window: Window, compiled_shader_modules: CompiledShaderModules, ) { - let backends = - wgpu::Backends::from_env().unwrap_or(wgpu::Backends::VULKAN | wgpu::Backends::METAL); + // FIXME(eddyb) should this just use `wgpu::Backends::PRIMARY`? + // (that also enables the DirectX 12 backend, not sure we want that one?) + let backends = wgpu::Backends::from_env() + .unwrap_or(wgpu::Backends::VULKAN | wgpu::Backends::METAL | wgpu::Backends::BROWSER_WEBGPU); let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor { backends, ..Default::default() @@ -108,6 +158,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 @@ -121,15 +177,59 @@ 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_slice(), + push_constant_ranges: push_constants_or_rossbo_emulation + .as_ref() + .map_or(&[], slice::from_ref), }); let mut render_pipeline = create_pipeline( @@ -138,12 +238,12 @@ 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, ); - 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); @@ -241,9 +341,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 }); { @@ -262,7 +363,7 @@ async fn run( ..Default::default() }); - 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; @@ -285,11 +386,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); } @@ -367,8 +480,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 { @@ -497,10 +641,11 @@ pub fn start( use winit::platform::web::WindowExtWebSys; // On wasm, append the canvas to the document body web_sys::window() - .and_then(|win| win.document()) - .and_then(|doc| doc.body()) - .and_then(|body| { - body.append_child(&web_sys::Element::from(window.canvas())) + .and_then(|dom_window| { + dom_window + .document()? + .body()? + .append_child(&web_sys::Element::from(window.canvas()?)) .ok() }) .expect("couldn't append canvas to document body"); diff --git a/examples/runners/wgpu/src/lib.rs b/examples/runners/wgpu/src/lib.rs index 880c3512fc..280dd3510c 100644 --- a/examples/runners/wgpu/src/lib.rs +++ b/examples/runners/wgpu/src/lib.rs @@ -216,33 +216,46 @@ fn maybe_watch( #[command()] pub struct Options { /// which shader to run - #[arg(short, long, default_value = "sky")] + #[cfg_attr(not(target_arch = "wasm32"), arg(short, long, default_value = "sky"))] + #[cfg_attr(target_arch = "wasm32", arg(short, long, default_value = "mouse"))] shader: RustGPUShader, #[arg(long)] force_spirv_passthru: bool, + + #[structopt(long)] + emulate_push_constants_with_storage_buffer: bool, } #[cfg_attr(target_os = "android", unsafe(export_name = "android_main"))] pub fn main( #[cfg(target_os = "android")] android_app: winit::platform::android::activity::AndroidApp, ) { - // Hack: spirv_builder builds into a custom directory if running under cargo, to not - // deadlock, and the default target directory if not. However, packages like `proc-macro2` - // have different configurations when being built here vs. when building - // rustc_codegen_spirv normally, so we *want* to build into a separate target directory, to - // not have to rebuild half the crate graph every time we run. So, pretend we're running - // under cargo by setting these environment variables. - unsafe { - std::env::set_var("OUT_DIR", env!("OUT_DIR")); - std::env::set_var("PROFILE", env!("PROFILE")); - } - - let options = Options::parse(); + let mut options = Options::parse(); #[cfg(not(any(target_os = "android", target_arch = "wasm32")))] - if options.shader == RustGPUShader::Compute { - return compute::start(&options); + { + // Hack: spirv_builder builds into a custom directory if running under cargo, to not + // deadlock, and the default target directory if not. However, packages like `proc-macro2` + // have different configurations when being built here vs. when building + // rustc_codegen_spirv normally, so we *want* to build into a separate target directory, to + // not have to rebuild half the crate graph every time we run. So, pretend we're running + // under cargo by setting these environment variables. + unsafe { + std::env::set_var("OUT_DIR", env!("OUT_DIR")); + std::env::set_var("PROFILE", env!("PROFILE")); + } + + 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(