From bda259b78abd3397196f8060ff562c09bc53de37 Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Thu, 20 Oct 2022 11:47:44 +0200 Subject: [PATCH] standalone cross-platform example for re_renderer (#209) * standalone cross-platform example for re_renderer * moving re_renderer examples over there * easily run examples on the web * moving run_wasm stuff outta crates/ * some more css for run_wasm * good enough for now * auto-open browser tab * cleanin up * whats going on here? * matching new APIs from main * fixing bytemuck gate * setting up a cam * excluse run_wasm from deny check * smarter tab opener * missed one * minor clarification * addressing PR comments * this too Co-authored-by: Emil Ernerfeldt --- .cargo/config.toml | 4 + .github/workflows/rust.yml | 6 + Cargo.lock | 422 +++++++++++++++++- Cargo.toml | 2 +- crates/re_renderer/Cargo.toml | 32 +- .../examples/renderer_standalone.rs | 260 +++++++++++ crates/re_renderer/src/global_bindings.rs | 3 +- crates/re_renderer/src/wgsl_types.rs | 14 +- run_wasm/Cargo.toml | 12 + run_wasm/README.md | 11 + run_wasm/src/main.rs | 127 ++++++ 11 files changed, 877 insertions(+), 16 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 crates/re_renderer/examples/renderer_standalone.rs create mode 100644 run_wasm/Cargo.toml create mode 100644 run_wasm/README.md create mode 100644 run_wasm/src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000000..82a27fc68fd0 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,4 @@ +[alias] +# To easily run examples on the web, see https://github.com/rukai/cargo-run-wasm. +# Temporary solution while we wait for our own xtasks! +run-wasm = "run --release --package run_wasm --" diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2a79283c06e0..8d3c24f465ba 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -139,6 +139,12 @@ jobs: - uses: EmbarkStudios/cargo-deny-action@v1 with: rust-version: "1.64.0" + # NOTE(cmc): run_wasm relies on the wasm-bindgen infrastructure of crates, which uses + # much older versions of common crates than we do. + # This is not really an issue for two reasons: + # 1. `run_wasm` is temporary while we build our own xtask/build tools + # 2. those dependencies never end up in an actual binary + arguments: --exclude run_wasm rs-maturin-linux: diff --git a/Cargo.lock b/Cargo.lock index ac1c80aff47d..f5337b6fc276 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -128,6 +137,20 @@ dependencies = [ "libloading", ] +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + [[package]] name = "async-stream" version = "0.3.3" @@ -149,6 +172,12 @@ dependencies = [ "syn", ] +[[package]] +name = "async-task" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" + [[package]] name = "atk-sys" version = "0.15.1" @@ -190,6 +219,16 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] + [[package]] name = "base64" version = "0.13.0" @@ -291,6 +330,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + [[package]] name = "cairo-sys-rs" version = "0.15.1" @@ -332,6 +377,17 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo-run-wasm" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611b811fad83eebfcdcf47ae1e425c82d1249608bc571d537448d706be08cf27" +dependencies = [ + "devserver_lib", + "pico-args", + "wasm-bindgen-cli-support", +] + [[package]] name = "cargo_metadata" version = "0.15.0" @@ -454,7 +510,7 @@ version = "4.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92289ffc6fb4a85d85c246ddb874c05a87a2e540fb6ad52f7ca07c8c1e1840b1" dependencies = [ - "heck", + "heck 0.4.0", "proc-macro-error", "proc-macro2", "quote", @@ -547,6 +603,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "concurrent-queue" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" +dependencies = [ + "cache-padded", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -557,6 +622,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "console_log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -856,6 +931,12 @@ dependencies = [ "syn", ] +[[package]] +name = "devserver_lib" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb4b71acc1405be2431a93892a79a0d82ed5ba6885649ddbdfc62caa4d67b1c" + [[package]] name = "digest" version = "0.10.3" @@ -1059,6 +1140,19 @@ dependencies = [ "serde", ] +[[package]] +name = "env_logger" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "epaint" version = "0.19.0" @@ -1113,6 +1207,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + [[package]] name = "filetime" version = "0.2.17" @@ -1285,6 +1388,21 @@ version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-macro" version = "0.3.24" @@ -1465,7 +1583,7 @@ name = "gltf" version = "1.0.0" source = "git+https://github.com/rerun-io/gltf?rev=3c14ded73755d1ce9e47010edb06db63cb7e2cca#3c14ded73755d1ce9e47010edb06db63cb7e2cca" dependencies = [ - "base64", + "base64 0.13.0", "byteorder", "gltf-json", "image", @@ -1675,6 +1793,15 @@ dependencies = [ "ahash 0.7.6", ] +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "heck" version = "0.4.0" @@ -1730,6 +1857,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.20" @@ -1768,6 +1901,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "ident_case" version = "1.0.1" @@ -1966,6 +2105,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "lexical" version = "5.2.2" @@ -2499,6 +2644,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "parking_lot" version = "0.12.1" @@ -2534,6 +2685,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -2903,19 +3060,28 @@ version = "0.1.0" dependencies = [ "ahash 0.8.0", "anyhow", + "async-executor", "bytemuck", + "console_error_panic_hook", + "console_log", "crossbeam", + "env_logger", "glam", + "log", "macaw", "notify", "ordered-float", "parking_lot", + "pollster", "re_error", "re_log", "slotmap", "thiserror", "type-map", + "wasm-bindgen-futures", + "web-sys", "wgpu", + "winit", ] [[package]] @@ -3097,6 +3263,8 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", ] @@ -3112,6 +3280,15 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "renderdoc-sys" version = "0.7.1" @@ -3207,11 +3384,26 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" dependencies = [ - "base64", + "base64 0.13.0", "bitflags", "serde", ] +[[package]] +name = "run_wasm" +version = "0.1.0" +dependencies = [ + "cargo-run-wasm", + "pico-args", + "webbrowser", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -3255,6 +3447,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + [[package]] name = "same-file" version = "1.0.6" @@ -3526,7 +3724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" dependencies = [ "cfg-expr", - "heck", + "heck 0.4.0", "pkg-config", "toml", "version-compare", @@ -3538,6 +3736,20 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -3860,7 +4072,7 @@ version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" dependencies = [ - "base64", + "base64 0.13.0", "byteorder", "bytes", "http", @@ -3922,6 +4134,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + [[package]] name = "unicode-width" version = "0.1.9" @@ -4010,6 +4228,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" version = "2.3.2" @@ -4021,6 +4245,32 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "walrus" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8" +dependencies = [ + "anyhow", + "id-arena", + "leb128", + "log", + "walrus-macro", + "wasmparser 0.77.0", +] + +[[package]] +name = "walrus-macro" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "want" version = "0.3.0" @@ -4068,6 +4318,40 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-cli-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03f35e0387a2c787ca5ee299bfb4259352b2a2184b406f8ee9f978c3c4671645" +dependencies = [ + "anyhow", + "base64 0.9.3", + "log", + "rustc-demangle", + "serde_json", + "tempfile", + "walrus", + "wasm-bindgen-externref-xform", + "wasm-bindgen-multi-value-xform", + "wasm-bindgen-shared", + "wasm-bindgen-threads-xform", + "wasm-bindgen-wasm-conventions", + "wasm-bindgen-wasm-interpreter", + "wit-text", + "wit-validator", + "wit-walrus", +] + +[[package]] +name = "wasm-bindgen-externref-xform" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d010a32a516a793adbea5835eab6f736d11c0cdd10ebe0c762c420f67510244" +dependencies = [ + "anyhow", + "walrus", +] + [[package]] name = "wasm-bindgen-futures" version = "0.4.33" @@ -4103,12 +4387,76 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-multi-value-xform" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b8c8d5dcc451b7e6a9c98d8fd966ff768a1e8f8afb270a829780086f2885ac" +dependencies = [ + "anyhow", + "walrus", +] + [[package]] name = "wasm-bindgen-shared" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +[[package]] +name = "wasm-bindgen-threads-xform" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d10f9246c4daa911283a7096fc3be9f1fab9e3e36400478a4ab8d7056701420" +dependencies = [ + "anyhow", + "walrus", + "wasm-bindgen-wasm-conventions", +] + +[[package]] +name = "wasm-bindgen-wasm-conventions" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a5ab217f12f73b7c3ff23cbbbb5d36f7ee97dd65bb0be44beebda887df9002" +dependencies = [ + "anyhow", + "walrus", +] + +[[package]] +name = "wasm-bindgen-wasm-interpreter" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fbb6c773b486889b7c1211d27a7a08eebaf54ec4269380266cadf69e269cd91" +dependencies = [ + "anyhow", + "log", + "walrus", + "wasm-bindgen-wasm-conventions", +] + +[[package]] +name = "wasmparser" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" + +[[package]] +name = "wasmparser" +version = "0.77.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6" + +[[package]] +name = "wast" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1844f66a2bc8526d71690104c0e78a8e59ffa1597b7245769d174ebb91deb5" +dependencies = [ + "leb128", +] + [[package]] name = "wavefront_obj" version = "10.0.0" @@ -4516,6 +4864,70 @@ dependencies = [ "winapi", ] +[[package]] +name = "wit-parser" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f5fd97866f4b9c8e1ed57bcf9446f3d0d8ba37e2dd01c3c612c046c053b06f7" +dependencies = [ + "anyhow", + "leb128", + "wit-schema-version", +] + +[[package]] +name = "wit-schema-version" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfee4a6a4716eefa0682e7a3b836152e894a3e4f34a9d6c2c3e1c94429bfe36a" + +[[package]] +name = "wit-text" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33358e95c77d660f1c7c07f4a93c2bd89768965e844e3c50730bb4b42658df5f" +dependencies = [ + "anyhow", + "wast", + "wit-writer", +] + +[[package]] +name = "wit-validator" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c11d93d925420e7872b226c4161849c32be38385ccab026b88df99d8ddc6ba6" +dependencies = [ + "anyhow", + "wasmparser 0.59.0", + "wit-parser", + "wit-schema-version", +] + +[[package]] +name = "wit-walrus" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad559e3e4c6404b2a6a675d44129d62a3836e3b951b90112fa1c5feb852757cd" +dependencies = [ + "anyhow", + "id-arena", + "walrus", + "wit-parser", + "wit-schema-version", + "wit-writer", +] + +[[package]] +name = "wit-writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ad01ba5e9cbcff799a0689e56a153776ea694cec777f605938cb9880d41a09" +dependencies = [ + "leb128", + "wit-schema-version", +] + [[package]] name = "x11-dl" version = "2.20.0" diff --git a/Cargo.toml b/Cargo.toml index d6f08f3b4dfe..c864603defd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["crates/*", "rerun_py"] +members = ["crates/*", "rerun_py", "run_wasm"] [workspace.package] version = "0.1.0" edition = "2021" diff --git a/crates/re_renderer/Cargo.toml b/crates/re_renderer/Cargo.toml index 11e0db40cfc2..157b9231d66e 100644 --- a/crates/re_renderer/Cargo.toml +++ b/crates/re_renderer/Cargo.toml @@ -8,9 +8,9 @@ publish = false [dependencies] ahash = "0.8" -anyhow = "1.0.56" -bytemuck = "1.12" -glam = "0.20" # can't upgrade until macaw gets a new version using glam 0.21 +anyhow = "1.0" +bytemuck = { version = "1.12", features = ["derive"] } +glam = "0.20" # can't upgrade until macaw gets a new version using glam 0.21 macaw = "0.17" ordered-float = "3.2" parking_lot = "0.12" @@ -32,3 +32,29 @@ wgpu = { version = "0.14", default-features = false, features = [ "webgl", "wgsl", ] } + +## Examples + +[dev-dependencies] +env_logger = "0.9" +log = "0.4" +pollster = "0.2" +winit = "0.27" + +# native +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +async-executor = "1.0" + +# wasm +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +console_error_panic_hook = "0.1.7" +console_log = "0.2" +wasm-bindgen-futures = "0.4.33" +web-sys = { version = "0.3.60", features = [ + "Location", + "Blob", + "RequestInit", + "RequestMode", + "Request", + "Response", +] } diff --git a/crates/re_renderer/examples/renderer_standalone.rs b/crates/re_renderer/examples/renderer_standalone.rs new file mode 100644 index 000000000000..bd9de3cd17fa --- /dev/null +++ b/crates/re_renderer/examples/renderer_standalone.rs @@ -0,0 +1,260 @@ +//! Example of using `re_renderer` in standalone mode. +//! +//! To try it natively: +//! ``` +//! cargo run -p re_renderer --example renderer_standalone +//! ``` +//! +//! To try on the web: +//! ``` +//! cargo run-wasm --example renderer_standalone +//! ``` + +use std::f32::consts::TAU; + +use anyhow::Context as _; +use glam::{Affine3A, Quat, Vec3}; +use macaw::IsoTransform; +use re_renderer::context::{RenderContext, RenderContextConfig}; +use re_renderer::frame_builder::{FrameBuilder, TargetConfiguration}; +use type_map::concurrent::TypeMap; +use wgpu::{ + CommandEncoder, Device, Queue, RenderPass, Surface, SurfaceConfiguration, TextureFormat, +}; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::Window, +}; + +// --- + +// Rendering things using Rerun's renderer. + +async fn run(event_loop: EventLoop<()>, window: Window) { + let mut wgpu_ctx = WgpuContext::new(event_loop, window).await.unwrap(); + + let re_ctx = RenderContext::new( + &wgpu_ctx.device, + &wgpu_ctx.queue, + RenderContextConfig { + output_format_color: wgpu_ctx.swapchain_format, + }, + ); + + // Store our `RenderContext` into the `WgpuContext` so that lifetime issues will + // be handled for us. + wgpu_ctx.user_data.insert(re_ctx); + + wgpu_ctx.run( + // Setting up the `prepare` callback, which will be called once per frame with + // a ready-to-be-filled `CommandEncoder`. + |user_data, device, queue, encoder, resolution| { + let mut frame_builder = FrameBuilder::new(); + + let pos = Vec3::new(0.0, 0.0, 3.0); + let iso = IsoTransform::from_rotation_translation( + Quat::from_affine3(&Affine3A::look_at_rh(pos, Vec3::ZERO, Vec3::Y).inverse()), + pos, + ); + let target_cfg = TargetConfiguration { + resolution_in_pixel: resolution, + world_from_view: iso, + fov_y: 70.0 * TAU / 360.0, + near_plane_distance: 0.01, + target_identifier: 0, + }; + + let re_ctx = user_data.get_mut::().unwrap(); + frame_builder + .setup_target(re_ctx, device, queue, &target_cfg) + .unwrap() + .test_triangle(re_ctx, device) + .generic_skybox(re_ctx, device) + .draw(re_ctx, encoder) + .unwrap(); + + frame_builder + }, + // Setting up the `draw` callback, which will be called once per frame with the + // renderpass drawing onto the swapchain. + { + |user_data, rpass, frame_builder: FrameBuilder| { + let re_ctx = user_data.get::().unwrap(); + frame_builder.finish(re_ctx, rpass).unwrap(); + } + }, + ); +} + +// --- + +// Usual winit + wgpu initialization stuff + +struct WgpuContext { + event_loop: EventLoop<()>, + window: Window, + device: Device, + queue: Queue, + swapchain_format: TextureFormat, + surface: Surface, + surface_config: SurfaceConfiguration, + + pub user_data: TypeMap, +} + +impl WgpuContext { + async fn new(event_loop: EventLoop<()>, window: Window) -> anyhow::Result { + let size = window.inner_size(); + let instance = wgpu::Instance::new(wgpu::Backends::all()); + #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)] + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::default(), + force_fallback_adapter: false, + compatible_surface: Some(&surface), + }) + .await + .context("failed to find an appropriate adapter")?; + + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + label: None, + features: wgpu::Features::empty(), + limits: wgpu::Limits::downlevel_webgl2_defaults() + .using_resolution(adapter.limits()), + }, + None, + ) + .await + .context("failed to create device")?; + + let swapchain_format = if cfg!(target_arch = "wasm32") { + wgpu::TextureFormat::Rgba8Unorm + } else { + wgpu::TextureFormat::Bgra8Unorm + }; + + let surface_config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: swapchain_format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + alpha_mode: wgpu::CompositeAlphaMode::Auto, + }; + surface.configure(&device, &surface_config); + + Ok(Self { + event_loop, + window, + device, + queue, + swapchain_format, + surface, + surface_config, + user_data: TypeMap::new(), + }) + } + + fn run(mut self, mut prepare: Prepare, mut draw: Draw) + where + Prepare: FnMut(&mut TypeMap, &Device, &Queue, &mut CommandEncoder, [u32; 2]) -> DrawData + + 'static, + Draw: for<'a, 'b> FnMut(&'b mut TypeMap, &'a mut RenderPass<'b>, DrawData) + 'static, + { + self.event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { + event: WindowEvent::Resized(size), + .. + } => { + self.surface_config.width = size.width; + self.surface_config.height = size.height; + self.surface.configure(&self.device, &self.surface_config); + self.window.request_redraw(); + } + Event::RedrawRequested(_) => { + let frame = self + .surface + .get_current_texture() + .expect("failed to acquire next swap chain texture"); + let view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + let prepared = prepare( + &mut self.user_data, + &self.device, + &self.queue, + &mut encoder, + [self.surface_config.height, self.surface_config.width], + ); + + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::GREEN), + store: true, + }, + })], + depth_stencil_attachment: None, + }); + + draw(&mut self.user_data, &mut rpass, prepared); + } + + self.queue.submit(Some(encoder.finish())); + frame.present(); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + _ => {} + } + }); + } +} + +// --- + +fn main() { + let event_loop = EventLoop::new(); + let window = winit::window::Window::new(&event_loop).unwrap(); + + #[cfg(not(target_arch = "wasm32"))] + { + env_logger::init(); + pollster::block_on(run(event_loop, window)); + } + + #[cfg(target_arch = "wasm32")] + { + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + console_log::init().expect("could not initialize logger"); + use winit::platform::web::WindowExtWebSys; + // On wasm, append the canvas to the document body + web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| doc.body()) + .and_then(|body| { + body.append_child(&web_sys::Element::from(window.canvas())) + .ok() + }) + .expect("couldn't append canvas to document body"); + wasm_bindgen_futures::spawn_local(run(event_loop, window)); + } +} diff --git a/crates/re_renderer/src/global_bindings.rs b/crates/re_renderer/src/global_bindings.rs index 0aba002987f4..154c961e9674 100644 --- a/crates/re_renderer/src/global_bindings.rs +++ b/crates/re_renderer/src/global_bindings.rs @@ -10,13 +10,14 @@ use crate::{ }, wgsl_types, }; +use bytemuck::{Pod, Zeroable}; /// Mirrors the GPU contents of a frame-global uniform buffer. /// /// Contains information that is constant for a single frame like camera. /// (does not contain information that is special to a particular renderer) #[repr(C)] -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Clone, Copy, Zeroable, Pod)] pub(crate) struct FrameUniformBuffer { pub view_from_world: wgsl_types::Mat4x3, pub projection_from_view: wgsl_types::Mat4, diff --git a/crates/re_renderer/src/wgsl_types.rs b/crates/re_renderer/src/wgsl_types.rs index 741d2191b1a3..3d9217604167 100644 --- a/crates/re_renderer/src/wgsl_types.rs +++ b/crates/re_renderer/src/wgsl_types.rs @@ -3,8 +3,10 @@ //! //! This is especially important for cases where [`glam`] isn't explicit about padding and alignment. +use bytemuck::{Pod, Zeroable}; + #[repr(C, align(8))] -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Clone, Copy, Zeroable, Pod)] pub struct Vec2 { pub x: f32, pub y: f32, @@ -18,7 +20,7 @@ impl From for Vec2 { } #[repr(C, align(16))] -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Clone, Copy, Zeroable, Pod)] pub struct Vec2Padded { pub x: f32, pub y: f32, @@ -39,7 +41,7 @@ impl From for Vec2Padded { } #[repr(C, align(16))] -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Clone, Copy, Zeroable, Pod)] pub struct Vec3 { pub x: f32, pub y: f32, @@ -72,7 +74,7 @@ impl From for Vec3 { } #[repr(C, align(16))] -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Clone, Copy, Zeroable, Pod)] pub struct Vec4 { pub x: f32, pub y: f32, @@ -93,7 +95,7 @@ impl From for Vec4 { } #[repr(C, align(16))] -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Clone, Copy, Zeroable, Pod)] pub struct Mat4 { c0: Vec4, c1: Vec4, @@ -114,7 +116,7 @@ impl From for Mat4 { } #[repr(C, align(16))] -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] +#[derive(Clone, Copy, Zeroable, Pod)] pub struct Mat4x3 { c0: Vec3, c1: Vec3, diff --git a/run_wasm/Cargo.toml b/run_wasm/Cargo.toml new file mode 100644 index 000000000000..9fa8a128cf48 --- /dev/null +++ b/run_wasm/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "run_wasm" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +publish = false + +[dependencies] +cargo-run-wasm = "0.2.0" +pico-args = "0.5" +webbrowser = "0.8" diff --git a/run_wasm/README.md b/run_wasm/README.md new file mode 100644 index 000000000000..b2f69bd06b7a --- /dev/null +++ b/run_wasm/README.md @@ -0,0 +1,11 @@ +# run-wasm + +This provides an [`xtask`](https://github.com/matklad/cargo-xtask) that makes it trivial to run web-based examples. + +It relies on [`cargo-run-wasm`](https://github.com/rukai/cargo-run-wasm) to run the `wasm-bindgen` machinery, generate HTML files and all of that good stuff. +This is a temporary solution while we're in the process of building our own `xtask` tools. + +You can try it e.g. with the standalone re_renderer demo: +``` +cargo run-wasm --example renderer_standalone +``` diff --git a/run_wasm/src/main.rs b/run_wasm/src/main.rs new file mode 100644 index 000000000000..4fd4dabbb012 --- /dev/null +++ b/run_wasm/src/main.rs @@ -0,0 +1,127 @@ +//! Intended to be used as an xtask in order to make it trivial to run web-based examples. +//! +//! This is a temporary solution while we're in the process of building our own xtask tools. + +use std::{net::ToSocketAddrs, time::Duration}; + +fn main() { + // TODO(cmc): Why is this not taking the full screen? + const CSS: &str = r#" + html { + /* Remove touch delay: */ + touch-action: manipulation; + } + + body { + /* Light mode background color for what is not covered by the egui canvas, + or where the egui canvas is translucent. */ + background: #909090; + } + + @media (prefers-color-scheme: dark) { + body { + /* Dark mode background color for what is not covered by the egui canvas, + or where the egui canvas is translucent. */ + background: #404040; + } + } + + /* Allow canvas to fill entire web page: */ + html, + body { + overflow: hidden; + margin: 0 !important; + padding: 0 !important; + height: 100%; + width: 100%; + } + + /* Position canvas in center-top: */ + canvas { + margin-right: auto; + margin-left: auto; + display: block; + position: absolute; + top: 0%; + left: 50%; + transform: translate(-50%, 0%); + } + + .centered { + margin-right: auto; + margin-left: auto; + display: block; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: #f0f0f0; + font-size: 24px; + font-family: Ubuntu-Light, Helvetica, sans-serif; + text-align: center; + } + + /* ---------------------------------------------- */ + /* Loading animation from https://loading.io/css/ */ + .lds-dual-ring { + display: inline-block; + width: 24px; + height: 24px; + } + + .lds-dual-ring:after { + content: " "; + display: block; + width: 24px; + height: 24px; + margin: 0px; + border-radius: 50%; + border: 3px solid #fff; + border-color: #fff transparent #fff transparent; + animation: lds-dual-ring 1.2s linear infinite; + } + + @keyframes lds-dual-ring { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + "#; + + use pico_args::Arguments; + let mut args = Arguments::from_env(); + let host: Option = args.opt_value_from_str("--host").unwrap(); + let port: Option = args.opt_value_from_str("--port").unwrap(); + let host = host.as_deref().unwrap_or("localhost"); + let port = port.as_deref().unwrap_or("8000"); + + std::thread::spawn(|| { + cargo_run_wasm::run_wasm_with_css(CSS); + }); + + // Wait for the server to be up before opening a browser tab. + let addr = format!("{host}:{port}") + .to_socket_addrs() + .unwrap() + .next() + .unwrap(); + loop { + // TODO(cmc): this will make the webserver embedded within cargo-run-wasm complain + // a bit but eh... that's only temporary. + if std::net::TcpStream::connect(addr).is_ok() { + break; + } + std::thread::sleep(Duration::from_millis(200)); + } + + // Open browser tab. + let viewer_url = format!("http://{host}:{port}",); + webbrowser::open(&viewer_url).ok(); + println!("Opening browser at {viewer_url}"); + + std::thread::sleep(Duration::from_secs(u64::MAX)); +}