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

Commit b49cc46

Browse files
committed
Add web backend
1 parent 7b15e24 commit b49cc46

File tree

8 files changed

+1685
-519
lines changed

8 files changed

+1685
-519
lines changed

Cargo.toml

+95-9
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ 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"
2929
git = "https://github.com/gfx-rs/wgpu"
3030
rev = "08e8d406c175579da5ef18c1abf4d6c00e2a9726"
3131

32-
[dependencies.wgc]
32+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc]
3333
package = "wgpu-core"
3434
version = "0.1"
3535
git = "https://github.com/gfx-rs/wgpu"
@@ -48,16 +48,102 @@ raw-window-handle = "0.3"
4848

4949
[dev-dependencies]
5050
cgmath = "0.17"
51-
env_logger = "0.7"
52-
glsl-to-spirv = "0.1"
51+
#glsl-to-spirv = "0.1"
5352
log = "0.4"
5453
png = "0.15"
55-
winit = "0.22"
54+
winit = { version = "0.22", features = ["web-sys"] }
5655
rand = "0.7.2"
5756
zerocopy = "0.2"
5857
futures = "0.3"
5958

60-
#[patch."https://github.com/gfx-rs/wgpu"]
61-
#wgc = { version = "0.1.0", package = "wgpu-core", path = "../wgpu/wgpu-core" }
62-
#wgt = { version = "0.1.0", package = "wgpu-types", path = "../wgpu/wgpu-types" }
63-
#wgn = { version = "0.4.0", package = "wgpu-native", path = "../wgpu/wgpu-native" }
59+
[patch."https://github.com/gfx-rs/wgpu"]
60+
wgc = { version = "0.1.0", package = "wgpu-core", path = "../wgpu/wgpu-core" }
61+
wgt = { version = "0.1.0", package = "wgpu-types", path = "../wgpu/wgpu-types" }
62+
wgn = { version = "0.4.0", package = "wgpu-native", path = "../wgpu/wgpu-native" }
63+
64+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
65+
env_logger = "0.7"
66+
67+
[target.'cfg(target_arch = "wasm32")'.dependencies]
68+
wasm-bindgen = "0.2.59"
69+
web-sys = { version = "0.3.36", features = [
70+
"Document",
71+
"Navigator",
72+
"Node",
73+
"NodeList",
74+
"Gpu",
75+
"GpuAdapter",
76+
"GpuBindGroup",
77+
"GpuBindGroupBinding",
78+
"GpuBindGroupDescriptor",
79+
"GpuBindGroupLayout",
80+
"GpuBindGroupLayoutBinding",
81+
"GpuBindGroupLayoutDescriptor",
82+
"GpuBlendDescriptor",
83+
"GpuBlendFactor",
84+
"GpuBlendOperation",
85+
"GpuBindingType",
86+
"GpuBuffer",
87+
"GpuBufferBinding",
88+
"GpuBufferDescriptor",
89+
"GpuCanvasContext",
90+
"GpuColorDict",
91+
"GpuColorStateDescriptor",
92+
"GpuCommandBuffer",
93+
"GpuCommandBufferDescriptor",
94+
"GpuCommandEncoder",
95+
"GpuCommandEncoderDescriptor",
96+
"GpuCompareFunction",
97+
"GpuComputePassDescriptor",
98+
"GpuComputePassEncoder",
99+
"GpuComputePipeline",
100+
"GpuComputePipelineDescriptor",
101+
"GpuCullMode",
102+
"GpuDepthStencilStateDescriptor",
103+
"GpuDevice",
104+
"GpuDeviceDescriptor",
105+
"GpuFrontFace",
106+
"GpuIndexFormat",
107+
"GpuInputStepMode",
108+
"GpuLimits",
109+
"GpuLoadOp",
110+
"GpuPipelineLayout",
111+
"GpuPipelineLayoutDescriptor",
112+
"GpuPowerPreference",
113+
"GpuPrimitiveTopology",
114+
"GpuProgrammableStageDescriptor",
115+
"GpuQueue",
116+
"GpuRasterizationStateDescriptor",
117+
"GpuRenderPassColorAttachmentDescriptor",
118+
"GpuRenderPassDepthStencilAttachmentDescriptor",
119+
"GpuRenderPassDescriptor",
120+
"GpuRenderPassEncoder",
121+
"GpuRenderPipeline",
122+
"GpuRenderPipelineDescriptor",
123+
"GpuRequestAdapterOptions",
124+
"GpuSampler",
125+
"GpuShaderModule",
126+
"GpuShaderModuleDescriptor",
127+
"GpuStencilOperation",
128+
"GpuStencilStateFaceDescriptor",
129+
"GpuStoreOp",
130+
"GpuSwapChain",
131+
"GpuSwapChainDescriptor",
132+
"GpuTexture",
133+
"GpuTextureFormat",
134+
"GpuTextureViewDimension",
135+
"GpuTextureView",
136+
"GpuVertexAttributeDescriptor",
137+
"GpuVertexBufferLayoutDescriptor",
138+
"GpuVertexFormat",
139+
"GpuVertexStateDescriptor",
140+
"GpuVertexAttributeDescriptor",
141+
"HtmlCanvasElement",
142+
"Window",
143+
]}
144+
js-sys = "0.3.36"
145+
wasm-bindgen-futures = "0.4.9"
146+
147+
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
148+
console_error_panic_hook = "0.1.6"
149+
console_log = "0.1.2"

