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

Add web backend #193

Merged
merged 17 commits into from
Apr 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,29 @@ on:
jobs:
build:
runs-on: ${{ matrix.os }}
env:
RUSTFLAGS: ${{ matrix.RUSTFLAGS }}
strategy:
matrix:
os: [macos-10.15, ubuntu-18.04, windows-2019]
wasm: [true, false]
include:
- os: macos-10.15
CHECK_COMMAND: cargo check
TEST_COMMAND: cargo test --no-run
wasm: false
CHECK_COMMAND: cargo check --all-targets
TEST_COMMAND: cargo test --all-targets --no-run
- os: ubuntu-18.04
CHECK_COMMAND: cargo check
TEST_COMMAND: cargo test --no-run
wasm: false
CHECK_COMMAND: cargo check --all-targets
TEST_COMMAND: cargo test --all-targets --no-run
- os: windows-2019
CHECK_COMMAND: rustup default stable-msvc; cargo check
TEST_COMMAND: rustup default stable-msvc; cargo test --no-run
wasm: false
CHECK_COMMAND: rustup default stable-msvc && cargo check --all-targets
TEST_COMMAND: rustup default stable-msvc && cargo test --all-targets --no-run
- wasm: true
CHECK_COMMAND: rustup target add wasm32-unknown-unknown && cargo check --all-targets --target=wasm32-unknown-unknown
TEST_COMMAND: rustup target add wasm32-unknown-unknown && cargo test --all-targets --no-run --target=wasm32-unknown-unknown
RUSTFLAGS: --cfg=web_sys_unstable_apis
steps:
- uses: actions/checkout@v2
- name: cargo check
Expand Down
117 changes: 108 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ default = []
# Make Vulkan backend available on platforms where it is by default not, e.g. macOS
vulkan = ["wgn/vulkan-portability"]

[dependencies.wgn]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgn]
package = "wgpu-native"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
rev = "49dbe08f37f8396cff0d6672667a48116ec487f5"

[dependencies.wgc]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc]
package = "wgpu-core"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
Expand All @@ -49,12 +49,10 @@ parking_lot = "0.10"

[dev-dependencies]
cgmath = "0.17"
env_logger = "0.7"
glsl-to-spirv = "0.1"
log = "0.4"
png = "0.15"
winit = "0.22"
rand = "0.7.2"
winit = { version = "0.22.1", features = ["web-sys"] }
rand = { version = "0.7.2", features = ["wasm-bindgen"] }
bytemuck = "1"
futures = "0.3"

Expand All @@ -63,16 +61,117 @@ name="hello-compute"
path="examples/hello-compute/main.rs"
test = true

#[patch.crates-io]
[patch.crates-io]
#wgpu-types = { version = "0.5.0", path = "../wgpu/wgpu-types" }
#wgpu-core = { version = "0.5.0", path = "../wgpu/wgpu-core" }
#wgpu-native = { version = "0.5.0", path = "../wgpu/wgpu-native" }

