Skip to content
This repository was archived by the owner on Jun 18, 2021. It is now read-only.

Commit 1084bbd

Browse files
committed
Add web backend
1 parent 82c8f34 commit 1084bbd

File tree

8 files changed

+1686
-509
lines changed

8 files changed

+1686
-509
lines changed

Cargo.toml

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,26 @@ default = []
2323
# Make Vulkan backend available on platforms where it is by default not, e.g. macOS
2424
vulkan = ["wgn/vulkan-portability"]
2525

26-
[dependencies.wgn]
26+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgn]
2727
package = "wgpu-native"
2828
version = "0.4"
29-
git = "https://github.com/gfx-rs/wgpu"
30-
rev = "39f17e50754aba6beeeabdd868ddfd700f9710c5"
31-
#path = "../wgpu/wgpu-native"
29+
#git = "https://github.com/gfx-rs/wgpu"
30+
#rev = "39f17e50754aba6beeeabdd868ddfd700f9710c5"
31+
path = "../wgpu/wgpu-native"
3232

33-
[dependencies.wgc]
33+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc]
3434
package = "wgpu-core"
3535
version = "0.1"
36-
git = "https://github.com/gfx-rs/wgpu"
37-
rev = "39f17e50754aba6beeeabdd868ddfd700f9710c5"
38-
#path = "../wgpu/wgpu-core"
36+
#git = "https://github.com/gfx-rs/wgpu"
37+
#rev = "39f17e50754aba6beeeabdd868ddfd700f9710c5"
38+
path = "../wgpu/wgpu-core"
3939

4040
[dependencies.wgt]
4141
package = "wgpu-types"
4242
version = "0.1"
43-
git = "https://github.com/gfx-rs/wgpu"
44-
rev = "39f17e50754aba6beeeabdd868ddfd700f9710c5"
45-
#path = "../wgpu/wgpu-types"
43+
#git = "https://github.com/gfx-rs/wgpu"
44+
#rev = "39f17e50754aba6beeeabdd868ddfd700f9710c5"
45+
path = "../wgpu/wgpu-types"
4646

4747
[dependencies]
4848
arrayvec = "0.5"
@@ -51,11 +51,97 @@ raw-window-handle = "0.3"
5151

