Revamp Examples to Match Website (#4765)

* Revamp examples to match website

* Small fixes

* Fix stencil_triangles on resize

* Fix

* Fix everything
This commit is contained in:
Connor Fitzgerald 2023-11-25 17:20:11 -05:00 committed by GitHub
parent ebcfd25b58
commit 7a37229630
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 553 additions and 706 deletions

View File

@ -34,45 +34,15 @@ jobs:
- name: Install wasm-bindgen - name: Install wasm-bindgen
run: cargo +stable install wasm-bindgen-cli --version=$WASM_BINDGEN_VERSION run: cargo +stable install wasm-bindgen-cli --version=$WASM_BINDGEN_VERSION
- name: Build WebGPU examples - name: Build examples
run: cargo build --release --target wasm32-unknown-unknown run: cargo xtask run-wasm --no-serve
- name: Generate JS bindings for WebGPU examples
run: |
for i in target/wasm32-unknown-unknown/release/*.wasm;
do
wasm-bindgen --no-typescript --out-dir target/generated-gpu --web "$i";
done
- name: Deploy WebGPU examples - name: Deploy WebGPU examples
uses: JamesIves/github-pages-deploy-action@v4.4.3 uses: JamesIves/github-pages-deploy-action@v4.4.3
if: github.ref == 'refs/heads/trunk' if: github.ref == 'refs/heads/trunk'
with: with:
token: ${{ secrets.WEB_DEPLOY }} token: ${{ secrets.WEB_DEPLOY }}
folder: target/generated-gpu folder: target/generated
repository-name: gfx-rs/wgpu-rs.github.io repository-name: gfx-rs/wgpu-rs.github.io
branch: master branch: master
target-folder: examples-gpu/wasm target-folder: examples/
- name: Clean the build
run: cargo clean
- name: Build WebGL examples
run: cargo build --release --target wasm32-unknown-unknown --features webgl
- name: Generate JS bindings for WebGL examples
run: |
for i in target/wasm32-unknown-unknown/release/*.wasm;
do
wasm-bindgen --no-typescript --out-dir target/generated-gl --web "$i";
done
- name: Deploy WebGL examples
uses: JamesIves/github-pages-deploy-action@v4.4.3
if: github.ref == 'refs/heads/trunk'
with:
token: ${{ secrets.WEB_DEPLOY }}
folder: target/generated-gl
repository-name: gfx-rs/wgpu-rs.github.io
branch: master
target-folder: examples-gl/wasm

37
Cargo.lock generated
View File

@ -937,10 +937,11 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]] [[package]]
name = "ddsfile" name = "ddsfile"
version = "0.5.2-unstable" version = "0.5.2"
source = "git+https://github.com/SiegeEngine/ddsfile.git?rev=9b597930edc00502391cbb1a39708dadde0fd0ff#9b597930edc00502391cbb1a39708dadde0fd0ff" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479dfe1e6737aa9e96c6ac7b69689dc4c32da8383f2c12744739d76afa8b66c4"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.1",
"byteorder", "byteorder",
"enum-primitive-derive", "enum-primitive-derive",
"num-traits", "num-traits",
@ -1260,12 +1261,9 @@ dependencies = [
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "1.9.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
dependencies = [
"instant",
]
[[package]] [[package]]
name = "fdeflate" name = "fdeflate"
@ -1445,17 +1443,6 @@ dependencies = [
"futures-util", "futures-util",
] ]
[[package]]
name = "futures-intrusive"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
dependencies = [
"futures-core",
"lock_api",
"parking_lot",
]
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.29" version = "0.3.29"
@ -1464,9 +1451,9 @@ checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
[[package]] [[package]]
name = "futures-lite" name = "futures-lite"
version = "1.13.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"futures-core", "futures-core",
@ -1474,7 +1461,6 @@ dependencies = [
"memchr", "memchr",
"parking", "parking",
"pin-project-lite", "pin-project-lite",
"waker-fn",
] ]
[[package]] [[package]]
@ -3760,12 +3746,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
[[package]]
name = "waker-fn"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.4.0" version = "2.4.0"
@ -4144,7 +4124,6 @@ dependencies = [
"env_logger", "env_logger",
"fern", "fern",
"flume", "flume",
"futures-intrusive",
"getrandom", "getrandom",
"glam", "glam",
"js-sys", "js-sys",

View File

@ -77,14 +77,12 @@ cfg_aliases = "0.1"
cfg-if = "1" cfg-if = "1"
codespan-reporting = "0.11" codespan-reporting = "0.11"
ctor = "0.2" ctor = "0.2"
# https://github.com/SiegeEngine/ddsfile/issues/15 (Updated dependencies) ddsfile = "0.5.2"
ddsfile = { version = "0.5.2-unstable", git = "https://github.com/SiegeEngine/ddsfile.git", rev = "9b597930edc00502391cbb1a39708dadde0fd0ff" }
encase = "0.6" encase = "0.6"
env_logger = "0.10" env_logger = "0.10"
fern = "0.6" fern = "0.6"
flume = "0.11" flume = "0.11"
futures-lite = "1" futures-lite = "2"
futures-intrusive = "0.5"
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
getrandom = "0.2" getrandom = "0.2"
glam = "0.24.2" glam = "0.24.2"

View File

@ -24,9 +24,7 @@ bytemuck.workspace = true
cfg-if.workspace = true cfg-if.workspace = true
ddsfile.workspace = true ddsfile.workspace = true
encase = { workspace = true, features = ["glam"] } encase = { workspace = true, features = ["glam"] }
env_logger.workspace = true
flume.workspace = true flume.workspace = true
futures-intrusive.workspace = true
getrandom.workspace = true getrandom.workspace = true
glam.workspace = true glam.workspace = true
log.workspace = true log.workspace = true
@ -42,13 +40,15 @@ winit.workspace = true
[dev-dependencies] [dev-dependencies]
wgpu-test.workspace = true wgpu-test.workspace = true
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
env_logger.workspace = true
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook.workspace = true console_error_panic_hook.workspace = true
console_log.workspace = true console_log.workspace = true
fern.workspace = true fern.workspace = true
js-sys.workspace = true js-sys.workspace = true
wasm-bindgen.workspace = true wasm-bindgen.workspace = true
wasm-bindgen-test.workspace = true
wasm-bindgen-futures.workspace = true wasm-bindgen-futures.workspace = true
hal = { workspace = true, optional = true } hal = { workspace = true, optional = true }
# We need these features in the framework examples and tests # We need these features in the framework examples and tests
@ -63,8 +63,7 @@ web-sys = { workspace = true, features = [
"HtmlImageElement", "HtmlImageElement",
"WebGl2RenderingContext", "WebGl2RenderingContext",
"CanvasRenderingContext2d", "CanvasRenderingContext2d",
# Needed for example display logic
"HtmlStyleElement",
"HtmlHeadElement",
] } ] }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test.workspace = true

View File

@ -98,21 +98,22 @@ impl EventLoopWrapper {
pub fn new(title: &str) -> Self { pub fn new(title: &str) -> Self {
let event_loop = EventLoop::new().unwrap(); let event_loop = EventLoop::new().unwrap();
let mut builder = winit::window::WindowBuilder::new(); let mut builder = winit::window::WindowBuilder::new();
builder = builder.with_title(title);
let window = Arc::new(builder.build(&event_loop).unwrap());
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
{ {
use winit::platform::web::WindowExtWebSys; use wasm_bindgen::JsCast;
let canvas = window.canvas().expect("Couldn't get canvas"); use winit::platform::web::WindowBuilderExtWebSys;
canvas.style().set_css_text("height: 100%; width: 100%;"); let canvas = web_sys::window()
// On wasm, append the canvas to the document body .unwrap()
web_sys::window() .document()
.and_then(|win| win.document()) .unwrap()
.and_then(|doc| doc.body()) .get_element_by_id("canvas")
.and_then(|body| body.append_child(&canvas).ok()) .unwrap()
.expect("couldn't append canvas to document body"); .dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap();
builder = builder.with_canvas(Some(canvas));
} }
builder = builder.with_title(title);
let window = Arc::new(builder.build(&event_loop).unwrap());
Self { event_loop, window } Self { event_loop, window }
} }

View File

@ -150,7 +150,24 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
pub fn main() { pub fn main() {
let event_loop = EventLoop::new().unwrap(); let event_loop = EventLoop::new().unwrap();
let window = winit::window::Window::new(&event_loop).unwrap(); #[allow(unused_mut)]
let mut builder = winit::window::WindowBuilder::new();
#[cfg(target_arch = "wasm32")]
{
use wasm_bindgen::JsCast;
use winit::platform::web::WindowBuilderExtWebSys;
let canvas = web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("canvas")
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap();
builder = builder.with_canvas(Some(canvas));
}
let window = builder.build(&event_loop).unwrap();
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
{ {
env_logger::init(); env_logger::init();
@ -160,15 +177,6 @@ pub fn main() {
{ {
std::panic::set_hook(Box::new(console_error_panic_hook::hook)); std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger"); console_log::init().expect("could not initialize logger");
use winit::platform::web::WindowExtWebSys;
let canvas = window.canvas().expect("Couldn't get canvas");
canvas.style().set_css_text("height: 100%; width: 100%;");
// 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(&canvas).ok())
.expect("couldn't append canvas to document body");
wasm_bindgen_futures::spawn_local(run(event_loop, window)); wasm_bindgen_futures::spawn_local(run(event_loop, window));
} }
} }

View File

@ -170,10 +170,10 @@ async fn get_data<T: bytemuck::Pod>(
); );
queue.submit(Some(command_encoder.finish())); queue.submit(Some(command_encoder.finish()));
let buffer_slice = staging_buffer.slice(..); let buffer_slice = staging_buffer.slice(..);
let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel(); let (sender, receiver) = flume::bounded(1);
buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap());
device.poll(wgpu::Maintain::Wait); device.poll(wgpu::Maintain::Wait);
receiver.receive().await.unwrap().unwrap(); receiver.recv_async().await.unwrap().unwrap();
output.copy_from_slice(bytemuck::cast_slice(&buffer_slice.get_mapped_range()[..])); output.copy_from_slice(bytemuck::cast_slice(&buffer_slice.get_mapped_range()[..]));
staging_buffer.unmap(); staging_buffer.unmap();
} }

View File

@ -1,33 +1,151 @@
const EXAMPLES: &[(&str, fn())] = &[ struct ExampleDesc {
("boids", wgpu_examples::boids::main), name: &'static str,
("bunnymark", wgpu_examples::bunnymark::main), function: fn(),
( #[allow(dead_code)] // isn't used on native
"conservative_raster", webgl: bool,
wgpu_examples::conservative_raster::main, #[allow(dead_code)] // isn't used on native
), webgpu: bool,
("cube", wgpu_examples::cube::main), }
("hello", wgpu_examples::hello::main),
("hello_compute", wgpu_examples::hello_compute::main), const EXAMPLES: &[ExampleDesc] = &[
( ExampleDesc {
"hello_synchronization", name: "boids",
wgpu_examples::hello_synchronization::main, function: wgpu_examples::boids::main,
), webgl: false, // No compute
("hello_triangle", wgpu_examples::hello_triangle::main), webgpu: true,
("hello_windows", wgpu_examples::hello_windows::main), },
("hello_workgroups", wgpu_examples::hello_workgroups::main), ExampleDesc {
("mipmap", wgpu_examples::mipmap::main), name: "bunnymark",
("msaa_line", wgpu_examples::msaa_line::main), function: wgpu_examples::bunnymark::main,
("render_to_texture", wgpu_examples::render_to_texture::main), webgl: true,
("repeated_compute", wgpu_examples::repeated_compute::main), webgpu: true,
("shadow", wgpu_examples::shadow::main), },
("skybox", wgpu_examples::skybox::main), ExampleDesc {
("srgb_blend", wgpu_examples::srgb_blend::main), name: "conservative_raster",
("stencil_triangles", wgpu_examples::stencil_triangles::main), function: wgpu_examples::conservative_raster::main,
("storage_texture", wgpu_examples::storage_texture::main), webgl: false, // No conservative raster
("texture_arrays", wgpu_examples::texture_arrays::main), webgpu: false, // No conservative raster
("timestamp_queries", wgpu_examples::timestamp_queries::main), },
("uniform_values", wgpu_examples::uniform_values::main), ExampleDesc {
("water", wgpu_examples::water::main), name: "cube",
function: wgpu_examples::cube::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "hello",
function: wgpu_examples::hello::main,
webgl: false, // No canvas for WebGL
webgpu: true,
},
ExampleDesc {
name: "hello_compute",
function: wgpu_examples::hello_compute::main,
webgl: false, // No compute
webgpu: true,
},
ExampleDesc {
name: "hello_synchronization",
function: wgpu_examples::hello_synchronization::main,
webgl: false, // No canvas for WebGL
webgpu: true,
},
ExampleDesc {
name: "hello_triangle",
function: wgpu_examples::hello_triangle::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "hello_windows",
function: wgpu_examples::hello_windows::main,
webgl: false, // Native only example
webgpu: false, // Native only example
},
ExampleDesc {
name: "hello_workgroups",
function: wgpu_examples::hello_workgroups::main,
webgl: false,
webgpu: true,
},
ExampleDesc {
name: "mipmap",
function: wgpu_examples::mipmap::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "msaa_line",
function: wgpu_examples::msaa_line::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "render_to_texture",
function: wgpu_examples::render_to_texture::main,
webgl: false, // No canvas for WebGL
webgpu: true,
},
ExampleDesc {
name: "repeated_compute",
function: wgpu_examples::repeated_compute::main,
webgl: false, // No compute
webgpu: true,
},
ExampleDesc {
name: "shadow",
function: wgpu_examples::shadow::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "skybox",
function: wgpu_examples::skybox::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "srgb_blend",
function: wgpu_examples::srgb_blend::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "stencil_triangles",
function: wgpu_examples::stencil_triangles::main,
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "storage_texture",
function: wgpu_examples::storage_texture::main,
webgl: false, // No storage textures
webgpu: true,
},
ExampleDesc {
name: "texture_arrays",
function: wgpu_examples::texture_arrays::main,
webgl: false, // No texture arrays
webgpu: false, // No texture arrays
},
ExampleDesc {
name: "timestamp_queries",
function: wgpu_examples::timestamp_queries::main,
webgl: false, // No canvas for WebGL
webgpu: false, // No timestamp queries
},
ExampleDesc {
name: "uniform_values",
function: wgpu_examples::uniform_values::main,
webgl: false, // No compute
webgpu: true,
},
ExampleDesc {
name: "water",
function: wgpu_examples::water::main,
webgl: false, // No RODS
webgpu: true,
},
]; ];
fn get_example_name() -> Option<String> { fn get_example_name() -> Option<String> {
@ -42,71 +160,70 @@ fn get_example_name() -> Option<String> {
} }
} }
fn print_unknown_example(result: Option<String>) { #[cfg(target_arch = "wasm32")]
cfg_if::cfg_if! { fn print_examples() {
if #[cfg(target_arch = "wasm32")] { // Get the document, header, and body elements.
use wasm_bindgen::JsCast; let document = web_sys::window().unwrap().document().unwrap();
use web_sys::HtmlStyleElement;
// Get the document, header, and body elements. for backend in ["webgl2", "webgpu"] {
let document = web_sys::window().unwrap().document().unwrap(); let ul = document
let head = document.head().unwrap(); .get_element_by_id(&format!("{backend}-list"))
let body = document.body().unwrap(); .unwrap();
// Add a basic style sheet to center the text and remove some margin. for example in EXAMPLES {
let style_sheet: HtmlStyleElement = document.create_element("style").unwrap().dyn_into().unwrap(); if backend == "webgl2" && !example.webgl {
style_sheet.set_inner_text("div { text-align: center; } p { margin: 4px }"); continue;
head.append_child(&style_sheet).unwrap();
// A div to provide a container and some padding.
let div = document.create_element("div").unwrap();
body.append_child(&div).unwrap();
let user_message = if let Some(example) = result {
format!("Unknown example: {example}. Please choose an example!")
} else {
String::from("Please choose an example!")
};
// A header to display the message to the user.
let header = document.create_element("h1").unwrap();
header.set_text_content(Some(&user_message));
div.append_child(&header).unwrap();
// Write a link for each example, wrapped in a paragraph.
for (name, _) in EXAMPLES {
let paragraph = document.create_element("p").unwrap();
let link = document.create_element("a").unwrap();
link.set_text_content(Some(name));
link.set_attribute("href", &format!("?example={name}")).unwrap();
paragraph.append_child(&link).unwrap();
div.append_child(&paragraph).unwrap();
} }
} else { if backend == "webgpu" && !example.webgpu {
if let Some(example) = result { continue;
println!("Unknown example: {}", example);
} else {
println!("Please specify an example as the first argument!");
} }
println!("\nAvailable Examples:"); let link = document.create_element("a").unwrap();
for (name, _) in EXAMPLES { link.set_text_content(Some(example.name));
println!("\t{name}"); link.set_attribute(
} "href",
&format!("?backend={backend}&example={}", example.name),
)
.unwrap();
link.set_class_name("example-link");
let item = document.create_element("div").unwrap();
item.append_child(&link).unwrap();
ul.append_child(&item).unwrap();
} }
} }
} }
#[cfg(target_arch = "wasm32")]
fn print_unknown_example(_result: Option<String>) {}
#[cfg(not(target_arch = "wasm32"))]
fn print_unknown_example(result: Option<String>) {
if let Some(example) = result {
println!("Unknown example: {}", example);
} else {
println!("Please specify an example as the first argument!");
}
println!("\nAvailable Examples:");
for examples in EXAMPLES {
println!("\t{}", examples.name);
}
}
fn main() { fn main() {
#[cfg(target_arch = "wasm32")]
print_examples();
let Some(example) = get_example_name() else { let Some(example) = get_example_name() else {
print_unknown_example(None); print_unknown_example(None);
return; return;
}; };
let Some((_, function)) = EXAMPLES.iter().find(|(name, _)| *name == example) else { let Some(found) = EXAMPLES.iter().find(|e| e.name == example) else {
print_unknown_example(Some(example)); print_unknown_example(Some(example));
return; return;
}; };
function(); (found.function)();
} }

View File

@ -521,7 +521,7 @@ static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTest
#[wgpu_test::gpu_test] #[wgpu_test::gpu_test]
static TEST_QUERY: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams { static TEST_QUERY: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
name: "mipmap-query", name: "mipmap-query",
image_path: "/examples/src/mipmap/screenshot-query.png", image_path: "/examples/src/mipmap/screenshot_query.png",
width: 1024, width: 1024,
height: 768, height: 768,
optional_features: QUERY_FEATURES, optional_features: QUERY_FEATURES,

View File

@ -129,10 +129,10 @@ async fn run(_path: Option<String>) {
// Time to get our image. // Time to get our image.
let buffer_slice = output_staging_buffer.slice(..); let buffer_slice = output_staging_buffer.slice(..);
let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel(); let (sender, receiver) = flume::bounded(1);
buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap());
device.poll(wgpu::Maintain::Wait); device.poll(wgpu::Maintain::Wait);
receiver.receive().await.unwrap().unwrap(); receiver.recv_async().await.unwrap().unwrap();
log::info!("Output buffer mapped."); log::info!("Output buffer mapped.");
{ {
let view = buffer_slice.get_mapped_range(); let view = buffer_slice.get_mapped_range();

View File

@ -103,7 +103,7 @@ async fn compute(local_buffer: &mut [u32], context: &WgpuContext) {
// It may also be worth noting that although on native, the usage of asynchronous // It may also be worth noting that although on native, the usage of asynchronous
// channels is wholely unnecessary, for the sake of portability to WASM (std channels // channels is wholely unnecessary, for the sake of portability to WASM (std channels
// don't work on WASM,) we'll use async channels that work on both native and WASM. // don't work on WASM,) we'll use async channels that work on both native and WASM.
let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel(); let (sender, receiver) = flume::bounded(1);
buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap());
// In order for the mapping to be completed, one of three things must happen. // In order for the mapping to be completed, one of three things must happen.
// One of those can be calling `Device::poll`. This isn't necessary on the web as devices // One of those can be calling `Device::poll`. This isn't necessary on the web as devices
@ -112,7 +112,7 @@ async fn compute(local_buffer: &mut [u32], context: &WgpuContext) {
context.device.poll(wgpu::Maintain::Wait); context.device.poll(wgpu::Maintain::Wait);
log::info!("Device polled."); log::info!("Device polled.");
// Now we await the receiving and panic if anything went wrong because we're lazy. // Now we await the receiving and panic if anything went wrong because we're lazy.
receiver.receive().await.unwrap().unwrap(); receiver.recv_async().await.unwrap().unwrap();
log::info!("Result received."); log::info!("Result received.");
// NOW we can call get_mapped_range. // NOW we can call get_mapped_range.
{ {

View File

@ -478,7 +478,7 @@ static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTest
#[wgpu_test::gpu_test] #[wgpu_test::gpu_test]
static TEST_BCN: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams { static TEST_BCN: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
name: "skybox-bc1", name: "skybox-bc1",
image_path: "/examples/src/skybox/screenshot-bc1.png", image_path: "/examples/src/skybox/screenshot_bc1.png",
width: 1024, width: 1024,
height: 768, height: 768,
optional_features: wgpu::Features::TEXTURE_COMPRESSION_BC, optional_features: wgpu::Features::TEXTURE_COMPRESSION_BC,
@ -491,7 +491,7 @@ static TEST_BCN: crate::framework::ExampleTestParams = crate::framework::Example
#[wgpu_test::gpu_test] #[wgpu_test::gpu_test]
static TEST_ETC2: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams { static TEST_ETC2: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
name: "skybox-etc2", name: "skybox-etc2",
image_path: "/examples/src/skybox/screenshot-etc2.png", image_path: "/examples/src/skybox/screenshot_etc2.png",
width: 1024, width: 1024,
height: 768, height: 768,
optional_features: wgpu::Features::TEXTURE_COMPRESSION_ETC2, optional_features: wgpu::Features::TEXTURE_COMPRESSION_ETC2,
@ -504,7 +504,7 @@ static TEST_ETC2: crate::framework::ExampleTestParams = crate::framework::Exampl
#[wgpu_test::gpu_test] #[wgpu_test::gpu_test]
static TEST_ASTC: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams { static TEST_ASTC: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
name: "skybox-astc", name: "skybox-astc",
image_path: "/examples/src/skybox/screenshot-astc.png", image_path: "/examples/src/skybox/screenshot_astc.png",
width: 1024, width: 1024,
height: 768, height: 768,
optional_features: wgpu::Features::TEXTURE_COMPRESSION_ASTC, optional_features: wgpu::Features::TEXTURE_COMPRESSION_ASTC,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

View File

@ -170,11 +170,24 @@ impl crate::framework::Example for Example {
fn resize( fn resize(
&mut self, &mut self,
_config: &wgpu::SurfaceConfiguration, config: &wgpu::SurfaceConfiguration,
_device: &wgpu::Device, device: &wgpu::Device,
_queue: &wgpu::Queue, _queue: &wgpu::Queue,
) { ) {
// empty self.stencil_buffer = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Stencil buffer"),
size: wgpu::Extent3d {
width: config.width,
height: config.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Stencil8,
view_formats: &[],
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
});
} }
fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) { fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {

View File

@ -141,10 +141,10 @@ async fn run(_path: Option<String>) {
queue.submit(Some(command_encoder.finish())); queue.submit(Some(command_encoder.finish()));
let buffer_slice = output_staging_buffer.slice(..); let buffer_slice = output_staging_buffer.slice(..);
let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel(); let (sender, receiver) = flume::bounded(1);
buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap()); buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap());
device.poll(wgpu::Maintain::Wait); device.poll(wgpu::Maintain::Wait);
receiver.receive().await.unwrap().unwrap(); receiver.recv_async().await.unwrap().unwrap();
log::info!("Output buffer mapped"); log::info!("Output buffer mapped");
{ {
let view = buffer_slice.get_mapped_range(); let view = buffer_slice.get_mapped_range();

View File

@ -347,11 +347,27 @@ async fn run(event_loop: EventLoop<()>, window: Arc<Window>) {
pub fn main() { pub fn main() {
let event_loop = EventLoop::new().unwrap(); let event_loop = EventLoop::new().unwrap();
let window = winit::window::WindowBuilder::new() #[allow(unused_mut)]
let mut builder = winit::window::WindowBuilder::new()
.with_title("Remember: Use U/D to change sample count!") .with_title("Remember: Use U/D to change sample count!")
.with_inner_size(winit::dpi::LogicalSize::new(900, 900)) .with_inner_size(winit::dpi::LogicalSize::new(900, 900));
.build(&event_loop)
.unwrap(); #[cfg(target_arch = "wasm32")]
{
use wasm_bindgen::JsCast;
use winit::platform::web::WindowBuilderExtWebSys;
let canvas = web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("canvas")
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap();
builder = builder.with_canvas(Some(canvas));
}
let window = builder.build(&event_loop).unwrap();
let window = Arc::new(window); let window = Arc::new(window);
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
{ {
@ -362,16 +378,11 @@ pub fn main() {
{ {
std::panic::set_hook(Box::new(console_error_panic_hook::hook)); std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger"); console_log::init().expect("could not initialize logger");
use winit::platform::web::WindowExtWebSys;
let canvas = window.canvas().expect("Couldn't get canvas");
canvas.style().set_css_text("height: 100%; width: 100%;");
let document = web_sys::window() let document = web_sys::window()
.and_then(|win| win.document()) .and_then(|win| win.document())
.expect("Failed to get document."); .expect("Failed to get document.");
let body = document.body().unwrap(); let body = document.body().unwrap();
body.append_child(&canvas).unwrap();
let controls_text = document let controls_text = document
.create_element("p") .create_element("p")
.expect("Failed to create controls text as element."); .expect("Failed to create controls text as element.");

122
examples/static/index.html Normal file
View File

@ -0,0 +1,122 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
<style type="text/css">
:focus {
outline: none;
}
body {
margin: 0px;
background: #fff;
font-family: "Calibri", "Arial", sans-serif;
width: 100%;
height: 100%;
}
.root {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.banner {
background: #dee;
padding: 0.5em 0;
border-bottom: 1px solid #abb;
}
.banner-prefix {
text-align: center;
}
p {
font-size: 0.8em;
padding: 0;
margin: 0.5em 0;
}
.backend-list-container {
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
.backend-list {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: center;
}
.item-list {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: center;
height: 100px;
}
.example-link {
margin-left: 7px;
margin-right: 7px;
}
.backend-name {
text-align: center;
}
.main-canvas {
margin: 0;
/* This allows the flexbox to grow to max size, this is needed for WebGPU */
flex: 1;
/* This forces CSS to ignore the width/height of the canvas, this is needed for WebGL */
contain: size;
}
</style>
</head>
<body>
<div class="root">
<div class="banner">
<div class="banner-prefix">
<p>
<a href="../index.html">
Back to home page
</a>
</p>
</div>
<div class="backend-list-container">
<div class="backend-list">
<p class="backend-name">WebGL2</p>
<div class="item-list" id="webgl2-list">
</div>
</div>
<div class="backend-list">
<p class="backend-name">WebGPU</p>
<div class="item-list" id="webgpu-list">
</div>
</div>
</div>
</div>
<canvas class="main-canvas" id="canvas"></canvas>
</div>
<script type="module">
const params = new URLSearchParams(window.location.search);
const backend = params.get("backend");
const example = params.get("example");
if (backend !== null && example !== null) {
import(`./${backend}.js`).then((module) => module.default());
} else {
window.location.assign(
`${window.location.href}?backend=webgl2&example=hello_triangle`
);
}
</script>
</body>
</html>

