Skip to content

Commit

Permalink
Merge #2554
Browse files Browse the repository at this point in the history
2554: Add wasm32-unknown-unknown/WebGL support r=kvark a=grovesNL

Start to make a more maintainable version of my old branch from #1900 (comment). Heavily WIP but maybe somebody wants to start giving some feedback as I work through the remainder of issues.

This PR replaces gl_generator with glow (https://github.com/grovesNL/glow), a experimental crate meant to unify WebGL/OpenGL types and function signatures. Currently unsupported functions will just panic, but I think it makes sense to move some of the version logic and extension fallbacks in there too (removing them from the gl backend). The WebGL types are now just keys (and `Copy`) which fixes some of the issues I mentioned previously.

This is for the wasm32-unknown-unknown target and uses web-sys.

TODO:
- [X] ~~(major) spirv_cross wrapper on wasm32-unknown-unknown and C++ library through emscripten. For now the quad shaders are hardcoded.~~ See grovesNL/spirv_cross#92. (I'll probably leave the PR open until we work out how the integration between wasm bundles should work)
- [X] ~~Consolidate render loop somehow (see WIP in glow example https://github.com/grovesNL/glow/blob/master/examples/hello/src/main.rs#L118). I need some more ideas on how to work around the `'static` bounds for wasm32 here. The basic idea is that wasm32 has to use callbacks and we use spinloops on the native target, so we would ideally like to unify these (at least for use in examples but also simple applications). For wasm32 with the quad example I just render once and quit instead.~~ Currently winit is working through the implementation of "Event Loop 2.0" and there's been [some effort to write a stdweb backend for this](rust-windowing/winit#797), which we could later help port to wasm32-unknown-unknown. I think for now we can just keep the wasm render loop path separate in gfx examples, and things will work naturally once winit wasm32-unknown-unknown support is ready.
- [X] ~~Remove all remaining `#[cfg(not(target_arch = "wasm32"))]` wherever possible to make this more maintainable.~~ There are a few places remaining that can be removed when we move some logic into glow, like version parsing and extension checking. Some other parts like the runloop can't be addressed without winit support for wasm32-unknown-unknown or other workarounds in quad.
- [X] ~~Decide where to put things like `index.html` for examples (I've excluded it for now) and guide about how to create wasm bundle with wasm-bindgen.~~
- [X] ~~Consider how logging should work – I don't see how to redirect stdout to `console.log` so it's a bit manually at the moment. It would be really cool if things like `info!` just work automatically with wasm32-unknown-unknown.~~ We should be able to use https://github.com/iamcodemaker/console_log for the wasm backend without any major challenges.
- [X] ~~Publish glow~~ Published 0.2.0
- [x] ~~Publish updated spirv_cross~~ Published 0.14.0
- [X] ~~Add wasm-bindgen to CI~~ This has been added

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/gfx-rs/gfx/2554)
<!-- Reviewable:end -->


Co-authored-by: Joshua Groves <[email protected]>
  • Loading branch information
bors[bot] and grovesNL committed Jun 8, 2019
2 parents 416d9ff + de4075f commit 7608623
Show file tree
Hide file tree
Showing 24 changed files with 1,424 additions and 1,039 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# Compiled
/doc
target/
examples/generated-wasm

# Service
Cargo.lock
Expand Down
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ matrix:
- os: windows
rust: stable

# WebAssembly
- env: WASM=1
os: linux
rust: nightly
compiler: gcc

branches:
except:
- staging.tmp
Expand All @@ -63,6 +69,7 @@ before_install:
- if [[ $TRAVIS_OS_NAME == "windows" ]]; then choco install make; fi
- rustup self update
- rustup target add $TARGET; true
- if [[ -n "$WASM" ]]; then rustup target add wasm32-unknown-unknown --toolchain nightly && cargo install -f wasm-bindgen-cli ; fi

addons:
apt:
Expand Down Expand Up @@ -94,4 +101,5 @@ script:
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then export LIBRARY_PATH=$HOME/deps/usr/lib/x86_64-linux-gnu; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then export LD_LIBRARY_PATH=$LIBRARY_PATH; fi
- if [[ $TARGET != "aarch64-apple-ios" ]]; then make all; else make check; fi
- if [[ -n "$WASM" ]]; then make quad-wasm; fi
#- if [[ $TRAVIS_OS_NAME == "linux" ]]; then make reftests-ci; fi
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ else
endif


.PHONY: all check quad test doc reftests travis-sdl2
.PHONY: all check quad quad-wasm test doc reftests travis-sdl2

all: check test

Expand Down Expand Up @@ -72,6 +72,9 @@ reftests-ci:
quad:
cd examples && cargo run --bin quad --features ${FEATURES_HAL}

quad-wasm:
cd examples && cargo +nightly build --target wasm32-unknown-unknown --features gl --bin quad && wasm-bindgen ../target/wasm32-unknown-unknown/debug/quad.wasm --out-dir ../examples/generated-wasm --web

travis-sdl2:
#TODO
#if [ -e $(SDL2_CONFIG) ]; then exit 1; fi
Expand Down
23 changes: 20 additions & 3 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,34 @@ path = "compute/main.rs"
env_logger = "0.6"
image = "0.21"
log = "0.4"
winit = "0.19"
glsl-to-spirv = "0.1.4"
gfx-hal = { path = "../src/hal", version = "0.2" }
gfx-backend-empty = { path = "../src/backend/empty", version = "0.2" }

[dependencies.gfx-backend-gl]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
winit = "0.19"
glsl-to-spirv = "0.1.4"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies.gfx-backend-gl]
path = "../src/backend/gl"
version = "0.2"
features = ["glutin"]
optional = true

[target.'cfg(target_arch = "wasm32")'.dependencies.gfx-backend-gl]
path = "../src/backend/gl"
version = "0.2"
default-features = false
optional = true

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.32"
console_error_panic_hook = "0.1.6"
console_log = "0.1.2"

[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
version = "0.3.6"
features = [ "console", "Document", "Element", "HtmlElement", "Node", "Window" ]

[dependencies.gfx-backend-vulkan]
path = "../src/backend/vulkan"
version = "0.2"
Expand Down
33 changes: 31 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,36 @@ To run the examples, set your working directory to the examples directory and ex

For example, to run the `quad` example on the `vulkan` backend, try:

cd examples
cargo run --bin quad --features=vulkan
```bash
cd examples
cargo run --bin quad --features=vulkan
```

If you run the examples for the first time, it may take some time because all dependencies must be compiled too.

## Running `quad` with WebGL/WebAssembly

The quad example also supports WebGL and WebAssembly (`wasm32-unknown-unknown`).

First, start by compiling the quad example to WebAssembly:

```bash
cd .. # Move up to the parent directory of the gfx repository
git clone https://github.com/grovesNL/spirv_cross # Clone spirv_cross locally
cargo install wasm-bindgen-cli # Install the command line interface (CLI) for wasm-bindgen
cd examples # Set the working directory to examples (in the gfx repository)
cargo +nightly build --target wasm32-unknown-unknown --features gl --bin quad # Build quad as wasm
```

At this point, some crates may fail to build. If they do not build correctly, you may need to update your packages locally by removing your existing Cargo.lock and cleaning your target directory, or forcing certain packages to be updated (i.e. `cargo update -p package-name --precise x.y.z`).

Next, generate bindings and copy across some dependencies: an `index.html` file containing simple initialization code and a JS/wasm bundle for a dependency (spirv_cross):

```bash
wasm-bindgen ../target/wasm32-unknown-unknown/debug/quad.wasm --out-dir ../examples/generated-wasm --web
cd generated-wasm # Set the working directory to the newly created generated-wasm directory
cp ../quad/data/index.html ./ # Copy the index page
cp ../../../../spirv_cross/wasm/spirv_cross*.* ./ # Copy (or symlink) the spirv_cross bundle
```

Afterwards, run any HTTP server supporting `application/wasm` from the `generated-wasm` directory. You may need to add `application/wasm` MIME type to your web server in order for WebAssembly to be served correctly. While the web server is running, open the `index.html` file in your web browser to see the quad render.
17 changes: 17 additions & 0 deletions examples/quad/data/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
</head>
<body>
<script src="./spirv_cross_wrapper_glsl.js"></script>
<script type="module">
import init from './quad.js';
window.addEventListener("load", () => {
const module = window.sc_internal_wrapper().then(module => {
window.sc_internal = module;
init('./quad_bg.wasm');
});
});
</script>
</body>
</html>
Binary file added examples/quad/data/quad.frag.spv
Binary file not shown.
Binary file added examples/quad/data/quad.vert.spv
Binary file not shown.
44 changes: 24 additions & 20 deletions examples/quad/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
allow(dead_code, unused_extern_crates, unused_imports)
)]

