Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full (experimental) WebGPU support #1965

Merged
merged 11 commits into from
Apr 26, 2023
7 changes: 7 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ run-wasm = "run --release --package run_wasm --"
# Some of our build.rs files only run if this is set,
# so that we don't run them on cargo publish or on users machines.
IS_IN_RERUN_WORKSPACE = "yes"

# web_sys_unstable_apis is required to enable the web_sys clipboard API which egui_web uses,
# https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
# as well as WebGPU apis.
# https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
[target.wasm32-unknown-unknown]
rustflags = ["--cfg=web_sys_unstable_apis"]
31 changes: 31 additions & 0 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,37 @@ pip install ./rerun_py
> Note: If you are unable to upgrade pip to version `>=21.3`, you need to pass `--use-feature=in-tree-build` to the `pip install` command.


## Building for the Web

If you want to build a standalone rerun executable that contains the web-viewer and a websocket server,
you need to ensure the `web_viewer` feature flag is set:
```
cargo build -p rerun --features web_viewer
```

Rerun uses a standalone tool to build the web-viewer. You can invoke it directly as well:
```
cargo run -p re_build_web_viewer -- --release
```


### Building with WebGPU support

By default all web builds are using WebGL for rendering.
However, Rerun can also build with experimental WebGPU support!
Note that currently we can't build wasm files that support both WebGPU and WebGL.

To build a standalone Rerun executable with a WebGPU web viewer, you need to set
the `RERUN_BUILD_WEBGPU` env variable and enable the `web_viewer` feature:
```
RERUN_BUILD_WEBGPU=1 cargo build -p rerun --features web_viewer
```

And for building a WebGPU based web-viewer without the server:
```
cargo run -p re_build_web_viewer -- --release --webgpu
```

## Improving compile times

