Skip to content

Commit

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

This PR adds wasm32-unknown-unknown support for GLSL/ESSL compilation. Other compilers could easily be added to the Emscripten bundle, but it only includes the GLSL compiler for now.

This works by manually writing function bindings to redirect native Rust -> C++ calls to become Rust/wasm32-unknown-unknown -> C++/Emscripten calls. Rust and C++ have separate wasm memory, so we have to do some copying between both of these in order to pass arguments back and forth. There is some more information in gfx-rs/gfx#2554

There are a few parts to this PR:

- A crate to generate an Emscripten bundle from the C wrapper of SPIRV-Cross
- The generated Emscripten bundle which contains everything needed for compiling SPIR-V to GLSL/ESSL
  - This bundle could easily include MSL and HLSL compilation too, but at the moment it's not clear how best to support all combinations (other than providing one large bundle), and we ideally don't want to require Emscripten binaries to be installed as a dependency. So for now to keep it straightforward we'll just keep the bundle limited to GLSL/ESSL, unless somebody needs HLSL/MSL support in wasm.
- Some Emscripten and pointer utilities to unify access to pointers (to make Emscripten heap offsets look like pointers) so we can avoid changing the API. I think these could still be improved a lot, especially because it becomes confusing when accessing the wrong heap (Rust vs. Emscripten) but this seems to work ok for now. There is a bit of copying that could probably be made more efficient.

I've been testing this so far through an example so I can run native and wasm side-by-side to check the output of reflection/compilation:

![image](https://user-images.githubusercontent.com/2113872/53678099-aa73c780-3c77-11e9-984f-749dcb42d2ec.png)

In the future I want to expand the native test cases to improve coverage (there could still be a few calls omitted from my example) and figure out the best approach to run these tests in wasm too.

Co-authored-by: Joshua Groves <[email protected]>
  • Loading branch information
bors[bot] and grovesNL committed Mar 20, 2019
2 parents 14fd3d0 + a5a299a commit cffa068
Show file tree
Hide file tree
Showing 37 changed files with 3,024 additions and 313 deletions.
20 changes: 10 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ branches:
- staging.tmp
matrix:
include:
- os: linux
language: android
compiler: gcc
env:
- JOB="android_gcc"
android:
components:
- build-tools-26.0.1
- android-18
jdk: openjdk8
#- os: linux
# language: android
# compiler: gcc
# env:
# - JOB="android_gcc"
# android:
# components:
# - build-tools-26.0.1
# - android-18
# jdk: openjdk8
- os: osx
osx_image: xcode9
compiler: clang
Expand Down
4 changes: 2 additions & 2 deletions .travis/linux_clang.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
export CXX=clang++

cargo build --verbose --all
cargo test --verbose --all
cargo build --verbose --all --all-features
cargo test --verbose --all --all-features
2 changes: 1 addition & 1 deletion .travis/linux_clang_coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export RUSTFLAGS="-C link-dead-code"
export CXX=clang++

cargo test --verbose --no-run
cargo test --verbose --no-run --all-features
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz
tar xzf master.tar.gz
cd kcov-master
Expand Down
4 changes: 2 additions & 2 deletions .travis/linux_gcc.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
export CXX=g++-5

cargo build --verbose --all
cargo test --verbose --all
cargo build --verbose --all --all-features
cargo test --verbose --all --all-features
4 changes: 2 additions & 2 deletions .travis/macos_clang.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
export CXX=clang++
export MACOSX_DEPLOYMENT_TARGET=10.7

cargo build --verbose --all
cargo test --verbose --all
cargo build --verbose --all --all-features
cargo test --verbose --all --all-features
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
members = [
"spirv_cross",
"examples",
"bindings_generator"
"bindings_generator",
"wasm"
]
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ install:
- git submodule update --init --recursive

build_script:
- cargo build --verbose --all --target %TARGET%
- cargo build --verbose --all --target %TARGET% --all-features

test_script:
- cargo test --verbose --all --target %TARGET%
- cargo test --verbose --all --target %TARGET% --all-features

branches:
only:
Expand Down
2 changes: 1 addition & 1 deletion bindings_generator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ bindgen = "0.30.0"

[[bin]]
name = "bindings_generator"
path = "src/main.rs"
path = "src/main.rs"
61 changes: 58 additions & 3 deletions bindings_generator/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
let out_path = PathBuf::from(env::current_dir().unwrap());
let out_path = env::current_dir().unwrap();
// For native targets, include all types and functions
bindgen::Builder::default()
.header(
out_path
Expand All @@ -20,10 +20,65 @@ fn main() {
.whitelisted_type("spirv_cross::Resource")
.whitelisted_type("spirv_cross::MSLVertexAttr")
.whitelisted_type("spirv_cross::MSLResourceBinding")
// TODO: Simplify with glob
.whitelisted_type("ScInternalCompilerBase")
.whitelisted_type("ScInternalCompilerHlsl")
.whitelisted_type("ScInternalCompilerMsl")
.whitelisted_type("ScInternalCompilerGlsl")
.whitelisted_type("ScInternalResult")
.whitelisted_type("ScEntryPoint")
.whitelisted_type("ScCombinedImageSampler")
.whitelisted_type("ScHlslRootConstant")
.whitelisted_type("ScHlslCompilerOptions")
.whitelisted_type("ScMslCompilerOptions")
.whitelisted_type("ScGlslCompilerOptions")
.whitelisted_type("ScResource")
.whitelisted_type("ScResourceArray")
.whitelisted_type("ScShaderResources")
.whitelisted_type("ScSpecializationConstant")
.whitelisted_type("ScType")
.opaque_type("std::.*")
.layout_tests(false)
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("../spirv_cross/src/bindings.rs"))
.write_to_file(out_path.join("../spirv_cross/src/bindings_native.rs"))
.expect("Couldn't write bindings!");
// For wasm targets, include all types, functions will be implemented manually
bindgen::Builder::default()
.header(
out_path
.join("../spirv_cross/src/wrapper.hpp")
.to_str()
.unwrap(),
)
.clang_args(["-x", "c++", "-std=c++14"].iter())
.enable_cxx_namespaces()
.whitelisted_type("spv::.*")
.bitfield_enum(".*(Mask|Flags)")
.whitelisted_type("spirv_cross::Resource")
.whitelisted_type("spirv_cross::MSLVertexAttr")
.whitelisted_type("spirv_cross::MSLResourceBinding")
// TODO: Simplify with glob
.whitelisted_type("ScInternalCompilerBase")
.whitelisted_type("ScInternalCompilerHlsl")
.whitelisted_type("ScInternalCompilerMsl")
.whitelisted_type("ScInternalCompilerGlsl")
.whitelisted_type("ScInternalResult")
.whitelisted_type("ScEntryPoint")
.whitelisted_type("ScCombinedImageSampler")
.whitelisted_type("ScHlslRootConstant")
.whitelisted_type("ScHlslCompilerOptions")
.whitelisted_type("ScMslCompilerOptions")
.whitelisted_type("ScGlslCompilerOptions")
.whitelisted_type("ScResource")
.whitelisted_type("ScResourceArray")
.whitelisted_type("ScShaderResources")
.whitelisted_type("ScSpecializationConstant")
.whitelisted_type("ScType")
.opaque_type("std::.*")
.layout_tests(false)
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("../spirv_cross/src/bindings_wasm.rs"))
.expect("Couldn't write bindings!");
}
1 change: 1 addition & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "examples"
version = "0.1.0"
authors = ["Joshua Groves <[email protected]>"]
edition = "2018"

