diff --git a/Cargo.lock b/Cargo.lock index dbdcdfa2..3ca17865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2300,6 +2300,7 @@ dependencies = [ "tokio", "url", "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", "wgpu-executor", "winit", diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index fa6ab03b..26d5d797 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -45,12 +45,18 @@ impl PreferencesDialogMessageHandler { }) .widget_holder(), ]; + let vello_tooltip = "Use the experimental Vello renderer (your browser must support WebGPU)"; let use_vello = vec![ TextLabel::new("Renderer").min_width(60).italic(true).widget_holder(), - TextLabel::new("Vello (Experimental)").table_align(true).widget_holder(), + TextLabel::new("Vello (Experimental)") + .table_align(true) + .tooltip(vello_tooltip) + .disabled(!preferences.supports_wgpu()) + .widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder(), - CheckboxInput::new(preferences.use_vello) - .tooltip("Use the experimental Vello renderer (your browser must support WebGPU)") + CheckboxInput::new(preferences.use_vello && preferences.supports_wgpu()) + .tooltip(vello_tooltip) + .disabled(!preferences.supports_wgpu()) .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::UseVello { use_vello: checkbox_input.checked }.into()) .widget_holder(), ]; diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 916ce412..39b6ba05 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -642,6 +642,7 @@ impl MessageHandler> for PortfolioMes responses.add(FrontendMessage::UpdateOpenDocumentsList { open_documents }); } PortfolioMessage::UpdateVelloPreference => { + responses.add(NodeGraphMessage::RunDocumentGraph); self.persistent_data.use_vello = preferences.use_vello; } } diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index 0031943f..2ad57606 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -14,9 +14,13 @@ impl PreferencesMessageHandler { pub fn editor_preferences(&self) -> EditorPreferences { EditorPreferences { imaginate_hostname: self.imaginate_server_hostname.clone(), - use_vello: self.use_vello, + use_vello: self.use_vello && self.supports_wgpu(), } } + + pub fn supports_wgpu(&self) -> bool { + graph_craft::wasm_application_io::wgpu_available().unwrap_or_default() + } } impl Default for PreferencesMessageHandler { diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index e6895d77..3d8ad15f 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -153,7 +153,15 @@ impl NodeRuntime { } pub async fn run(&mut self) { - // TODO: Currently we still render the document after we submit the node graph execution request. This should be avoided in the future. + if self.editor_api.application_io.is_none() { + self.editor_api = WasmEditorApi { + application_io: Some(WasmApplicationIo::new().await.into()), + font_cache: self.editor_api.font_cache.clone(), + node_graph_message_sender: Box::new(self.sender.clone()), + editor_preferences: Box::new(self.editor_preferences.clone()), + } + .into(); + } let mut font = None; let mut preferences = None; @@ -232,16 +240,6 @@ impl NodeRuntime { } async fn update_network(&mut self, graph: NodeNetwork) -> Result<(), String> { - if self.editor_api.application_io.is_none() { - self.editor_api = WasmEditorApi { - application_io: Some(WasmApplicationIo::new().await.into()), - font_cache: self.editor_api.font_cache.clone(), - node_graph_message_sender: Box::new(self.sender.clone()), - editor_preferences: Box::new(self.editor_preferences.clone()), - } - .into(); - } - let scoped_network = wrap_network_in_scope(graph, self.editor_api.clone()); self.monitor_nodes = scoped_network .recursive_nodes() diff --git a/node-graph/graph-craft/Cargo.toml b/node-graph/graph-craft/Cargo.toml index 85c75125..86fdafb9 100644 --- a/node-graph/graph-craft/Cargo.toml +++ b/node-graph/graph-craft/Cargo.toml @@ -43,6 +43,7 @@ tokio = { workspace = true, optional = true } web-sys = { workspace = true } js-sys = { workspace = true } wasm-bindgen = { workspace = true } +wasm-bindgen-futures = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # Workspace dependencies diff --git a/node-graph/graph-craft/src/wasm_application_io.rs b/node-graph/graph-craft/src/wasm_application_io.rs index 3c4a4651..6e477d30 100644 --- a/node-graph/graph-craft/src/wasm_application_io.rs +++ b/node-graph/graph-craft/src/wasm_application_io.rs @@ -1,7 +1,6 @@ use dyn_any::StaticType; use graphene_core::application_io::SurfaceHandleFrame; use graphene_core::application_io::{ApplicationError, ApplicationIo, ResourceFuture, SurfaceHandle, SurfaceId}; -#[cfg(feature = "wgpu")] use wgpu_executor::WgpuExecutor; #[cfg(target_arch = "wasm32")] @@ -34,9 +33,19 @@ pub struct WasmApplicationIo { pub resources: HashMap>, } +static WGPU_AVAILABLE: std::sync::atomic::AtomicI8 = std::sync::atomic::AtomicI8::new(-1); + +pub fn wgpu_available() -> Option { + match WGPU_AVAILABLE.load(::std::sync::atomic::Ordering::SeqCst) { + -1 => None, + 0 => Some(false), + _ => Some(true), + } +} + impl WasmApplicationIo { pub async fn new() -> Self { - #[cfg(all(feature = "wgpu", target_arch = "wasm32"))] + #[cfg(target_arch = "wasm32")] let executor = if let Some(gpu) = web_sys::window().map(|w| w.navigator().gpu()) { let request_adapter = || { let request_adapter = js_sys::Reflect::get(&gpu, &wasm_bindgen::JsValue::from_str("requestAdapter")).ok()?; @@ -51,8 +60,9 @@ impl WasmApplicationIo { } else { None }; - #[cfg(all(feature = "wgpu", not(target_arch = "wasm32")))] + #[cfg(not(target_arch = "wasm32"))] let executor = WgpuExecutor::new().await; + WGPU_AVAILABLE.store(executor.is_some() as i8, ::std::sync::atomic::Ordering::SeqCst); let mut io = Self { #[cfg(target_arch = "wasm32")] ids: AtomicU64::new(0),