5252
[dev-dependencies]
5353
cgmath = "0.17"
54-
env_logger = "0.7"
55-
glsl-to-spirv = "0.1"
54+
#glsl-to-spirv = "0.1"
5655
log = "0.4"
5756
png = "0.15"
58-
winit = "0.22"
57+
winit = { version = "0.22", features = ["web-sys"] }
5958
rand = "0.7.2"
6059
zerocopy = "0.2"
6160
futures = "0.3"
61+
62+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
63+
env_logger = "0.7"
64+
65+
[target.'cfg(target_arch = "wasm32")'.dependencies]
66+
wasm-bindgen = "0.2.59"
67+
web-sys = { version = "0.3.36", features = [
68+
"Document",
69+
"Navigator",
70+
"Node",
71+
"NodeList",
72+
"Gpu",
73+
"GpuAdapter",
74+
"GpuBindGroup",
75+
"GpuBindGroupBinding",
76+
"GpuBindGroupDescriptor",
77+
"GpuBindGroupLayout",
78+
"GpuBindGroupLayoutBinding",
79+
"GpuBindGroupLayoutDescriptor",
80+
"GpuBlendDescriptor",
81+
"GpuBlendFactor",
82+
"GpuBlendOperation",
83+
"GpuBindingType",
84+
"GpuBuffer",
85+
"GpuBufferBinding",
86+
"GpuBufferDescriptor",
87+
"GpuCanvasContext",
88+
"GpuColorDict",
89+
"GpuColorStateDescriptor",
90+
"GpuCommandBuffer",
91+
"GpuCommandBufferDescriptor",
92+
"GpuCommandEncoder",
93+
"GpuCommandEncoderDescriptor",
94+
"GpuCompareFunction",
95+
"GpuComputePassDescriptor",
96+
"GpuComputePassEncoder",
97+
"GpuComputePipeline",
98+
"GpuComputePipelineDescriptor",
99+
"GpuCullMode",
100+
"GpuDepthStencilStateDescriptor",
101+
"GpuDevice",
102+
"GpuDeviceDescriptor",
103+
"GpuFrontFace",
104+
"GpuIndexFormat",
105+
"GpuInputStepMode",
106+
"GpuLimits",
107+
"GpuLoadOp",
108+
"GpuPipelineLayout",
109+
"GpuPipelineLayoutDescriptor",
110+
"GpuPowerPreference",
111+
"GpuPrimitiveTopology",
112+
"GpuProgrammableStageDescriptor",
113+
"GpuQueue",
114+
"GpuRasterizationStateDescriptor",
115+
"GpuRenderPassColorAttachmentDescriptor",
116+
"GpuRenderPassDepthStencilAttachmentDescriptor",
117+
"GpuRenderPassDescriptor",
118+
"GpuRenderPassEncoder",
119+
"GpuRenderPipeline",
120+
"GpuRenderPipelineDescriptor",
121+
"GpuRequestAdapterOptions",
122+
"GpuSampler",
123+
"GpuShaderModule",
124+
"GpuShaderModuleDescriptor",
125+
"GpuStencilOperation",
126+
"GpuStencilStateFaceDescriptor",
127+
"GpuStoreOp",
128+
"GpuSwapChain",
129+
"GpuSwapChainDescriptor",
130+
"GpuTexture",
131+
"GpuTextureFormat",
132+
"GpuTextureViewDimension",
133+
"GpuTextureView",
134+
"GpuVertexAttributeDescriptor",
135+
"GpuVertexBufferLayoutDescriptor",
136+
"GpuVertexFormat",
137+
"GpuVertexStateDescriptor",
138+
"GpuVertexAttributeDescriptor",
139+
"HtmlCanvasElement",
140+
"Window",
141+
]}
142+
js-sys = "0.3.36"
143+
wasm-bindgen-futures = "0.4.9"
144+
145+
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
146+
console_error_panic_hook = "0.1.6"
147+
console_log = "0.1.2"

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ The `hello-triangle` and `hello-compute` examples show bare-bones setup without
3434
cargo run --example hello-compute 1 2 3 4
3535
```
3636

37+
#### Run Examples on the Web (`wasm32-unknown-unknown`)
38+
39+
To run examples on the `wasm32-unknown-unknown` target, first build the example as usual, then run `wasm-bindgen`:
40+
41+
```bash
42+
# Install or update wasm-bindgen-cli
43+
cargo install -f wasm-bindgen-cli
44+
# Build with the wasm target
45+
RUSTFLAGS=--cfg=web_sys_unstable_apis cargo build --example hello-triangle --target wasm32-unknown-unknown
46+
# Generate bindings in a `target/generated` directory
47+
wasm-bindgen target/wasm32-unknown-unknown/debug/examples/hello-triangle.wasm --out-dir target/generated --web
48+
```
49+
3750
## Friends
3851

3952
Shout out to the following projects that work best with wgpu-rs:

examples/hello-compute/main.rs

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
use std::{convert::TryInto as _, str::FromStr};
21
use zerocopy::AsBytes as _;
2+
use std::{convert::TryInto, str::FromStr};
33

44
async fn run() {
5-
let numbers = if std::env::args().len() == 1 {
5+
let numbers = if std::env::args().len() <= 1 {
66
let default = vec![1, 2, 3, 4];
77
log::info!("No numbers were provided, defaulting to {:?}", default);
88
default
99
} else {
1010
std::env::args()
1111
.skip(1)
12-
.map(|s| u32::from_str(&s).expect("You must pass a list of positive integers!"))
12+
.map(|s| u32::from_str(&s)
13+
.expect("You must pass a list of positive integers!"))
1314
.collect()
1415
};
1516

@@ -109,28 +110,20 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
109110
}
110111
}
111112

112-
fn main() {
113-
env_logger::init();
114-
futures::executor::block_on(run());
113+
#[cfg(target_arch = "wasm32")]
114+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen(start))]
115+
pub fn wasm_main() {
116+
console_log::init().expect("could not initialize log");
117+
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
118+
wasm_bindgen_futures::spawn_local(run());
115119
}
116120

117-
#[cfg(test)]
118-
mod tests {
119-
use super::*;
120-
121-
#[test]
122-
fn test_compute_1(){
123-
let input = vec!(1, 2, 3, 4);
124-
futures::executor::block_on(assert_execute_gpu(input, vec!(0, 1, 7, 2)));
125-
}
126-
127-
#[test]
128-
fn test_compute_2(){
129-
let input = vec!(5, 23, 10, 9);
130-
futures::executor::block_on(assert_execute_gpu(input, vec!(5, 15, 6, 19)));
131-
}
121+
#[cfg(target_arch = "wasm32")]
122+
fn main() {
123+
}
132124

133-
async fn assert_execute_gpu(input: Vec<u32>, expected: Vec<u32>){
134-
assert_eq!(execute_gpu(input).await, expected);
135-
}
125+
#[cfg(not(target_arch = "wasm32"))]
126+
fn main() {
127+
env_logger::init();
128+
futures::executor::block_on(run());
136129
}

examples/hello-triangle/main.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use winit::{
77
async fn run(event_loop: EventLoop<()>, window: Window) {
88
let size = window.inner_size();
99
let surface = wgpu::Surface::create(&window);
10-
1110
let adapter = wgpu::Adapter::request(
1211
&wgpu::RequestAdapterOptions {
1312
power_preference: wgpu::PowerPreference::Default,
@@ -35,10 +34,12 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
3534

3635
let bind_group_layout =
3736
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[] });
37+
3838
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
3939
layout: &bind_group_layout,
4040
bindings: &[],
4141
});
42+
4243
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
4344
bind_group_layouts: &[&bind_group_layout],
4445
});
@@ -62,7 +63,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
6263
}),
6364
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
6465
color_states: &[wgpu::ColorStateDescriptor {
65-
format: wgpu::TextureFormat::Bgra8UnormSrgb,
66+
format: wgpu::TextureFormat::Bgra8Unorm,
6667
color_blend: wgpu::BlendDescriptor::REPLACE,
6768
alpha_blend: wgpu::BlendDescriptor::REPLACE,
6869
write_mask: wgpu::ColorWrite::ALL,
@@ -77,7 +78,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
7778

7879
let mut sc_desc = wgpu::SwapChainDescriptor {
7980
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
80-
format: wgpu::TextureFormat::Bgra8UnormSrgb,
81+
format: wgpu::TextureFormat::Bgra8Unorm,
8182
width: size.width,
8283
height: size.height,
8384
present_mode: wgpu::PresentMode::Mailbox,
@@ -86,7 +87,8 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
8687
let mut swap_chain = device.create_swap_chain(&surface, &sc_desc);
8788

8889
event_loop.run(move |event, _, control_flow| {
89-
*control_flow = ControlFlow::Poll;
90+
// TODO: ControlFlow::Poll;
91+
*control_flow = ControlFlow::Wait;
9092
match event {
9193
Event::MainEventsCleared => window.request_redraw(),
9294
Event::WindowEvent { event: WindowEvent::Resized(size), .. } => {
@@ -126,9 +128,31 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
126128
}
127129
});
128130
}
131+
132+
#[cfg(target_arch = "wasm32")]
133+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen(start))]
134+
pub fn wasm_main() {
135+
main();
136+
}
137+
129138
fn main() {
130139
let event_loop = EventLoop::new();
131140
let window = winit::window::Window::new(&event_loop).unwrap();
132-
env_logger::init();
133-
futures::executor::block_on(run(event_loop, window));
141+
#[cfg(not(target_arch = "wasm32"))]
142+
{
143+
env_logger::init();
144+
futures::executor::block_on(run(event_loop, window));
145+
}
146+
#[cfg(target_arch = "wasm32")]
147+
{
148+
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
149+
use winit::platform::web::WindowExtWebSys;
150+
// On wasm, append the canvas to the document body
151+
web_sys::window()
152+
.and_then(|win| win.document())
153+
.and_then(|doc| doc.body())
154+
.and_then(|body| body.append_child(&web_sys::Element::from(window.canvas())).ok())
155+
.expect("couldn't append canvas to document body");
156+
wasm_bindgen_futures::spawn_local(run(event_loop, window));
157+
}
134158
}

src/backend/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,13 @@
1-
pub(crate) mod native_gpu_future;
1+
#[cfg(target_arch = "wasm32")]
2+
mod web;
3+
#[cfg(target_arch = "wasm32")]
4+
pub use web::*;
5+
6+
#[cfg(not(target_arch = "wasm32"))]
7+
mod native;
8+
9+
#[cfg(not(target_arch = "wasm32"))]
10+
pub use native::*;
11+
12+
#[cfg(not(target_arch = "wasm32"))]
13+
mod native_gpu_future;

0 commit comments

Comments
 (0)