README.md

+13
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

+21-25
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

@@ -51,6 +52,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
5152
usage: wgpu::BufferUsage::STORAGE
5253
| wgpu::BufferUsage::COPY_DST
5354
| wgpu::BufferUsage::COPY_SRC,
55+
label: std::ptr::null(), // TODO
5456
});
5557

5658
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@@ -87,7 +89,9 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
8789
},
8890
});
8991

90-
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
92+
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
93+
label: std::ptr::null(), // TODO
94+
});
9195
encoder.copy_buffer_to_buffer(&staging_buffer, 0, &storage_buffer, 0, size);
9296
{
9397
let mut cpass = encoder.begin_compute_pass();
@@ -109,28 +113,20 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
109113
}
110114
}
111115

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

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-
}
124+
#[cfg(target_arch = "wasm32")]
125+
fn main() {
126+
}
132127

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

examples/hello-triangle/main.rs

+33-7
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), .. } => {
@@ -99,7 +101,9 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
99101
.get_next_texture()
100102
.expect("Timeout when acquiring next swap chain texture");
101103
let mut encoder =
102-
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
104+
device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
105+
label: std::ptr::null(), // TODO
106+
});
103107
{
104108
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
105109
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
@@ -126,9 +130,31 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
126130
}
127131
});
128132
}
133+
134+
#[cfg(target_arch = "wasm32")]
135+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen(start))]
136+
pub fn wasm_main() {
137+
main();
138+
}
139+
129140
fn main() {
130141
let event_loop = EventLoop::new();
131142
let window = winit::window::Window::new(&event_loop).unwrap();
132-
env_logger::init();
133-
futures::executor::block_on(run(event_loop, window));
143+
#[cfg(not(target_arch = "wasm32"))]
144+
{
145+
env_logger::init();
146+
futures::executor::block_on(run(event_loop, window));
147+
}
148+
#[cfg(target_arch = "wasm32")]
149+
{
150+
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
151+
use winit::platform::web::WindowExtWebSys;
152+
// On wasm, append the canvas to the document body
153+
web_sys::window()
154+
.and_then(|win| win.document())
155+
.and_then(|doc| doc.body())
156+
.and_then(|body| body.append_child(&web_sys::Element::from(window.canvas())).ok())
157+
.expect("couldn't append canvas to document body");
158+
wasm_bindgen_futures::spawn_local(run(event_loop, window));
159+
}
134160
}

src/backend/mod.rs

+13-1
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)