View File

@ -26,7 +26,6 @@ bitflags.workspace = true
bytemuck.workspace = true bytemuck.workspace = true
cfg-if.workspace = true cfg-if.workspace = true
ctor.workspace = true ctor.workspace = true
env_logger.workspace = true
futures-lite.workspace = true futures-lite.workspace = true
heck.workspace = true heck.workspace = true
libtest-mimic.workspace = true libtest-mimic.workspace = true
@ -42,6 +41,7 @@ wgpu.workspace = true
wgt = { workspace = true, features = ["replay"] } wgt = { workspace = true, features = ["replay"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
env_logger.workspace = true
nv-flip.workspace = true nv-flip.workspace = true
parking_lot = { workspace = true, features = ["deadlock_detection"] } parking_lot = { workspace = true, features = ["deadlock_detection"] }

View File

@ -11,7 +11,7 @@ async fn read_png(path: impl AsRef<Path>, width: u32, height: u32) -> Option<Vec
Ok(f) => f, Ok(f) => f,
Err(e) => { Err(e) => {
log::warn!( log::warn!(
"image comparison invalid: file io error when 3comparing {}: {}", "image comparison invalid: file io error when comparing {}: {}",
path.as_ref().display(), path.as_ref().display(),
e e
); );

422
xtask/Cargo.lock generated
View File

@ -8,57 +8,6 @@ version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "base64"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
dependencies = [
"byteorder",
"safemem",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cargo-run-wasm"
version = "0.3.2"
source = "git+https://github.com/ErichDonGubler/cargo-run-wasm?branch=expose-args#e9b502e50eaccb0f360deb36ccd0f42c6c56f9ba"
dependencies = [
"devserver_lib",
"pico-args",
"serde_json",
"wasm-bindgen-cli-support",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "devserver_lib"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edf215dbb8cb1409cca7645aaed35f9e39fb0a21855bba1ac48bc0334903bf66"
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.10.0" version = "0.10.0"
@ -68,61 +17,6 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "errno"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "id-arena"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[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.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "linux-raw-sys"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.20" version = "0.4.20"
@ -135,321 +29,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "safemem"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
[[package]]
name = "serde"
version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "serde_json"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall",
"rustix",
"windows-sys",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-segmentation"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[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.109",
]
[[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",
"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-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.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 = "5fe3d5405e9ea6c1317a656d6e0820912d8b7b3607823a7596117c8f666daf6f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "xshell" name = "xshell"
version = "0.2.5" version = "0.2.5"
@ -470,7 +49,6 @@ name = "xtask"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo-run-wasm",
"env_logger", "env_logger",
"log", "log",
"pico-args", "pico-args",

View File

@ -4,9 +4,6 @@ version = "0.1.0"
edition = "2021" edition = "2021"
publish = false publish = false
[features]
run-wasm = ["cargo-run-wasm"]
[dependencies] [dependencies]
# The dependencies in this config have no transitive dependencies. # The dependencies in this config have no transitive dependencies.
anyhow = "1.0.71" anyhow = "1.0.71"
@ -19,10 +16,4 @@ pico-args = { version = "0.5.0", features = [
] } ] }
xshell = "0.2.3" xshell = "0.2.3"
# Feature: run-wasm
# Current contents filed as a PR here:
# <https://github.com/rukai/cargo-run-wasm/pull/37>
cargo-run-wasm = { version = "0.3.2", git = "https://github.com/ErichDonGubler/cargo-run-wasm", branch = "expose-args", optional = true }
[workspace] [workspace]

View File

@ -8,6 +8,8 @@ Usage: xtask <COMMAND>
Commands: Commands:
run-wasm run-wasm
--release Build in release mode
--no-serve Just build the generated files, don't serve them
test test
--llvm-cov Run tests with LLVM code coverage using the llvm-cov tool --llvm-cov Run tests with LLVM code coverage using the llvm-cov tool
@ -49,33 +51,6 @@ pub enum Subcommand {
} }
impl Subcommand { impl Subcommand {
/// Returns the name of the subcommand as a string.
///
/// Opposite of [`Self::parse`].
pub fn to_str(&self) -> &'static str {
match self {
Self::RunWasm => "run-wasm",
Self::Test => "test",
}
}
/// Returns true if all required features are enabled for this subcommand.
pub fn required_features_enabled(&self) -> bool {
match self {
Self::RunWasm => cfg!(feature = "run-wasm"),
Self::Test => true,
}
}
/// Comma separated list of features required by this subcommand.
pub fn features(&self) -> &'static str {
match self {
Self::RunWasm => "run-wasm",
// We will never ask for the features if required_features_enabled always returns true.
Self::Test => unreachable!(),
}
}
fn parse(args: &mut Arguments) -> anyhow::Result<Subcommand> { fn parse(args: &mut Arguments) -> anyhow::Result<Subcommand> {
let subcmd = args let subcmd = args
.subcommand() .subcommand()

View File

@ -1,10 +1,9 @@
use std::process::Command;
use anyhow::Context;
use cli::Args; use cli::Args;
mod cli; mod cli;
mod run_wasm;
mod test; mod test;
mod util;
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
env_logger::builder() env_logger::builder()
@ -15,57 +14,13 @@ fn main() -> anyhow::Result<()> {
let args = Args::parse(); let args = Args::parse();
if !args.subcommand.required_features_enabled() {
let features = args.subcommand.features();
log::info!(
"Required features \"{features}\" are not enabled, recursing with features enabled"
);
let subcommand_args = args.command_args.finish();
let iter = subcommand_args
.iter()
.map(|os| os.as_os_str().to_str().unwrap());
let status = Command::new("cargo")
.args(["xtask", "--features", features, args.subcommand.to_str()])
.args(iter)
.status()
.context("Failed to execute recursive cargo xtask")?;
if status.success() {
return Ok(());
} else {
return Err(anyhow::anyhow!("subcommand failed"));
}
}
run(args) run(args)
} }
#[allow(unused_mut, unreachable_patterns)] #[allow(unused_mut, unreachable_patterns)]
fn run(mut args: Args) -> anyhow::Result<()> { fn run(mut args: Args) -> anyhow::Result<()> {
match args.subcommand { match args.subcommand {
#[cfg(feature = "run-wasm")] cli::Subcommand::RunWasm => run_wasm::run_wasm(args.command_args),
cli::Subcommand::RunWasm => {
log::info!("Running wasm example");
// Use top-level Cargo.toml instead of xtask/Cargo.toml by default
let manifest_path = args
.command_args
.value_from_str("--manifest-path")
.unwrap_or_else(|_| "../Cargo.toml".to_string());
let mut arg_vec = args.command_args.finish();
arg_vec.push("--manifest-path".into());
arg_vec.push(manifest_path.into());
let args = pico_args::Arguments::from_vec(arg_vec);
cargo_run_wasm::run_wasm_with_css_and_args(
"body { margin: 0px; }",
cargo_run_wasm::Args::from_args(args)
.map_err(anyhow::Error::msg)
.context("failed to parse arguments for `cargo-run-wasm`")?,
);
Ok(())
}
cli::Subcommand::Test => test::run_tests(args.command_args), cli::Subcommand::Test => test::run_tests(args.command_args),
_ => unreachable!(), _ => unreachable!(),
} }

97
xtask/src/run_wasm.rs Normal file
View File

@ -0,0 +1,97 @@
use anyhow::Context;
use pico_args::Arguments;
use crate::util::check_all_programs;
pub(crate) fn run_wasm(mut args: Arguments) -> Result<(), anyhow::Error> {
let no_serve = args.contains("--no-serve");
let release = args.contains("--release");
let programs_needed: &[_] = if no_serve {
&["wasm-bindgen"]
} else {
&["wasm-bindgen", "simple-http-server"]
};
check_all_programs(programs_needed)?;
let release_flag: &[_] = if release { &["--release"] } else { &[] };
let output_dir = if release { "release" } else { "debug" };
let shell = xshell::Shell::new().context("Couldn't create xshell shell")?;
shell.change_dir(String::from(env!("CARGO_MANIFEST_DIR")) + "/..");
log::info!("building webgpu examples");
let cargo_args = args.finish();
xshell::cmd!(
shell,
"cargo build --target wasm32-unknown-unknown --bin wgpu-examples {release_flag...}"
)
.args(&cargo_args)
.quiet()
.run()
.context("Failed to build webgpu examples for wasm")?;
log::info!("running wasm-bindgen on webgpu examples");
xshell::cmd!(
shell,
"wasm-bindgen target/wasm32-unknown-unknown/{output_dir}/wgpu-examples.wasm --target web --no-typescript --out-dir target/generated --out-name webgpu"
)
.quiet()
.run()
.context("Failed to run wasm-bindgen")?;
log::info!("building webgl examples");
xshell::cmd!(
shell,
"cargo build --target wasm32-unknown-unknown --bin wgpu-examples --features webgl {release_flag...}"
)
.args(&cargo_args)
.quiet()
.run()
.context("Failed to build webgl examples for wasm")?;
log::info!("running wasm-bindgen on webgl examples");
xshell::cmd!(
shell,
"wasm-bindgen target/wasm32-unknown-unknown/{output_dir}/wgpu-examples.wasm --target web --no-typescript --out-dir target/generated --out-name webgl2"
)
.quiet()
.run()
.context("Failed to run wasm-bindgen")?;
let static_files = shell
.read_dir("examples/static")
.context("Failed to enumerate static files")?;
for file in static_files {
log::info!(
"copying static file \"{}\"",
file.canonicalize().unwrap().display()
);
shell
.copy_file(&file, "target/generated")
.with_context(|| format!("Failed to copy static file \"{}\"", file.display()))?;
}
if !no_serve {
log::info!("serving on port 8000");
xshell::cmd!(
shell,
"simple-http-server target/generated -c wasm,html,js -i --coep --coop"
)
.quiet()
.run()
.context("Failed to simple-http-server")?;
}
Ok(())
}

33
xtask/src/util.rs Normal file
View File

@ -0,0 +1,33 @@
use std::{io, process::Command};
pub(crate) fn check_all_programs(programs: &[&str]) -> anyhow::Result<()> {
let mut failed = Vec::new();
for &program in programs {
let mut cmd = Command::new(program);
cmd.arg("--help");
let output = cmd.output();
match output {
Ok(_output) => {
log::info!("Checking for {program} in PATH: ✅");
}
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => {
log::error!("Checking for {program} in PATH: ❌");
failed.push(program);
}
Err(e) => {
log::error!("Checking for {program} in PATH: ❌");
panic!("Unknown IO error: {:?}", e);
}
}
}
if !failed.is_empty() {
log::error!(
"Please install them with: cargo install {}",
failed.join(" ")
);
anyhow::bail!("Missing programs in PATH");
}
Ok(())
}