Restructure window state management and fix Vello canvas not resizing with viewport (#1900)

* Restructure window state management

* Disable window creation on ci

* Code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert
2024-08-06 08:18:04 +02:00
committed by GitHub
parent 5474a22b2e
commit f21c8c1b17
9 changed files with 140 additions and 94 deletions

View File

@@ -66,7 +66,7 @@ impl Size for web_sys::HtmlCanvasElement {
impl<S: Size> From<SurfaceHandleFrame<S>> for SurfaceFrame {
fn from(x: SurfaceHandleFrame<S>) -> 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<S: Size> From<SurfaceHandleFrame<S>> for SurfaceFrame {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SurfaceHandle<Surface> {
pub surface_id: SurfaceId,
pub window_id: SurfaceId,
pub surface: Surface,
}
// #[cfg(target_arch = "wasm32")]
// unsafe impl<T: dyn_any::WasmNotSend> Send for SurfaceHandle<T> {}
// #[cfg(target_arch = "wasm32")]
@@ -131,8 +132,9 @@ pub type ResourceFuture = Pin<Box<dyn Future<Output = Result<Arc<[u8]>, Applicat
pub trait ApplicationIo {
type Surface;
type Executor;
fn create_surface(&self) -> SurfaceHandle<Self::Surface>;
fn destroy_surface(&self, surface_id: SurfaceId);
fn window(&self) -> Option<SurfaceHandle<Self::Surface>>;
fn create_window(&self) -> SurfaceHandle<Self::Surface>;
fn destroy_window(&self, surface_id: SurfaceId);
fn gpu_executor(&self) -> Option<&Self::Executor> {
None
}
@@ -143,12 +145,16 @@ impl<T: ApplicationIo> ApplicationIo for &T {
type Surface = T::Surface;
type Executor = T::Executor;
fn create_surface(&self) -> SurfaceHandle<T::Surface> {
(**self).create_surface()
fn window(&self) -> Option<SurfaceHandle<Self::Surface>> {
(**self).window()
}
fn destroy_surface(&self, surface_id: SurfaceId) {
(**self).destroy_surface(surface_id)
fn create_window(&self) -> SurfaceHandle<T::Surface> {
(**self).create_window()
}
fn destroy_window(&self, surface_id: SurfaceId) {
(**self).destroy_window(surface_id)
}
fn gpu_executor(&self) -> Option<&T::Executor> {

View File

@@ -222,7 +222,7 @@ impl From<SurfaceFrame> for GraphicElement {
}
impl From<alloc::sync::Arc<SurfaceHandleFrame<HtmlCanvasElement>>> for GraphicElement {
fn from(surface: alloc::sync::Arc<SurfaceHandleFrame<HtmlCanvasElement>>) -> 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<alloc::sync::Arc<SurfaceHandleFrame<HtmlCanvasElement>>> for GraphicEl
}
impl From<SurfaceHandleFrame<HtmlCanvasElement>> for GraphicElement {
fn from(surface: SurfaceHandleFrame<HtmlCanvasElement>) -> 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,

View File

@@ -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<T, CachedNode> {
cache: Arc<Mutex<Option<T>>>,
cache: Arc<Mutex<Option<(u64, T)>>>,
node: CachedNode,
}
impl<'i, 'o: 'i, T: 'i + Clone + 'o + WasmNotSend, CachedNode: 'i> Node<'i, ()> for MemoNode<T, CachedNode>
impl<'i, 'o: 'i, I: Hash + 'i, T: 'i + Clone + 'o + WasmNotSend, CachedNode: 'i> Node<'i, I> for MemoNode<T, CachedNode>
where
CachedNode: for<'any_input> Node<'any_input, ()>,
for<'a> <CachedNode as Node<'a, ()>>::Output: core::future::Future<Output = T> + WasmNotSend,
CachedNode: for<'any_input> Node<'any_input, I>,
for<'a> <CachedNode as Node<'a, I>>::Output: core::future::Future<Output = T> + 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
})
}

View File

@@ -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]

View File

@@ -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<HtmlCanvasElement>,
#[cfg(not(target_arch = "wasm32"))]
window: SurfaceHandle<Arc<winit::window::Window>>,
}
#[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<WgpuExecutor>,
// #[cfg(not(target_arch = "wasm32"))]
// windows: Mutex<Vec<Arc<winit::window::Window>>>,
windows: Vec<WindowWrapper>,
pub resources: HashMap<String, Arc<[u8]>>,
}
@@ -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<winit::window::Window>;
#[cfg(feature = "wgpu")]
type Executor = WgpuExecutor;
#[cfg(not(feature = "wgpu"))]
type Executor = ();
#[cfg(target_arch = "wasm32")]
fn create_surface(&self) -> SurfaceHandle<Self::Surface> {
fn create_window(&self) -> SurfaceHandle<Self::Surface> {
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<Self::Surface> {
fn create_window(&self) -> SurfaceHandle<Self::Surface> {
#[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<SurfaceHandle<Self::Surface>> {
self.windows.iter().next().map(|wrapper| wrapper.window.clone())
}
}
pub type WasmSurfaceHandle = SurfaceHandle<wgpu_executor::Window>;

View File

@@ -28,7 +28,7 @@ pub struct CreateSurfaceNode {}
#[node_macro::node_fn(CreateSurfaceNode)]
async fn create_surface_node<'a: 'input>(editor: &'a WasmEditorApi) -> Arc<WasmSurfaceHandle> {
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<Footprint, Output = T>,
_surface_handle: impl Node<Footprint, Output = Option<wgpu_executor::WgpuSurface>>,
_surface_handle: impl Node<(), Output = Option<wgpu_executor::WgpuSurface>>,
) -> 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();

View File

@@ -382,7 +382,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
#[cfg(feature = "gpu")]
async_node!(wgpu_executor::ReadOutputBufferNode<_, _>, input: Arc<WgpuShaderInput>, output: Vec<u8>, params: [&WgpuExecutor, ()]),
#[cfg(feature = "gpu")]
async_node!(wgpu_executor::CreateGpuSurfaceNode<_>, input: Footprint, output: Option<wgpu_executor::WgpuSurface>, params: [&WasmEditorApi]),
async_node!(wgpu_executor::CreateGpuSurfaceNode, input: &WasmEditorApi, output: Option<wgpu_executor::WgpuSurface>, params: []),
#[cfg(feature = "gpu")]
async_node!(wgpu_executor::RenderTextureNode<_, _, _>, input: Footprint, output: graphene_std::SurfaceFrame, fn_params: [Footprint => ShaderInputFrame, () => Option<wgpu_executor::WgpuSurface>, () =>&WgpuExecutor]),
#[cfg(feature = "gpu")]
@@ -617,6 +617,21 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_core::memo::MemoNode<_, _>, 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<Color>, fn_params: [Footprint => Image<Color>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: ImageFrame<Color>, fn_params: [Footprint => ImageFrame<Color>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: QuantizationChannels, fn_params: [Footprint => QuantizationChannels]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: Vec<DVec2>, fn_params: [Footprint => Vec<DVec2>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Footprint, output: Arc<WasmSurfaceHandle>, fn_params: [Footprint => Arc<WasmSurfaceHandle>]),
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<wgpu_executor::WgpuSurface>, fn_params: [Footprint => Option<wgpu_executor::WgpuSurface>]),
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<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
register_node!(graphene_core::quantization::QuantizeNode<_>, 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<Color>, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => VectorData, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => GraphicGroup, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Artboard, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ArtboardGroup, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Option<Color>, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Vec<Color>, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => bool, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f32, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f64, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => String, Footprint => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ImageFrame<Color>, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => VectorData, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => GraphicGroup, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Artboard, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ArtboardGroup, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Option<Color>, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Vec<Color>, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => bool, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f32, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f64, () => Option<WgpuSurface>]),
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => String, () => Option<WgpuSurface>]),
#[cfg(target_arch = "wasm32")]
async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: VectorData, output: ImageFrame<Color>, params: [Footprint, Arc<WasmSurfaceHandle>]),
#[cfg(target_arch = "wasm32")]

View File

@@ -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<winit::window::Window>;
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<WgpuShaderInput>, execu
executor.read_output_buffer(buffer).await.unwrap()
}
pub struct CreateGpuSurfaceNode<EditorApi> {
pub type WindowHandle = Arc<SurfaceHandle<Window>>;
pub struct CreateGpuSurfaceNode;
#[node_macro::node_fn(CreateGpuSurfaceNode)]
async fn create_gpu_surface<'a: 'input, Io: ApplicationIo<Executor = WgpuExecutor, Surface = Window> + 'a + Send + Sync>(editor_api: &'a EditorApi<Io>) -> Option<WgpuSurface> {
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<EditorApi> {
editor_api: EditorApi,
}
pub type WindowHandle = Arc<SurfaceHandle<Window>>;
#[node_macro::node_fn(CreateGpuSurfaceNode)]
async fn create_gpu_surface<'a: 'input, Io: ApplicationIo<Executor = WgpuExecutor, Surface = Window> + 'a + Send + Sync>(footprint: Footprint, editor_api: &'a EditorApi<Io>) -> Option<WgpuSurface> {
let canvas = editor_api.application_io.as_ref()?.create_surface();
#[node_macro::node_fn(ConfigureGpuSurfaceNode)]
async fn create_gpu_surface<'a: 'input, Io: ApplicationIo<Executor = WgpuExecutor, Surface = Window> + 'a + Send + Sync>(resolution: UVec2, editor_api: &'a EditorApi<Io>) -> Option<WgpuSurface> {
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<Image, Surface, EditorApi> {
@@ -957,7 +935,7 @@ pub struct ShaderInputFrame {
#[node_macro::node_fn(RenderTextureNode)]
async fn render_texture_node<'a: 'input>(footprint: Footprint, image: impl Node<Footprint, Output = ShaderInputFrame>, surface: Option<WgpuSurface>, 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;