extern crate env_logger;
#[cfg(feature = "dx11")]
extern crate gfx_backend_dx11 as back;
#[cfg(feature = "dx12")]
Expand All @@ -22,9 +21,15 @@ extern crate gfx_backend_metal as back;
extern crate gfx_backend_vulkan as back;
extern crate gfx_hal as hal;

extern crate glsl_to_spirv;
extern crate image;
extern crate winit;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(start)]
pub fn wasm_main() {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
main();
}

use hal::format::{AsFormat, ChannelType, Rgba8Srgb as ColorFormat, Swizzle};
use hal::pass::Subpass;
Expand All @@ -36,8 +41,7 @@ use hal::{
use hal::{DescriptorPool, Primitive, SwapchainConfig};
use hal::{Device, Instance, PhysicalDevice, Surface, Swapchain};

use std::fs;
use std::io::{Cursor, Read};
use std::io::Cursor;

#[cfg_attr(rustfmt, rustfmt_skip)]
const DIMS: Extent2D = Extent2D { width: 1024,height: 768 };
Expand Down Expand Up @@ -76,10 +80,15 @@ const COLOR_RANGE: i::SubresourceRange = i::SubresourceRange {
feature = "gl"
))]
fn main() {
#[cfg(target_arch = "wasm32")]
console_log::init_with_level(log::Level::Debug).unwrap();
#[cfg(not(target_arch = "wasm32"))]
env_logger::init();

#[cfg(not(target_arch = "wasm32"))]
let mut events_loop = winit::EventsLoop::new();

#[cfg(not(target_arch = "wasm32"))]
let wb = winit::WindowBuilder::new()
.with_min_dimensions(winit::dpi::LogicalSize::new(
1.0,
Expand All @@ -101,12 +110,15 @@ fn main() {
};
#[cfg(feature = "gl")]
let (mut adapters, mut surface) = {
#[cfg(not(target_arch = "wasm32"))]
let window = {
let builder =
back::config_context(back::glutin::ContextBuilder::new(), ColorFormat::SELF, None)
.with_vsync(true);
back::glutin::WindowedContext::new_windowed(wb, builder, &events_loop).unwrap()
};
#[cfg(target_arch = "wasm32")]
let window = { back::Window };

let surface = back::Surface::from_window(window);
let adapters = surface.enumerate_adapters();
Expand Down Expand Up @@ -520,22 +532,12 @@ fn main() {
.expect("Can't create pipeline layout");
let pipeline = {
let vs_module = {
let glsl = fs::read_to_string("quad/data/quad.vert").unwrap();
let spirv: Vec<u8> = glsl_to_spirv::compile(&glsl, glsl_to_spirv::ShaderType::Vertex)
.unwrap()
.bytes()
.map(|b| b.unwrap())
.collect();
unsafe { device.create_shader_module(&spirv) }.unwrap()
let spirv = include_bytes!("data/quad.vert.spv");
unsafe { device.create_shader_module(spirv) }.unwrap()
};
let fs_module = {
let glsl = fs::read_to_string("quad/data/quad.frag").unwrap();
let spirv: Vec<u8> = glsl_to_spirv::compile(&glsl, glsl_to_spirv::ShaderType::Fragment)
.unwrap()
.bytes()
.map(|b| b.unwrap())
.collect();
unsafe { device.create_shader_module(&spirv) }.unwrap()
let spirv = include_bytes!("./data/quad.frag.spv");
unsafe { device.create_shader_module(spirv) }.unwrap()
};

let pipeline = {
Expand Down Expand Up @@ -632,6 +634,8 @@ fn main() {
};
let mut frame: u64 = 0;
while running {
running = !cfg!(target_arch = "wasm32");
#[cfg(not(target_arch = "wasm32"))]
events_loop.poll_events(|event| {
if let winit::Event::WindowEvent { event, .. } = event {
#[allow(unused_variables)]
Expand Down
2 changes: 1 addition & 1 deletion src/backend/dx11/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ bitflags = "1"
derivative = "1"
log = { version = "0.4" }
smallvec = "0.6"
spirv_cross = { version = "0.13.0", features = ["hlsl"] }
spirv_cross = { version = "0.14.0", features = ["hlsl"] }
parking_lot = "0.7"
winapi = { version = "0.3", features = ["basetsd","d3d11", "d3d11sdklayers", "d3dcommon","d3dcompiler","dxgi1_2","dxgi1_3","dxgi1_4", "dxgi1_5", "dxgiformat","dxgitype","handleapi","minwindef","synchapi","unknwnbase","winbase","windef","winerror","winnt","winuser"] }
winit = { version = "0.19", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion src/backend/dx12/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ derivative = "1"
d3d12 = "0.1"
log = { version = "0.4" }
smallvec = "0.6"
spirv_cross = { version = "0.13.0", features = ["hlsl"] }
spirv_cross = { version = "0.14.0", features = ["hlsl"] }
winapi = { version = "0.3", features = ["basetsd","d3d12","d3d12sdklayers","d3d12shader","d3dcommon","d3dcompiler","dxgi1_2","dxgi1_3","dxgi1_4","dxgi1_6","dxgidebug","dxgiformat","dxgitype","handleapi","minwindef","synchapi","unknwnbase","winbase","windef","winerror","winnt","winuser"] }
winit = { version = "0.19", optional = true }
14 changes: 12 additions & 2 deletions src/backend/gl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,18 @@ default = ["glutin"]
[dependencies]
bitflags = "1"
log = { version = "0.4" }
gfx_gl = "0.5"
gfx-hal = { path = "../../hal", version = "0.2" }
smallvec = "0.6"
glow = { version = "0.2.0" }
spirv_cross = { version = "0.14.0", features = ["glsl"] }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
glutin = { version = "0.20", optional = true }
spirv_cross = { version = "0.13.0", features = ["glsl"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = "0.3.6"
wasm-bindgen = "0.2.39"

[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
version = "0.3.6"
features = [ "console", "Document", "Element", "HtmlCanvasElement", "WebGlBuffer", "WebGlRenderingContext", "WebGl2RenderingContext", "WebGlProgram", "WebGlSampler", "WebGlShader", "WebGlTexture", "Window" ]
Loading

0 comments on commit 7608623

Please sign in to comment.