diff --git a/.cargo/config.toml b/.cargo/config.toml index 097c2ea3ba0a..18ecd71a6b15 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -10,6 +10,9 @@ rerun-release = "run --package rerun-cli --no-default-features --features native # `cargo rerun-web` is short a convenient shorthand for building & starting the web viewer. rerun-web = "run --package rerun-cli --no-default-features --features web_viewer -- --web-viewer" +# `cargo rerun-release-web` is short a convenient shorthand for building & starting the web viewer in release mode. +rerun-release-web = "run --package rerun-cli --no-default-features --features web_viewer --release -- --web-viewer" + # Run the codegen. Optionally pass `--profile` to it. # NOTE: there are several CI jobs with `command: codegen` with the cargo action codegen = "run --package re_types_builder --" diff --git a/Cargo.lock b/Cargo.lock index e0f995289c4a..6c3908e2f41a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5038,7 +5038,9 @@ dependencies = [ "serde_json", "thiserror", "time", + "wasm-bindgen", "wasm-bindgen-futures", + "web-sys", "web-time", "wgpu", ] diff --git a/crates/re_renderer/src/config.rs b/crates/re_renderer/src/config.rs index e2408bce6b1c..9b0ef6573b02 100644 --- a/crates/re_renderer/src/config.rs +++ b/crates/re_renderer/src/config.rs @@ -230,3 +230,72 @@ pub fn supported_backends() -> wgpu::Backends { wgpu::Backends::GL | wgpu::Backends::BROWSER_WEBGPU } } + +/// Generous parsing of a graphics backend string. +pub fn parse_graphics_backend(backend: &str) -> Option { + match backend.to_lowercase().as_str() { + // "vulcan" is a common typo that we just swallow. We know what you mean ;) + "vulcan" | "vulkan" | "vk" => Some(wgpu::Backend::Vulkan), + + "metal" | "apple" | "mtl" => Some(wgpu::Backend::Metal), + + "dx12" | "dx" | "d3d" | "d3d12" | "directx" => Some(wgpu::Backend::Dx12), + + // We don't want to lie - e.g. `webgl1` should not work! + // This means that `gles`/`gles3` stretches it a bit, but it's still close enough. + // Similarly, we accept both `webgl` & `opengl` on each desktop & web. + // This is a bit dubious but also too much hassle to forbid. + "webgl2" | "webgl" | "opengl" | "gles" | "gles3" | "gl" => Some(wgpu::Backend::Gl), + + "browserwebgpu" | "webgpu" => Some(wgpu::Backend::BrowserWebGpu), + + _ => None, + } +} + +/// Validates that the given backend is applicable for the current build. +/// +/// This is meant as a sanity check of first resort. +/// There are still many other reasons why a backend may not work on a given platform/build combination. +pub fn validate_graphics_backend_applicability(backend: wgpu::Backend) -> Result<(), &'static str> { + match backend { + wgpu::Backend::Empty => { + // This should never happen. + return Err("Cannot run with empty backend."); + } + wgpu::Backend::Vulkan => { + // Through emulation and build configs Vulkan may work everywhere except the web. + if cfg!(target_arch = "wasm32") { + return Err("Can only run with WebGL or WebGPU on the web."); + } + } + wgpu::Backend::Metal => { + if cfg!(target_arch = "wasm32") { + return Err("Can only run with WebGL or WebGPU on the web."); + } + if cfg!(target_os = "linux") || cfg!(target_os = "windows") { + return Err("Cannot run with DX12 backend on Linux & Windows."); + } + } + wgpu::Backend::Dx12 => { + // We don't have DX12 enabled right now, but someone could. + // TODO(wgpu#5166): But if we get this wrong we might crash. + // TODO(wgpu#5167): And we also can't query the config. + return Err("DX12 backend is currently not supported."); + } + wgpu::Backend::Gl => { + // Using Angle Mac might actually run GL, but we don't enable this. + // TODO(wgpu#5166): But if we get this wrong we might crash. + // TODO(wgpu#5167): And we also can't query the config. + if cfg!(target_os = "macos") { + return Err("Cannot run with GL backend on Mac."); + } + } + wgpu::Backend::BrowserWebGpu => { + if !cfg!(target_arch = "wasm32") { + return Err("Cannot run with WebGPU backend on native application."); + } + } + } + Ok(()) +} diff --git a/crates/re_sdk/src/web_viewer.rs b/crates/re_sdk/src/web_viewer.rs index d1ce6d06b1f4..2b70ddf7592a 100644 --- a/crates/re_sdk/src/web_viewer.rs +++ b/crates/re_sdk/src/web_viewer.rs @@ -79,6 +79,7 @@ impl WebViewerSink { pub async fn host_web_viewer( bind_ip: String, web_port: WebViewerServerPort, + force_wgpu_backend: Option, open_browser: bool, source_url: String, ) -> anyhow::Result<()> { @@ -86,7 +87,10 @@ pub async fn host_web_viewer( let http_web_viewer_url = web_server.server_url(); let web_server_handle = web_server.serve(); - let viewer_url = format!("{http_web_viewer_url}?url={source_url}"); + let mut viewer_url = format!("{http_web_viewer_url}?url={source_url}"); + if let Some(force_graphics) = force_wgpu_backend { + viewer_url = format!("{viewer_url}&renderer={force_graphics}"); + } re_log::info!("Hosting a web-viewer at {viewer_url}"); if open_browser { diff --git a/crates/re_ui/src/command.rs b/crates/re_ui/src/command.rs index b27c5bfdbd77..0a9ed503dd74 100644 --- a/crates/re_ui/src/command.rs +++ b/crates/re_ui/src/command.rs @@ -74,6 +74,12 @@ pub enum UICommand { #[cfg(target_arch = "wasm32")] CopyDirectLink, + + // Graphics options: + #[cfg(target_arch = "wasm32")] + RestartWithWebGl, + #[cfg(target_arch = "wasm32")] + RestartWithWebGpu, } impl UICommand { @@ -201,7 +207,18 @@ impl UICommand { Self::CopyDirectLink => ( "Copy direct link", "Copy a link to the viewer with the URL parameter set to the current .rrd data source." - ) + ), + + #[cfg(target_arch = "wasm32")] + Self::RestartWithWebGl => ( + "Restart with WebGL", + "Reloads the webpage and force WebGL for rendering. All data will be lost." + ), + #[cfg(target_arch = "wasm32")] + Self::RestartWithWebGpu => ( + "Restart with WebGPU", + "Reloads the webpage and force WebGPU for rendering. All data will be lost." + ), } } @@ -285,6 +302,11 @@ impl UICommand { #[cfg(target_arch = "wasm32")] Self::CopyDirectLink => None, + + #[cfg(target_arch = "wasm32")] + Self::RestartWithWebGl => None, + #[cfg(target_arch = "wasm32")] + Self::RestartWithWebGpu => None, } } diff --git a/crates/re_viewer/Cargo.toml b/crates/re_viewer/Cargo.toml index 611ef0558fae..749db3cd6c08 100644 --- a/crates/re_viewer/Cargo.toml +++ b/crates/re_viewer/Cargo.toml @@ -106,7 +106,15 @@ wgpu.workspace = true # web dependencies: [target.'cfg(target_arch = "wasm32")'.dependencies] +wasm-bindgen.workspace = true wasm-bindgen-futures.workspace = true +web-sys = { workspace = true, features = [ + 'Location', + 'Url', + 'UrlSearchParams', + 'Window', +] } + [build-dependencies] re_build_tools.workspace = true diff --git a/crates/re_viewer/src/app.rs b/crates/re_viewer/src/app.rs index 5530b66bd7eb..3a563dcf0ea2 100644 --- a/crates/re_viewer/src/app.rs +++ b/crates/re_viewer/src/app.rs @@ -56,6 +56,9 @@ pub struct StartupOptions { pub resolution_in_points: Option<[f32; 2]>, pub skip_welcome_screen: bool, + + /// Forces wgpu backend to use the specified graphics API. + pub force_wgpu_backend: Option, } impl Default for StartupOptions { @@ -75,6 +78,7 @@ impl Default for StartupOptions { resolution_in_points: None, skip_welcome_screen: false, + force_wgpu_backend: None, } } } @@ -639,6 +643,20 @@ impl App { UICommand::CopyDirectLink => { self.run_copy_direct_link_command(store_context); } + + #[cfg(target_arch = "wasm32")] + UICommand::RestartWithWebGl => { + if crate::web_tools::set_url_parameter_and_refresh("renderer", "webgl").is_err() { + re_log::error!("Failed to set URL parameter `renderer=webgl` & refresh page."); + } + } + + #[cfg(target_arch = "wasm32")] + UICommand::RestartWithWebGpu => { + if crate::web_tools::set_url_parameter_and_refresh("renderer", "webgpu").is_err() { + re_log::error!("Failed to set URL parameter `renderer=webgpu` & refresh page."); + } + } } } diff --git a/crates/re_viewer/src/lib.rs b/crates/re_viewer/src/lib.rs index 70a283e58400..dd325eba9612 100644 --- a/crates/re_viewer/src/lib.rs +++ b/crates/re_viewer/src/lib.rs @@ -55,6 +55,9 @@ pub use native::{run_native_app, run_native_viewer_with_messages}; #[cfg(target_arch = "wasm32")] mod web; +#[cfg(target_arch = "wasm32")] +mod web_tools; + // --------------------------------------------------------------------------- /// Information about this version of the crate. @@ -129,8 +132,29 @@ impl AppEnvironment { // --------------------------------------------------------------------------- -pub(crate) fn wgpu_options() -> egui_wgpu::WgpuConfiguration { +fn supported_graphics_backends(force_wgpu_backend: Option) -> wgpu::Backends { + if let Some(force_wgpu_backend) = force_wgpu_backend { + if let Some(backend) = re_renderer::config::parse_graphics_backend(&force_wgpu_backend) { + if let Err(err) = re_renderer::config::validate_graphics_backend_applicability(backend) + { + re_log::error!("Failed to force rendering backend parsed from {force_wgpu_backend:?}: {err}\nUsing default backend instead."); + re_renderer::config::supported_backends() + } else { + re_log::info!("Forcing graphics backend to {backend:?}."); + backend.into() + } + } else { + re_log::error!("Failed to parse rendering backend string {force_wgpu_backend:?}. Using default backend instead."); + re_renderer::config::supported_backends() + } + } else { + re_renderer::config::supported_backends() + } +} + +pub(crate) fn wgpu_options(force_wgpu_backend: Option) -> egui_wgpu::WgpuConfiguration { re_tracing::profile_function!(); + egui_wgpu::WgpuConfiguration { // When running wgpu on native debug builds, we want some extra control over how // and when a poisoned surface gets recreated. @@ -150,7 +174,7 @@ pub(crate) fn wgpu_options() -> egui_wgpu::WgpuConfiguration { egui_wgpu::SurfaceErrorAction::SkipFrame } }), - supported_backends: re_renderer::config::supported_backends(), + supported_backends: supported_graphics_backends(force_wgpu_backend), device_descriptor: std::sync::Arc::new(|adapter| re_renderer::config::DeviceCaps::from_adapter(adapter).device_descriptor()), ..Default::default() } diff --git a/crates/re_viewer/src/native.rs b/crates/re_viewer/src/native.rs index 42cff5bf7fc3..61c1a80dd526 100644 --- a/crates/re_viewer/src/native.rs +++ b/crates/re_viewer/src/native.rs @@ -7,8 +7,11 @@ type AppCreator = Box, re_ui::ReUi) -> Box>; // NOTE: the name of this function is hard-coded in `crates/rerun/src/crash_handler.rs`! -pub fn run_native_app(app_creator: AppCreator) -> eframe::Result<()> { - let native_options = eframe_options(); +pub fn run_native_app( + app_creator: AppCreator, + force_wgpu_backend: Option, +) -> eframe::Result<()> { + let native_options = eframe_options(force_wgpu_backend); let window_title = "Rerun Viewer"; eframe::run_native( @@ -21,7 +24,7 @@ pub fn run_native_app(app_creator: AppCreator) -> eframe::Result<()> { ) } -pub fn eframe_options() -> eframe::NativeOptions { +pub fn eframe_options(force_wgpu_backend: Option) -> eframe::NativeOptions { re_tracing::profile_function!(); eframe::NativeOptions { viewport: egui::ViewportBuilder::default() @@ -40,7 +43,7 @@ pub fn eframe_options() -> eframe::NativeOptions { default_theme: eframe::Theme::Dark, renderer: eframe::Renderer::Wgpu, - wgpu_options: crate::wgpu_options(), + wgpu_options: crate::wgpu_options(force_wgpu_backend), depth_buffer: 0, multisampling: 0, // the 3D views do their own MSAA @@ -92,9 +95,14 @@ pub fn run_native_viewer_with_messages( for log_msg in log_messages { tx.send(log_msg).ok(); } - run_native_app(Box::new(move |cc, re_ui| { - let mut app = crate::App::new(build_info, &app_env, startup_options, re_ui, cc.storage); - app.add_receiver(rx); - Box::new(app) - })) + + let force_wgpu_backend = startup_options.force_wgpu_backend.clone(); + run_native_app( + Box::new(move |cc, re_ui| { + let mut app = crate::App::new(build_info, &app_env, startup_options, re_ui, cc.storage); + app.add_receiver(rx); + Box::new(app) + }), + force_wgpu_backend, + ) } diff --git a/crates/re_viewer/src/ui/rerun_menu.rs b/crates/re_viewer/src/ui/rerun_menu.rs index 6c124d8ea587..4a5b41ce7665 100644 --- a/crates/re_viewer/src/ui/rerun_menu.rs +++ b/crates/re_viewer/src/ui/rerun_menu.rs @@ -83,6 +83,7 @@ impl App { &self.command_sender, &self.re_ui, ui, + frame, &mut self.state.app_options, ); }); @@ -236,7 +237,7 @@ fn render_state_ui(ui: &mut egui::Ui, render_state: &egui_wgpu::RenderState) { egui::Grid::new("adapter_info").show(ui, |ui| { ui.label("Backend"); - ui.label(format!("{backend:?}")); + ui.label(backend.to_str()); // TODO(wgpu#5170): Use std::fmt::Display for backend. ui.end_row(); ui.label("Device Type"); @@ -274,7 +275,8 @@ fn render_state_ui(ui: &mut egui::Ui, render_state: &egui_wgpu::RenderState) { let wgpu_adapter_ui = |ui: &mut egui::Ui, adapter: &eframe::wgpu::Adapter| { let info = &adapter.get_info(); - ui.label(format!("{:?}", info.backend)).on_hover_ui(|ui| { + // TODO(wgpu#5170): Use std::fmt::Display for backend. + ui.label(info.backend.to_str()).on_hover_ui(|ui| { wgpu_adapter_details_ui(ui, adapter); }); }; @@ -303,6 +305,7 @@ fn options_menu_ui( command_sender: &re_viewer_context::CommandSender, re_ui: &ReUi, ui: &mut egui::Ui, + frame: &eframe::Frame, app_options: &mut re_viewer_context::AppOptions, ) { re_ui @@ -338,6 +341,23 @@ fn options_menu_ui( ui.label("Experimental features:"); experimental_feature_ui(command_sender, re_ui, ui, app_options); } + + if let Some(_backend) = frame + .wgpu_render_state() + .map(|state| state.adapter.get_info().backend) + { + // Adapter switching only implemented for web so far. + // For native it's less well defined since the application may be embedded in another application that reads arguments differently. + #[cfg(target_arch = "wasm32")] + { + ui.add_space(SPACING); + if _backend == wgpu::Backend::BrowserWebGpu { + UICommand::RestartWithWebGl.menu_button_ui(ui, command_sender); + } else { + UICommand::RestartWithWebGpu.menu_button_ui(ui, command_sender); + } + } + } } fn experimental_feature_ui( diff --git a/crates/re_viewer/src/web.rs b/crates/re_viewer/src/web.rs index 1e4abfcbe2f1..aaf08e53296f 100644 --- a/crates/re_viewer/src/web.rs +++ b/crates/re_viewer/src/web.rs @@ -31,17 +31,19 @@ impl WebHandle { /// - `url` is an optional URL to either an .rrd file over http, or a Rerun WebSocket server. /// - `manifest_url` is an optional URL to an `examples_manifest.json` file over http. + /// - `force_wgpu_backend` is an optional string to force a specific backend, either `webgl` or `webgpu`. #[wasm_bindgen] pub async fn start( &self, canvas_id: &str, url: Option, manifest_url: Option, + force_wgpu_backend: Option, ) -> Result<(), wasm_bindgen::JsValue> { let web_options = eframe::WebOptions { follow_system_theme: false, default_theme: eframe::Theme::Dark, - wgpu_options: crate::wgpu_options(), + wgpu_options: crate::wgpu_options(force_wgpu_backend), depth_buffer: 0, ..Default::default() }; @@ -119,6 +121,7 @@ fn create_app( persist_state: get_persist_state(&cc.integration_info), is_in_notebook: is_in_notebook(&cc.integration_info), skip_welcome_screen: false, + force_wgpu_backend: None, }; let re_ui = crate::customize_eframe(cc); diff --git a/crates/re_viewer/src/web_tools.rs b/crates/re_viewer/src/web_tools.rs new file mode 100644 index 000000000000..2575a31a944e --- /dev/null +++ b/crates/re_viewer/src/web_tools.rs @@ -0,0 +1,11 @@ +pub fn set_url_parameter_and_refresh(key: &str, value: &str) -> Result<(), wasm_bindgen::JsValue> { + let Some(window) = web_sys::window() else { + return Err("Failed to get window".into()); + }; + let location = window.location(); + + let url = web_sys::Url::new(&location.href()?)?; + url.search_params().set(key, value); + + location.assign(&url.href()) +} diff --git a/crates/rerun/src/run.rs b/crates/rerun/src/run.rs index f8bd8db2bb4b..c3ef96aaa5b8 100644 --- a/crates/rerun/src/run.rs +++ b/crates/rerun/src/run.rs @@ -23,7 +23,7 @@ Environment variables: RERUN_SHADER_PATH The search path for shader/shader-imports. Only available in developer builds. RERUN_TRACK_ALLOCATIONS Track memory allocations to diagnose memory leaks in the viewer. WARNING: slows down the viewer by a lot! RUST_LOG Change the log level of the viewer, e.g. `RUST_LOG=debug`. - WGPU_BACKEND Overwrites the graphics backend used, must be one of `vulkan`, `metal`, `dx12`, `dx11`, or `gl`. + WGPU_BACKEND Overwrites the graphics backend used, must be one of `vulkan`, `metal` or `gl`. Default is `vulkan` everywhere except on Mac where we use `metal`. What is supported depends on your OS. WGPU_POWER_PREF Overwrites the power setting used for choosing a graphics adapter, must be `high` or `low`. (Default is `high`) @@ -181,6 +181,21 @@ If no arguments are given, a server will be hosted which a Rerun SDK can connect #[clap(long, default_value_t = Default::default())] ws_server_port: RerunServerPort, + /// Override the default graphics backend and for a specific one instead. + /// + /// When using `--web-viewer` this should be one of: + /// * `webgpu` + /// * `webgl` + /// + /// When starting a native viewer instead this should be one of: + /// * `vulkan` (Linux & Windows only) + /// * `gl` (Linux & Windows only) + /// * `metal` (macOS only) + // Note that we don't compile with DX12 right now, but we could (we don't since this adds permutation and wgpu still has some issues with it). + // GL could be enabled on MacOS via `angle` but given prior issues with ANGLE this seems to be a bad idea! + #[clap(long)] + renderer: Option, + // ---------------------------------------------------------------------------- // Debug-options: /// Ingest data and then quit once the goodbye message has been received. @@ -499,6 +514,7 @@ async fn run_impl( } else { None }, + force_wgpu_backend: None, } }; @@ -534,6 +550,7 @@ async fn run_impl( return host_web_viewer( args.bind.clone(), args.web_viewer_port, + args.renderer, true, rerun_server_ws_url, ) @@ -608,6 +625,7 @@ async fn run_impl( let web_server_handle = tokio::spawn(host_web_viewer( args.bind.clone(), args.web_viewer_port, + args.renderer, open_browser, _ws_server_url, )); @@ -620,23 +638,26 @@ async fn run_impl( } } else { #[cfg(feature = "native_viewer")] - return re_viewer::run_native_app(Box::new(move |cc, re_ui| { - let mut app = re_viewer::App::new( - _build_info, - &call_source.app_env(), - startup_options, - re_ui, - cc.storage, - ); - for rx in rx { - app.add_receiver(rx); - } - app.set_profiler(profiler); - if let Ok(url) = std::env::var("EXAMPLES_MANIFEST_URL") { - app.set_examples_manifest_url(url); - } - Box::new(app) - })) + return re_viewer::run_native_app( + Box::new(move |cc, re_ui| { + let mut app = re_viewer::App::new( + _build_info, + &call_source.app_env(), + startup_options, + re_ui, + cc.storage, + ); + for rx in rx { + app.add_receiver(rx); + } + app.set_profiler(profiler); + if let Ok(url) = std::env::var("EXAMPLES_MANIFEST_URL") { + app.set_examples_manifest_url(url); + } + Box::new(app) + }), + args.renderer, + ) .map_err(|err| err.into()); #[cfg(not(feature = "native_viewer"))] diff --git a/docs/content/getting-started/troubleshooting.md b/docs/content/getting-started/troubleshooting.md index 290f8dd06949..b3675290c912 100644 --- a/docs/content/getting-started/troubleshooting.md +++ b/docs/content/getting-started/troubleshooting.md @@ -66,13 +66,16 @@ rerun reset [Wgpu](https://github.com/gfx-rs/wgpu) (the graphics API we use) maintains a list of [known driver issues](https://github.com/gfx-rs/wgpu/wiki/Known-Driver-Issues) and workarounds for them. -The following environment variables overwrite the config we choose for wgpu: -* `WGPU_BACKEND`: Overwrites the graphics backend used, must be one of `vulkan`, `metal`, `dx12`, `dx11`, or `gl`. - Naturally, support depends on your OS. Default is `vulkan` everywhere except on Mac where we use `metal`. +The configuration we use for wgpu can be influenced in the following ways: +* pass `--renderer=` on startup: `` must be one of `vulkan`, `metal` or `gl` for native and + either `webgl` or `webgpu` for the web viewer (see also `--web-viewer` argument). + Naturally, support depends on your OS. The default backend is `vulkan` everywhere except on Mac where we use `metal`. + On the web we prefer WebGPU and fall back automatically to WebGL if no support for WebGPU was detected. + * For instance, you can try `rerun --renderer=gl` or for the web viewer respectively `rerun --web-viewer --renderer=webgl`. + * Alternatively, for the native viewer you can also use the `WGPU_BACKEND` environment variable with the above values. + * The web viewer is configured by the `renderer=` url argument, e.g. [https://app.rerun.io/?renderer=webgl] * `WGPU_POWER_PREF`: Overwrites the power setting used for choosing a graphics adapter, must be `high` or `low`. (Default is `high`) -For instance, you can try `WGPU_BACKEND=gl rerun`. - We recommend setting these only if you're asked to try them or know what you're doing, since we don't support all of these settings equally well. diff --git a/examples/rust/custom_space_view/src/main.rs b/examples/rust/custom_space_view/src/main.rs index dc13199b4e8a..32d151b6c106 100644 --- a/examples/rust/custom_space_view/src/main.rs +++ b/examples/rust/custom_space_view/src/main.rs @@ -40,22 +40,25 @@ async fn main() -> Result<(), Box> { ); println!("Try for example to run: `cargo run -p minimal_options -- --connect` in another terminal instance."); - re_viewer::run_native_app(Box::new(move |cc, re_ui| { - let mut app = re_viewer::App::new( - re_viewer::build_info(), - &app_env, - startup_options, - re_ui, - cc.storage, - ); - app.add_receiver(rx); - - // Register the custom space view - app.add_space_view_class::() - .unwrap(); - - Box::new(app) - }))?; + re_viewer::run_native_app( + Box::new(move |cc, re_ui| { + let mut app = re_viewer::App::new( + re_viewer::build_info(), + &app_env, + startup_options, + re_ui, + cc.storage, + ); + app.add_receiver(rx); + + // Register the custom space view + app.add_space_view_class::() + .unwrap(); + + Box::new(app) + }), + None, + )?; Ok(()) } diff --git a/examples/rust/extend_viewer_ui/src/main.rs b/examples/rust/extend_viewer_ui/src/main.rs index 4387ffb16b5e..f9f075dc18a1 100644 --- a/examples/rust/extend_viewer_ui/src/main.rs +++ b/examples/rust/extend_viewer_ui/src/main.rs @@ -32,7 +32,7 @@ async fn main() -> Result<(), Box> { let native_options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_app_id("rerun_extend_viewer_ui_example"), - ..re_viewer::native::eframe_options() + ..re_viewer::native::eframe_options(None) }; let startup_options = re_viewer::StartupOptions::default(); diff --git a/web_viewer/index.html b/web_viewer/index.html index d49217b1279d..e95445e3b123 100644 --- a/web_viewer/index.html +++ b/web_viewer/index.html @@ -218,6 +218,20 @@ load_wasm(); } + var urlWebGl = new URL(window.location); + urlWebGl.searchParams.set("renderer", "webgl"); + + var urlWebGpu = new URL(window.location); + urlWebGpu.searchParams.set("renderer", "webgpu"); + + const forceWgpuBackendInfoParagraph = ` +

+ For graphics related issues, try forcing to render with WebGL
+ ${urlWebGl}
+ or with WebGPU
+ ${urlWebGpu} +

`; + function load_wasm() { // We'll defer our execution until the wasm is ready to go. // Here we tell bindgen the path to the wasm file so it can start @@ -325,8 +339,10 @@ See the console for details.

- Reload the page to try again. + Reload the page to try again.
+ Please consider filing a bug report. Thank you!

+ ${forceWgpuBackendInfoParagraph} `); } else { let delay_ms = 1000; @@ -336,7 +352,13 @@ check_for_panic(); - handle.start("the_canvas_id").then(on_app_started).catch(on_wasm_error); + const urlParams = new URLSearchParams(window.location.search); + const forceWgpuBackend = urlParams.get("renderer"); + + handle + .start("the_canvas_id", null, null, forceWgpuBackend) + .then(on_app_started) + .catch(on_wasm_error); } function on_app_started(handle) { @@ -363,9 +385,11 @@

${error}

-

- Make sure you use a modern browser with either WebGL or WebGPU support enabled. +

+ Reload the page to try again.
+ Please consider filing a
bug report. Thank you!

+ ${forceWgpuBackendInfoParagraph} `); }