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
})
}