[dependencies]
spirv_cross = { path = "../spirv_cross" }
Expand Down
1 change: 1 addition & 0 deletions examples/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[allow(clippy::cast_ptr_alignment)]
pub fn words_from_bytes(buf: &[u8]) -> &[u32] {
unsafe {
std::slice::from_raw_parts(
Expand Down
16 changes: 15 additions & 1 deletion spirv_cross/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ repository = "https://github.com/grovesNL/spirv_cross"
readme = "../README.md"
keywords = ["spirv", "cross"]
build = "build.rs"
edition = "2018"

[build-dependencies]
[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = []
glsl = []
hlsl = []
msl = []

[target.'cfg(not(target_arch = "wasm32"))'.build-dependencies]
cc = "1.0.4"

[target.wasm32-unknown-unknown.dependencies]
wasm-bindgen = "0.2.33"
js-sys = "0.3.10"
27 changes: 20 additions & 7 deletions spirv_cross/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
extern crate cc;

fn main() {
// Prevent building SPIRV-Cross on wasm32 target
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH");
if let Ok(arch) = target_arch {
if "wasm32" == arch {
return;
}
}

let target_os = std::env::var("CARGO_CFG_TARGET_OS");
let is_macos = target_os.is_ok() && target_os.unwrap() == "macos";

Expand All @@ -22,9 +28,16 @@ fn main() {
.file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
.file("src/vendor/SPIRV-Cross/spirv_cross_parsed_ir.cpp")
.file("src/vendor/SPIRV-Cross/spirv_parser.cpp")
.file("src/vendor/SPIRV-Cross/spirv_cross_util.cpp")
.file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
.file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
.file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
.compile("spirv-cross-rust-wrapper");
.file("src/vendor/SPIRV-Cross/spirv_cross_util.cpp");

#[cfg(feature = "glsl")]
build.file("src/vendor/SPIRV-Cross/spirv_glsl.cpp");

#[cfg(feature = "hlsl")]
build.file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp");

#[cfg(feature = "msl")]
build.file("src/vendor/SPIRV-Cross/spirv_msl.cpp");

build.compile("spirv-cross-rust-wrapper");
}
Original file line number Diff line number Diff line change
Expand Up @@ -1843,7 +1843,10 @@ pub mod root {
pub fn sc_internal_compiler_set_scalar_constant(compiler:
*const root::ScInternalCompilerBase,
id: u32,
constant: u64)
constant_high_bits:
u32,
constant_low_bits:
u32)
-> root::ScInternalResult;
}
extern "C" {
Expand Down
Loading

0 comments on commit cffa068

Please sign in to comment.