diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs index ac7f1f1ea7..b33bac64b3 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs @@ -4439,15 +4439,14 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc")), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::CreateGpuSurfaceNode")), skip_deduplication: true, ..Default::default() }, DocumentNode { - manual_composition: Some(concrete!(Footprint)), + manual_composition: Some(concrete!(())), inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")), + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")), ..Default::default() }, // TODO: Add conversion step diff --git a/node-graph/gcore/src/application_io.rs b/node-graph/gcore/src/application_io.rs index 0ff4d5ff1f..fa71fbfd7f 100644 --- a/node-graph/gcore/src/application_io.rs +++ b/node-graph/gcore/src/application_io.rs @@ -66,7 +66,7 @@ impl Size for web_sys::HtmlCanvasElement { impl From> for SurfaceFrame { fn from(x: SurfaceHandleFrame) -> Self { Self { - surface_id: x.surface_handle.surface_id, + surface_id: x.surface_handle.window_id, transform: x.transform, resolution: x.surface_handle.surface.size(), } @@ -75,9 +75,10 @@ impl From> for SurfaceFrame { #[derive(Clone, Debug, PartialEq, Eq)] pub struct SurfaceHandle { - pub surface_id: SurfaceId, + pub window_id: SurfaceId, pub surface: Surface, } + // #[cfg(target_arch = "wasm32")] // unsafe impl Send for SurfaceHandle {} // #[cfg(target_arch = "wasm32")] @@ -131,8 +132,9 @@ pub type ResourceFuture = Pin, Applicat pub trait ApplicationIo { type Surface; type Executor; - fn create_surface(&self) -> SurfaceHandle; - fn destroy_surface(&self, surface_id: SurfaceId); + fn window(&self) -> Option>; + fn create_window(&self) -> SurfaceHandle; + fn destroy_window(&self, surface_id: SurfaceId); fn gpu_executor(&self) -> Option<&Self::Executor> { None } @@ -143,12 +145,16 @@ impl ApplicationIo for &T { type Surface = T::Surface; type Executor = T::Executor; - fn create_surface(&self) -> SurfaceHandle { - (**self).create_surface() + fn window(&self) -> Option> { + (**self).window() } - fn destroy_surface(&self, surface_id: SurfaceId) { - (**self).destroy_surface(surface_id) + fn create_window(&self) -> SurfaceHandle { + (**self).create_window() + } + + fn destroy_window(&self, surface_id: SurfaceId) { + (**self).destroy_window(surface_id) } fn gpu_executor(&self) -> Option<&T::Executor> { diff --git a/node-graph/gcore/src/graphic_element.rs b/node-graph/gcore/src/graphic_element.rs index 6b714d5036..1842b83100 100644 --- a/node-graph/gcore/src/graphic_element.rs +++ b/node-graph/gcore/src/graphic_element.rs @@ -222,7 +222,7 @@ impl From for GraphicElement { } impl From>> for GraphicElement { fn from(surface: alloc::sync::Arc>) -> Self { - let surface_id = surface.surface_handle.surface_id; + let surface_id = surface.surface_handle.window_id; let transform = surface.transform; GraphicElement::Surface(SurfaceFrame { surface_id, @@ -236,7 +236,7 @@ impl From>> for GraphicEl } impl From> for GraphicElement { fn from(surface: SurfaceHandleFrame) -> Self { - let surface_id = surface.surface_handle.surface_id; + let surface_id = surface.surface_handle.window_id; let transform = surface.transform; GraphicElement::Surface(SurfaceFrame { surface_id, diff --git a/node-graph/gcore/src/memo.rs b/node-graph/gcore/src/memo.rs index 6504c4a588..2fdc1e8031 100644 --- a/node-graph/gcore/src/memo.rs +++ b/node-graph/gcore/src/memo.rs @@ -1,36 +1,40 @@ use crate::{Node, WasmNotSend}; -use core::future::Future; -use core::ops::Deref; -use std::sync::Mutex; + +use dyn_any::DynFuture; #[cfg(feature = "alloc")] use alloc::sync::Arc; -use dyn_any::DynFuture; +use core::future::Future; +use core::ops::Deref; +use std::hash::DefaultHasher; +use std::sync::Mutex; /// Caches the output of a given Node and acts as a proxy #[derive(Default)] pub struct MemoNode { - cache: Arc>>, + cache: Arc>>, node: CachedNode, } -impl<'i, 'o: 'i, T: 'i + Clone + 'o + WasmNotSend, CachedNode: 'i> Node<'i, ()> for MemoNode +impl<'i, 'o: 'i, I: Hash + 'i, T: 'i + Clone + 'o + WasmNotSend, CachedNode: 'i> Node<'i, I> for MemoNode where - CachedNode: for<'any_input> Node<'any_input, ()>, - for<'a> >::Output: core::future::Future + WasmNotSend, + CachedNode: for<'any_input> Node<'any_input, I>, + for<'a> >::Output: core::future::Future + WasmNotSend, { // TODO: This should return a reference to the cached cached_value // but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty accurate xD type Output = DynFuture<'i, T>; - fn eval(&'i self, input: ()) -> Self::Output { - if let Some(cached_value) = self.cache.lock().as_ref().unwrap().deref() { - let data = cached_value.clone(); + fn eval(&'i self, input: I) -> Self::Output { + let mut hasher = DefaultHasher::new(); + input.hash(&mut hasher); + let hash = hasher.finish(); + if let Some(data) = self.cache.lock().as_ref().unwrap().as_ref().and_then(|data| (data.0 == hash).then_some(data.1.clone())) { Box::pin(async move { data }) } else { let fut = self.node.eval(input); let cache = self.cache.clone(); Box::pin(async move { let value = fut.await; - *cache.lock().unwrap() = Some(value.clone()); + *cache.lock().unwrap() = Some((hash, value.clone())); value }) } diff --git a/node-graph/graph-craft/Cargo.toml b/node-graph/graph-craft/Cargo.toml index 86fdafb980..73dd175bb9 100644 --- a/node-graph/graph-craft/Cargo.toml +++ b/node-graph/graph-craft/Cargo.toml @@ -9,6 +9,7 @@ default = ["dealloc_nodes"] serde = ["dep:serde", "graphene-core/serde", "glam/serde", "bezier-rs/serde"] dealloc_nodes = [] wgpu = [] +ci = [] tokio = ["dep:tokio"] [dependencies] diff --git a/node-graph/graph-craft/src/wasm_application_io.rs b/node-graph/graph-craft/src/wasm_application_io.rs index 6e477d3053..42909e76c6 100644 --- a/node-graph/graph-craft/src/wasm_application_io.rs +++ b/node-graph/graph-craft/src/wasm_application_io.rs @@ -22,14 +22,49 @@ use web_sys::window; #[cfg(target_arch = "wasm32")] use web_sys::HtmlCanvasElement; +#[derive(Debug)] +struct WindowWrapper { + #[cfg(target_arch = "wasm32")] + window: SurfaceHandle, + #[cfg(not(target_arch = "wasm32"))] + window: SurfaceHandle>, +} + +#[cfg(target_arch = "wasm32")] +impl Drop for WindowWrapper { + fn drop(&mut self) { + let window = window().expect("should have a window in this context"); + let window = Object::from(window); + + let image_canvases_key = JsValue::from_str("imageCanvases"); + + let wrapper = || { + if let Ok(canvases) = Reflect::get(&window, &image_canvases_key) { + // Convert key and value to JsValue + let js_key = JsValue::from_str(format!("canvas{}", self.window.window_id).as_str()); + + // Use Reflect API to set property + Reflect::delete_property(&canvases.into(), &js_key)?; + } + Ok::<_, JsValue>(()) + }; + + wrapper().expect("should be able to set canvas in global scope") + } +} + +#[cfg(target_arch = "wasm32")] +unsafe impl Sync for WindowWrapper {} +#[cfg(target_arch = "wasm32")] +unsafe impl Send for WindowWrapper {} + #[derive(Debug, Default)] pub struct WasmApplicationIo { #[cfg(target_arch = "wasm32")] ids: AtomicU64, #[cfg(feature = "wgpu")] pub(crate) gpu_executor: Option, - // #[cfg(not(target_arch = "wasm32"))] - // windows: Mutex>>, + windows: Vec, pub resources: HashMap>, } @@ -68,10 +103,14 @@ impl WasmApplicationIo { ids: AtomicU64::new(0), #[cfg(feature = "wgpu")] gpu_executor: executor, - // #[cfg(not(target_arch = "wasm32"))] - // windows: Vec::new().into(), + windows: Vec::new().into(), resources: HashMap::new(), }; + #[cfg(not(feature = "ci"))] + let window = io.create_window(); + #[cfg(not(feature = "ci"))] + io.windows.push(WindowWrapper { window }); + io.resources.insert("null".to_string(), Arc::from(include_bytes!("null.png").to_vec())); io } @@ -99,14 +138,14 @@ impl ApplicationIo for WasmApplicationIo { #[cfg(target_arch = "wasm32")] type Surface = HtmlCanvasElement; #[cfg(not(target_arch = "wasm32"))] - type Surface = winit::window::Window; + type Surface = Arc; #[cfg(feature = "wgpu")] type Executor = WgpuExecutor; #[cfg(not(feature = "wgpu"))] type Executor = (); #[cfg(target_arch = "wasm32")] - fn create_surface(&self) -> SurfaceHandle { + fn create_window(&self) -> SurfaceHandle { let wrapper = || { let document = window().expect("should have a window in this context").document().expect("window should have a document"); @@ -133,7 +172,7 @@ impl ApplicationIo for WasmApplicationIo { // Use Reflect API to set property Reflect::set(&canvases, &js_key, &js_value)?; Ok::<_, JsValue>(SurfaceHandle { - surface_id: graphene_core::SurfaceId(id), + window_id: graphene_core::SurfaceId(id), surface: canvas, }) }; @@ -141,7 +180,7 @@ impl ApplicationIo for WasmApplicationIo { wrapper().expect("should be able to set canvas in global scope") } #[cfg(not(target_arch = "wasm32"))] - fn create_surface(&self) -> SurfaceHandle { + fn create_window(&self) -> SurfaceHandle { #[cfg(feature = "wayland")] use winit::platform::wayland::EventLoopBuilderExtWayland; @@ -156,13 +195,13 @@ impl ApplicationIo for WasmApplicationIo { .unwrap(); // self.windows.lock().as_mut().unwrap().push(window.clone()); SurfaceHandle { - surface_id: SurfaceId(window.id().into()), - surface: window, + window_id: SurfaceId(window.id().into()), + surface: Arc::new(window), } } #[cfg(target_arch = "wasm32")] - fn destroy_surface(&self, surface_id: SurfaceId) { + fn destroy_window(&self, surface_id: SurfaceId) { let window = window().expect("should have a window in this context"); let window = Object::from(window); @@ -183,7 +222,7 @@ impl ApplicationIo for WasmApplicationIo { } #[cfg(not(target_arch = "wasm32"))] - fn destroy_surface(&self, _surface_id: SurfaceId) {} + fn destroy_window(&self, _surface_id: SurfaceId) {} #[cfg(feature = "wgpu")] fn gpu_executor(&self) -> Option<&Self::Executor> { @@ -226,6 +265,10 @@ impl ApplicationIo for WasmApplicationIo { _ => Err(ApplicationError::NotFound), } } + + fn window(&self) -> Option> { + self.windows.iter().next().map(|wrapper| wrapper.window.clone()) + } } pub type WasmSurfaceHandle = SurfaceHandle; diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index 7f1d9f4520..834ec28cb7 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -28,7 +28,7 @@ pub struct CreateSurfaceNode {} #[node_macro::node_fn(CreateSurfaceNode)] async fn create_surface_node<'a: 'input>(editor: &'a WasmEditorApi) -> Arc { - Arc::new(editor.application_io.as_ref().unwrap().create_surface()) + Arc::new(editor.application_io.as_ref().unwrap().create_window()) } #[cfg(target_arch = "wasm32")] @@ -207,7 +207,7 @@ async fn render_node<'a: 'input, T: 'input + GraphicElementRendered + WasmNotSen render_config: RenderConfig, editor_api: &'a WasmEditorApi, data: impl Node, - _surface_handle: impl Node>, + _surface_handle: impl Node<(), Output = Option>, ) -> RenderOutput { let footprint = render_config.viewport; @@ -216,7 +216,7 @@ async fn render_node<'a: 'input, T: 'input + GraphicElementRendered + WasmNotSen let data = self.data.eval(footprint).await; #[cfg(all(feature = "vello", target_arch = "wasm32"))] - let surface_handle = self._surface_handle.eval(footprint).await; + let surface_handle = self._surface_handle.eval(()).await; let use_vello = editor_api.editor_preferences.use_vello(); #[cfg(all(feature = "vello", target_arch = "wasm32"))] let use_vello = use_vello && surface_handle.is_some(); diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 457449b0f3..5a9a347d73 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -382,7 +382,7 @@ fn node_registry() -> HashMap, input: Arc, output: Vec, params: [&WgpuExecutor, ()]), #[cfg(feature = "gpu")] - async_node!(wgpu_executor::CreateGpuSurfaceNode<_>, input: Footprint, output: Option, params: [&WasmEditorApi]), + async_node!(wgpu_executor::CreateGpuSurfaceNode, input: &WasmEditorApi, output: Option, params: []), #[cfg(feature = "gpu")] async_node!(wgpu_executor::RenderTextureNode<_, _, _>, input: Footprint, output: graphene_std::SurfaceFrame, fn_params: [Footprint => ShaderInputFrame, () => Option, () =>&WgpuExecutor]), #[cfg(feature = "gpu")] @@ -617,6 +617,21 @@ fn node_registry() -> HashMap, input: (), output: wgpu_executor::WindowHandle, params: [wgpu_executor::WindowHandle]), async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: graphene_std::SurfaceFrame, params: [graphene_std::SurfaceFrame]), async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: RenderOutput, params: [RenderOutput]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: Image, fn_params: [Footprint => Image]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: ImageFrame, fn_params: [Footprint => ImageFrame]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: QuantizationChannels, fn_params: [Footprint => QuantizationChannels]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: Vec, fn_params: [Footprint => Vec]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: Arc, fn_params: [Footprint => Arc]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: WindowHandle, fn_params: [Footprint => WindowHandle]), + #[cfg(feature = "gpu")] + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: ShaderInputFrame, fn_params: [Footprint => ShaderInputFrame]), + #[cfg(feature = "gpu")] + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: wgpu_executor::WgpuSurface, fn_params: [Footprint => wgpu_executor::WgpuSurface]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: Option, fn_params: [Footprint => Option]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: wgpu_executor::WindowHandle, fn_params: [Footprint => wgpu_executor::WindowHandle]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: graphene_std::SurfaceFrame, fn_params: [Footprint => graphene_std::SurfaceFrame]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: UVec2, output: graphene_std::SurfaceFrame, fn_params: [UVec2 => graphene_std::SurfaceFrame]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: RenderOutput, fn_params: [Footprint => RenderOutput]), async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: GraphicElement, fn_params: [Footprint => GraphicElement]), async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => GraphicGroup]), async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData]), @@ -632,17 +647,17 @@ fn node_registry() -> HashMap, input: Color, params: [QuantizationChannels]), register_node!(graphene_core::quantization::DeQuantizeNode<_>, input: PackedPixel, params: [QuantizationChannels]), register_node!(graphene_core::ops::CloneNode<_>, input: &QuantizationChannels, params: []), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ImageFrame, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => VectorData, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => GraphicGroup, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Artboard, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ArtboardGroup, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Option, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Vec, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => bool, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f32, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f64, Footprint => Option]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => String, Footprint => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ImageFrame, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => VectorData, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => GraphicGroup, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Artboard, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ArtboardGroup, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Option, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Vec, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => bool, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f32, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f64, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => String, () => Option]), #[cfg(target_arch = "wasm32")] async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), #[cfg(target_arch = "wasm32")] diff --git a/node-graph/wgpu-executor/src/lib.rs b/node-graph/wgpu-executor/src/lib.rs index 8b78944ee8..3ee4faa62a 100644 --- a/node-graph/wgpu-executor/src/lib.rs +++ b/node-graph/wgpu-executor/src/lib.rs @@ -123,7 +123,7 @@ pub struct Surface { #[cfg(target_arch = "wasm32")] pub type Window = HtmlCanvasElement; #[cfg(not(target_arch = "wasm32"))] -pub type Window = winit::window::Window; +pub type Window = Arc; unsafe impl StaticType for Surface { type Static = Surface; @@ -509,22 +509,8 @@ impl WgpuExecutor { let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Canvas(canvas.surface))?; let resolution = resolution.unwrap_or(UVec2::new(1920, 1080)); - // let surface_caps = surface.get_capabilities(&self.context.adapter); - // let surface_format = wgpu::TextureFormat::Rgba16Float; - // let config = wgpu::SurfaceConfiguration { - // usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - // format: surface_format, - // width: 1920, - // height: 1080, - // present_mode: surface_caps.present_modes[0], - // alpha_mode: surface_caps.alpha_modes[0], - // view_formats: vec![], - // desired_maximum_frame_latency: 2, - // }; - // surface.configure(&self.context.device, &config); - // self.surface_config.set(Some(config)); Ok(SurfaceHandle { - surface_id: canvas.surface_id, + window_id: canvas.window_id, surface: Surface { inner: surface, resolution }, }) } @@ -534,24 +520,8 @@ impl WgpuExecutor { let resolution = resolution.unwrap_or(UVec2 { x: size.width, y: size.height }); let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Window(Box::new(window.surface)))?; - let surface_caps = surface.get_capabilities(&self.context.adapter); - println!("{surface_caps:?}"); - let surface_format = wgpu::TextureFormat::Rgba16Float; - let _config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width: resolution.x, - height: resolution.y, - present_mode: surface_caps.present_modes[0], - alpha_mode: surface_caps.alpha_modes[0], - view_formats: vec![], - desired_maximum_frame_latency: 2, - }; - // surface.configure(&self.context.device, &config); - - let surface_id = window.surface_id; Ok(SurfaceHandle { - surface_id, + window_id: window.window_id, surface: Surface { inner: surface, resolution }, }) } @@ -929,17 +899,25 @@ async fn read_output_buffer_node<'a: 'input>(buffer: Arc, execu executor.read_output_buffer(buffer).await.unwrap() } -pub struct CreateGpuSurfaceNode { +pub type WindowHandle = Arc>; + +pub struct CreateGpuSurfaceNode; + +#[node_macro::node_fn(CreateGpuSurfaceNode)] +async fn create_gpu_surface<'a: 'input, Io: ApplicationIo + 'a + Send + Sync>(editor_api: &'a EditorApi) -> Option { + let canvas = editor_api.application_io.as_ref()?.window()?; + let executor = editor_api.application_io.as_ref()?.gpu_executor()?; + Some(Arc::new(executor.create_surface(canvas, None).ok()?)) +} +pub struct ConfigureGpuSurfaceNode { editor_api: EditorApi, } -pub type WindowHandle = Arc>; - -#[node_macro::node_fn(CreateGpuSurfaceNode)] -async fn create_gpu_surface<'a: 'input, Io: ApplicationIo + 'a + Send + Sync>(footprint: Footprint, editor_api: &'a EditorApi) -> Option { - let canvas = editor_api.application_io.as_ref()?.create_surface(); +#[node_macro::node_fn(ConfigureGpuSurfaceNode)] +async fn create_gpu_surface<'a: 'input, Io: ApplicationIo + 'a + Send + Sync>(resolution: UVec2, editor_api: &'a EditorApi) -> Option { + let canvas = editor_api.application_io.as_ref()?.create_window(); let executor = editor_api.application_io.as_ref()?.gpu_executor()?; - Some(Arc::new(executor.create_surface(canvas, Some(footprint.resolution)).ok()?)) + Some(Arc::new(executor.create_surface(canvas, Some(resolution)).ok()?)) } pub struct RenderTextureNode { @@ -957,7 +935,7 @@ pub struct ShaderInputFrame { #[node_macro::node_fn(RenderTextureNode)] async fn render_texture_node<'a: 'input>(footprint: Footprint, image: impl Node, surface: Option, executor: &'a WgpuExecutor) -> SurfaceFrame { let surface = surface.unwrap(); - let surface_id = surface.surface_id; + let surface_id = surface.window_id; let image = self.image.eval(footprint).await; let transform = image.transform;