As of today, we link everything statically in both debug and release builds, which makes custom linkers and split debuginfo the two most impactful tools we have at our disposal in order to improve compile times.
Expand Down
19 changes: 10 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 12 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ version = "0.6.0-alpha.0"
# This is because we treat alpha-releases as incompatible, but semver doesn't.
# In particular: if we compile rerun 0.3.0-alpha.0 we only want it to use
# re_log_types 0.3.0-alpha.0, NOT 0.3.0-alpha.4 even though it is newer and semver-compatible.
re_sdk_comms = { path = "crates/re_sdk_comms", version = "=0.6.0-alpha.0" }
re_analytics = { path = "crates/re_analytics", version = "=0.6.0-alpha.0" }
re_arrow_store = { path = "crates/re_arrow_store", version = "=0.6.0-alpha.0" }
re_build_build_info = { path = "crates/re_build_build_info", version = "=0.6.0-alpha.0" }
Expand All @@ -37,15 +38,14 @@ re_log_encoding = { path = "crates/re_log_encoding", version = "=0.6.0-alpha.0"
re_log_types = { path = "crates/re_log_types", version = "=0.6.0-alpha.0" }
re_memory = { path = "crates/re_memory", version = "=0.6.0-alpha.0" }
re_query = { path = "crates/re_query", version = "=0.6.0-alpha.0" }
re_renderer = { path = "crates/re_renderer", version = "=0.6.0-alpha.0" }
re_renderer = { path = "crates/re_renderer", version = "=0.6.0-alpha.0", default-features = false }
re_sdk = { path = "crates/re_sdk", version = "=0.6.0-alpha.0" }
re_sdk_comms = { path = "crates/re_sdk_comms", version = "=0.6.0-alpha.0" }
re_smart_channel = { path = "crates/re_smart_channel", version = "=0.6.0-alpha.0" }
re_string_interner = { path = "crates/re_string_interner", version = "=0.6.0-alpha.0" }
re_tensor_ops = { path = "crates/re_tensor_ops", version = "=0.6.0-alpha.0" }
re_tuid = { path = "crates/re_tuid", version = "=0.6.0-alpha.0" }
re_ui = { path = "crates/re_ui", version = "=0.6.0-alpha.0" }
re_viewer = { path = "crates/re_viewer", version = "=0.6.0-alpha.0" }
re_viewer = { path = "crates/re_viewer", version = "=0.6.0-alpha.0", default-features = false }
re_web_viewer_server = { path = "crates/re_web_viewer_server", version = "=0.6.0-alpha.0" }
re_ws_comms = { path = "crates/re_ws_comms", version = "=0.6.0-alpha.0" }
rerun = { path = "crates/rerun", version = "=0.6.0-alpha.0" }
Expand Down Expand Up @@ -85,8 +85,8 @@ thiserror = "1.0"
time = { version = "0.3", features = ["wasm-bindgen"] }
tinyvec = { version = "1.6", features = ["alloc", "rustc_1_55"] }
tokio = "1.24"
wgpu = { version = "0.16", default-features = false }
wgpu-core = { version = "0.16", default-features = false }
wgpu = { version = "0.16" }
wgpu-core = { version = "0.16" }


[profile.dev]
Expand All @@ -113,13 +113,13 @@ debug = true
# ALWAYS document what PR the commit hash is part of, or when it was merged into the upstream trunk.

# TODO(andreas/emilk): Update to a stable egui version
# wgpu 0.16 support.
ecolor = { git = "https://github.com/emilk/egui", rev = "0e6d69d" }
eframe = { git = "https://github.com/emilk/egui", rev = "0e6d69d" }
egui = { git = "https://github.com/emilk/egui", rev = "0e6d69d" }
egui-wgpu = { git = "https://github.com/emilk/egui", rev = "0e6d69d" }
egui_extras = { git = "https://github.com/emilk/egui", rev = "0e6d69d" }
emath = { git = "https://github.com/emilk/egui", rev = "0e6d69d" }
# wgpu 0.16 support, device configuration dependent on adapter
ecolor = { git = "https://github.com/emilk/egui", rev = "f76eefb98d23cbf71989255aafe75a07d343f6ed" }
eframe = { git = "https://github.com/emilk/egui", rev = "f76eefb98d23cbf71989255aafe75a07d343f6ed" }
egui = { git = "https://github.com/emilk/egui", rev = "f76eefb98d23cbf71989255aafe75a07d343f6ed" }
egui-wgpu = { git = "https://github.com/emilk/egui", rev = "f76eefb98d23cbf71989255aafe75a07d343f6ed" }
egui_extras = { git = "https://github.com/emilk/egui", rev = "f76eefb98d23cbf71989255aafe75a07d343f6ed" }
emath = { git = "https://github.com/emilk/egui", rev = "f76eefb98d23cbf71989255aafe75a07d343f6ed" }

# TODO(andreas): Either work around this issue in wgpu-egui (never discard command buffers) or wait for wgpu patch release.
# Fix for command buffer dropping crash https://github.com/gfx-rs/wgpu/pull/3726
Expand Down
9 changes: 8 additions & 1 deletion crates/re_build_web_viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn target_directory() -> Utf8PathBuf {
}

/// Build `re_viewer` as Wasm, generate .js bindings for it, and place it all into the `./web_viewer` folder.
pub fn build(release: bool) {
pub fn build(release: bool, webgpu: bool) {
eprintln!("Building web viewer wasm…");
eprintln!("We assume you've already run ./scripts/setup_web.sh");

Expand Down Expand Up @@ -63,14 +63,21 @@ pub fn build(release: bool) {
"wasm32-unknown-unknown",
"--target-dir",
target_wasm_dir.as_str(),
"--no-default-features",
]);
if webgpu {
cmd.arg("--features=analytics");
} else {
cmd.arg("--features=analytics,webgl");
}
if release {
cmd.arg("--release");
}

// This is required to enable the web_sys clipboard API which egui_web uses
// https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
// https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html
// Furthermore, it's necessary for unstable WebGPU apis to work.
cmd.env("RUSTFLAGS", "--cfg=web_sys_unstable_apis");

// When executing this script from a Rust build script, do _not_, under any circumstances,
Expand Down
7 changes: 6 additions & 1 deletion crates/re_build_web_viewer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::process::ExitCode;

fn main() -> ExitCode {
let mut release = None;
let mut webgpu = false;

for arg in std::env::args().skip(1) {
match arg.as_str() {
Expand All @@ -17,6 +18,9 @@ fn main() -> ExitCode {
assert!(release.is_none(), "Can't set both --release and --debug");
release = Some(true);
}
"--webgpu" => {
webgpu = true;
}
_ => {
print_help();
return ExitCode::FAILURE;
Expand All @@ -29,7 +33,7 @@ fn main() -> ExitCode {
return ExitCode::FAILURE;
};

re_build_web_viewer::build(release);
re_build_web_viewer::build(release, webgpu);
ExitCode::SUCCESS
}

Expand All @@ -41,6 +45,7 @@ fn print_help() {
--debug: Build a debug binary
--release: Compile for release, and run wasm-opt.
NOTE: --release also removes debug symbols which are otherwise useful for in-browser profiling.
--webgpu: Enable WebGPU support (experimental). If not set the viewer will use WebGL instead.
"
);
}
16 changes: 5 additions & 11 deletions crates/re_renderer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]


[features]
default = ["arrow", "import-obj", "import-gltf"]
default = ["import-obj", "import-gltf"]

## Support for Arrow datatypes for end-to-end zero-copy.
arrow = ["dep:arrow2"]
Expand All @@ -38,6 +38,8 @@ import-gltf = ["dep:gltf"]
## Enable (de)serialization using serde.
serde = ["dep:serde"]

## Render using webgl instead of webgpu on wasm builds.
webgl = ["wgpu/webgl"]

[dependencies]
re_error.workspace = true
Expand All @@ -63,6 +65,7 @@ smallvec.workspace = true
static_assertions = "1.1"
thiserror.workspace = true
type-map = "0.5"
wgpu.workspace = true

# optional
arrow2 = { workspace = true, optional = true }
Expand All @@ -75,17 +78,8 @@ tobj = { version = "3.2", optional = true }
crossbeam = "0.8"
notify = "5.0"
puffin.workspace = true
wgpu = { workspace = true, default-features = false, features = ["wgsl"] }
wgpu-core.workspace = true

# wasm
[target.'cfg(target_arch = "wasm32")'.dependencies]
wgpu = { workspace = true, default-features = false, features = [
"webgl",
"wgsl",
] }


# For examples:
[dev-dependencies]
image = { workspace = true, default-features = false, features = ["png"] }
Expand All @@ -109,7 +103,7 @@ console_error_panic_hook = "0.1.6"
# required to make rand work on wasm, see https://github.com/rust-random/rand#wasm-support
getrandom = { version = "0.2", features = ["js"] }
wasm-bindgen-futures = "0.4.33"
web-sys = { version = "0.3.60", features = [
web-sys = { version = "0.3.61", features = [
"Location",
"Blob",
"RequestInit",
Expand Down
3 changes: 2 additions & 1 deletion crates/re_renderer/examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl<E: Example + 'static> Application<E> {
.await
.context("failed to find an appropriate adapter")?;

let hardware_tier = HardwareTier::default();
let hardware_tier = HardwareTier::from_adapter(&adapter);
hardware_tier.check_downlevel_capabilities(&adapter.get_downlevel_capabilities())?;
let (device, queue) = adapter
.request_device(
Expand Down Expand Up @@ -159,6 +159,7 @@ impl<E: Example + 'static> Application<E> {
surface.configure(&device, &surface_config);

let mut re_ctx = RenderContext::new(
&adapter,
device,
queue,
RenderContextConfig {
Expand Down
8 changes: 2 additions & 6 deletions crates/re_renderer/shader/colormap.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const COLORMAP_VIRIDIS: u32 = 6u;
/// Returns a gamma-space sRGB in 0-1 range.
///
/// The input will be saturated to [0, 1] range.
fn colormap_srgb(which: u32, t: f32) -> Vec3 {
fn colormap_srgb(which: u32, t_unsaturated: f32) -> Vec3 {
let t = saturate(t_unsaturated);
if which == COLORMAP_GRAYSCALE {
return linear_from_srgb(Vec3(t));
} else if which == COLORMAP_INFERNO {
Expand Down Expand Up @@ -61,7 +62,6 @@ fn colormap_turbo_srgb(t: f32) -> Vec3 {
let g2 = Vec2(4.27729857, 2.82956604);
let b2 = Vec2(-89.90310912, 27.34824973);

let t = saturate(t);
let v4 = vec4(1.0, t, t * t, t * t * t);
let v2 = v4.zw * v4.z;

Expand Down Expand Up @@ -97,7 +97,6 @@ fn colormap_viridis_srgb(t: f32) -> Vec3 {
let c4 = Vec3(6.228269936347081, 14.17993336680509, 56.69055260068105);
let c5 = Vec3(4.776384997670288, -13.74514537774601, -65.35303263337234);
let c6 = Vec3(-5.435455855934631, 4.645852612178535, 26.3124352495832);
let t = saturate(t);
return c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * c6)))));
}

Expand All @@ -112,7 +111,6 @@ fn colormap_plasma_srgb(t: f32) -> Vec3 {
let c4 = Vec3(-11.10743619062271, -82.66631109428045, 60.13984767418263);
let c5 = Vec3(10.02306557647065, 71.41361770095349, -54.07218655560067);
let c6 = Vec3(-3.658713842777788, -22.93153465461149, 18.19190778539828);
let t = saturate(t);
return c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * c6)))));
}

Expand All @@ -127,7 +125,6 @@ fn colormap_magma_srgb(t: f32) -> Vec3 {
let c4 = Vec3(52.17613981234068, -27.94360607168351, 12.94416944238394);
let c5 = Vec3(-50.76852536473588, 29.04658282127291, 4.23415299384598);
let c6 = Vec3(18.65570506591883, -11.48977351997711, -5.601961508734096);
let t = saturate(t);
return c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * c6)))));
}

Expand All @@ -142,6 +139,5 @@ fn colormap_inferno_srgb(t: f32) -> Vec3 {
let c4 = Vec3(77.162935699427, -33.40235894210092, -81.80730925738993);
let c5 = Vec3(-71.31942824499214, 32.62606426397723, 73.20951985803202);
let c6 = Vec3(25.13112622477341, -12.24266895238567, -23.07032500287172);
let t = saturate(t);
return c0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * (c5 + t * c6)))));
}
2 changes: 1 addition & 1 deletion crates/re_renderer/shader/lines.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ fn vs_main(@builtin(vertex_index) vertex_idx: u32) -> VertexOut {
quad_dir = pos_data_quad_after.pos - pos_data_quad_end.pos; // Go one pos data forward.
} else if is_cap_triangle {
// Discard vertex.
center_position = Vec3(0.0/0.0, 0.0/0.0, 0.0/0.0);
center_position = Vec3(f32max);
} else {
quad_dir = pos_data_quad_end.pos - pos_data_quad_begin.pos;
}
Expand Down
Loading