#[patch.crates-io]
#gfx-hal = { version = "0.5.0", path = "../gfx/src/hal" }
#gfx-backend-empty = { version = "0.5.0", path = "../gfx/src/backend/empty" }
#gfx-backend-vulkan = { version = "0.5.0", path = "../gfx/src/backend/vulkan" }
#gfx-backend-dx12 = { version = "0.5.0", path = "../gfx/src/backend/dx12" }
#gfx-backend-dx11 = { version = "0.5.0", path = "../gfx/src/backend/dx11" }
#gfx-descriptor = { version = "0.1.0", path = "../gfx-extras/gfx-descriptor" }
#gfx-memory = { version = "0.1.0", path = "../gfx-extras/gfx-memory" }
wasm-bindgen = { git = "https://github.com/rustwasm/wasm-bindgen" }
wasm-bindgen-futures = { git = "https://github.com/rustwasm/wasm-bindgen" }
web-sys = { git = "https://github.com/rustwasm/wasm-bindgen" }
js-sys = { git = "https://github.com/rustwasm/wasm-bindgen" }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
env_logger = "0.7"

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.60"
web-sys = { version = "0.3.37", features = [
"Document",
"Navigator",
"Node",
"NodeList",
"Gpu",
"GpuAdapter",
"GpuAddressMode",
"GpuBindGroup",
"GpuBindGroupEntry",
"GpuBindGroupDescriptor",
"GpuBindGroupLayout",
"GpuBindGroupLayoutEntry",
"GpuBindGroupLayoutDescriptor",
"GpuBlendDescriptor",
"GpuBlendFactor",
"GpuBlendOperation",
"GpuBindingType",
"GpuBuffer",
"GpuBufferBinding",
"GpuBufferCopyView",
"GpuBufferDescriptor",
"GpuCanvasContext",
"GpuColorDict",
"GpuColorStateDescriptor",
"GpuCommandBuffer",
"GpuCommandBufferDescriptor",
"GpuCommandEncoder",
"GpuCommandEncoderDescriptor",
"GpuCompareFunction",
"GpuComputePassDescriptor",
"GpuComputePassEncoder",
"GpuComputePipeline",
"GpuComputePipelineDescriptor",
"GpuCullMode",
"GpuDepthStencilStateDescriptor",
"GpuDevice",
"GpuDeviceDescriptor",
"GpuExtent3dDict",
"GpuFilterMode",
"GpuFrontFace",
"GpuIndexFormat",
"GpuInputStepMode",
"GpuLimits",
"GpuLoadOp",
"GpuOrigin3dDict",
"GpuPipelineLayout",
"GpuPipelineLayoutDescriptor",
"GpuPowerPreference",
"GpuPrimitiveTopology",
"GpuProgrammableStageDescriptor",
"GpuQueue",
"GpuRasterizationStateDescriptor",
"GpuRenderPassColorAttachmentDescriptor",
"GpuRenderPassDepthStencilAttachmentDescriptor",
"GpuRenderPassDescriptor",
"GpuRenderPassEncoder",
"GpuRenderPipeline",
"GpuRenderPipelineDescriptor",
"GpuRequestAdapterOptions",
"GpuSampler",
"GpuSamplerDescriptor",
"GpuShaderModule",
"GpuShaderModuleDescriptor",
"GpuStencilOperation",
"GpuStencilStateFaceDescriptor",
"GpuStoreOp",
"GpuSwapChain",
"GpuSwapChainDescriptor",
"GpuTexture",
"GpuTextureAspect",
"GpuTextureComponentType",
"GpuTextureCopyView",
"GpuTextureDescriptor",
"GpuTextureDimension",
"GpuTextureFormat",
"GpuTextureViewDescriptor",
"GpuTextureViewDimension",
"GpuTextureView",
"GpuVertexAttributeDescriptor",
"GpuVertexBufferLayoutDescriptor",
"GpuVertexFormat",
"GpuVertexStateDescriptor",
"GpuVertexAttributeDescriptor",
"HtmlCanvasElement",
"Window",
]}
js-sys = "0.3.37"
wasm-bindgen-futures = "0.4.10"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
console_error_panic_hook = "0.1.6"
console_log = "0.1.2"
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ The `hello-triangle` and `hello-compute` examples show bare-bones setup without
cargo run --example hello-compute 1 2 3 4
```

#### Run Examples on the Web (`wasm32-unknown-unknown`)

To run examples on the `wasm32-unknown-unknown` target, first build the example as usual, then run `wasm-bindgen`:

```bash
# Install or update wasm-bindgen-cli
cargo install -f wasm-bindgen-cli
# Build with the wasm target
RUSTFLAGS=--cfg=web_sys_unstable_apis cargo build --target wasm32-unknown-unknown --example hello-triangle
# Generate bindings in a `target/generated` directory
wasm-bindgen --out-dir target/generated --web target/wasm32-unknown-unknown/debug/examples/hello-triangle.wasm
```

## Friends

Shout out to the following projects that work best with wgpu-rs:
Expand Down
9 changes: 6 additions & 3 deletions bors.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
status = [
"build (macos-10.15)",
"build (ubuntu-18.04)",
"build (windows-2019)",
"build (macos-10.15, true)",
"build (macos-10.15, false)",
"build (ubuntu-18.04, true)",
"build (ubuntu-18.04, false)",
"build (windows-2019, true)",
"build (windows-2019, false)",
"docs",
]

Expand Down
5 changes: 3 additions & 2 deletions examples/boids/boids.comp
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#version 450

// this shader expects NUM_PARTICLES and PARTICLES_PER_GROUP
// defines to be inserted by main.rs
// These should match the Rust constants defined in main.rs
#define NUM_PARTICLES 1500
#define PARTICLES_PER_GROUP 64

layout(local_size_x = PARTICLES_PER_GROUP) in;

Expand Down
Binary file added examples/boids/boids.comp.spv
Binary file not shown.
35 changes: 9 additions & 26 deletions examples/boids/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ extern crate rand;
#[path = "../framework.rs"]
mod framework;

use std::fmt::Write;

use wgpu::vertex_attr_array;

// number of boid particles to simulate
Expand Down Expand Up @@ -35,34 +33,19 @@ impl framework::Example for Example {
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
) -> (Self, Option<wgpu::CommandBuffer>) {
// loads comp shader source and adds shared constants as defines to comp shader

const BOIDS_SOURCE: &str = include_str!("boids.comp");
const HEADER: &str = "#version 450";
assert_eq!(BOIDS_SOURCE.lines().next(), Some(HEADER));

let mut boids_source_str = String::from(HEADER);
write!(
boids_source_str,
"\n#define NUM_PARTICLES {}\n#define PARTICLES_PER_GROUP {}",
NUM_PARTICLES, PARTICLES_PER_GROUP
)
.unwrap();
boids_source_str += &BOIDS_SOURCE[HEADER.len()..];

// load (and compile) shaders and create shader modules

let boids = framework::load_glsl(&boids_source_str, framework::ShaderStage::Compute);
let boids_module = device.create_shader_module(&boids);
let boids = include_bytes!("boids.comp.spv");
let boids_module = device
.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&boids[..])).unwrap());

let vs = framework::load_glsl(include_str!("shader.vert"), framework::ShaderStage::Vertex);
let vs_module = device.create_shader_module(&vs);
let vs = include_bytes!("shader.vert.spv");
let vs_module =
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap());

let fs = framework::load_glsl(
include_str!("shader.frag"),
framework::ShaderStage::Fragment,
);
let fs_module = device.create_shader_module(&fs);
let fs = include_bytes!("shader.frag.spv");
let fs_module =
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap());

// create compute bind layout group and compute pipeline layout

Expand Down
Binary file added examples/boids/shader.frag.spv
Binary file not shown.
Binary file added examples/boids/shader.vert.spv
Binary file not shown.
21 changes: 17 additions & 4 deletions examples/capture/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ async fn run() {
// be called in an event loop or on another thread.
device.poll(wgpu::Maintain::Wait);

// Write the buffer as a PNG
// If a file system is available, write the buffer as a PNG
let has_file_system_available = cfg!(not(target_arch = "wasm32"));
if !has_file_system_available {
return;
}

if let Ok(mapping) = buffer_future.await {
let mut png_encoder = png::Encoder::new(File::create("red.png").unwrap(), size, size);
png_encoder.set_depth(png::BitDepth::Eight);
Expand All @@ -110,7 +115,15 @@ async fn run() {
}

fn main() {
env_logger::init();

futures::executor::block_on(run());
#[cfg(not(target_arch = "wasm32"))]
{
env_logger::init();
futures::executor::block_on(run());
}
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
wasm_bindgen_futures::spawn_local(run());
}
}
16 changes: 7 additions & 9 deletions examples/cube/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl framework::Example for Example {
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
lod_min_clamp: -100.0,
lod_min_clamp: 0.0,
lod_max_clamp: 100.0,
compare: wgpu::CompareFunction::Undefined,
});
Expand Down Expand Up @@ -241,14 +241,12 @@ impl framework::Example for Example {
});

// Create the render pipeline
let vs_bytes =
framework::load_glsl(include_str!("shader.vert"), framework::ShaderStage::Vertex);
let fs_bytes = framework::load_glsl(
include_str!("shader.frag"),
framework::ShaderStage::Fragment,
);
let vs_module = device.create_shader_module(&vs_bytes);
let fs_module = device.create_shader_module(&fs_bytes);
let vs_bytes = include_bytes!("shader.vert.spv");
let fs_bytes = include_bytes!("shader.frag.spv");
let vs_module = device
.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap());
let fs_module = device
.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap());

let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
layout: &pipeline_layout,
Expand Down
2 changes: 1 addition & 1 deletion examples/cube/shader.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ layout(set = 0, binding = 2) uniform sampler s_Color;
void main() {
vec4 tex = texture(sampler2D(t_Color, s_Color), v_TexCoord);
float mag = length(v_TexCoord-vec2(0.5));
o_Target = mix(tex, vec4(0.0), mag*mag);
o_Target = vec4(mix(tex.xyz, vec3(0.0), mag*mag), 1.0);
}
Binary file added examples/cube/shader.frag.spv
Binary file not shown.
Binary file added examples/cube/shader.vert.spv
Binary file not shown.
20 changes: 15 additions & 5 deletions examples/describe/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
/// This example shows how to describe the adapter in use.
fn main() {
env_logger::init();
futures::executor::block_on(run());
}

async fn run() {
let adapter = wgpu::Adapter::request(
&wgpu::RequestAdapterOptions {
Expand All @@ -15,5 +10,20 @@ async fn run() {
.await
.unwrap();

#[cfg(not(target_arch = "wasm32"))]
println!("{:?}", adapter.get_info())
}

fn main() {
#[cfg(not(target_arch = "wasm32"))]
{
env_logger::init();
futures::executor::block_on(run());
}
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
wasm_bindgen_futures::spawn_local(run());
}
}
Loading