From aa66848383fa5669b007c8f532f7a905d810bbad Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 23 Jul 2024 16:17:37 +1200 Subject: [PATCH] Move Scene to Renderer, scroll_offset to Document --- packages/blitz/src/renderer.rs | 41 ++++++++++----------- packages/blitz/src/renderer/render.rs | 51 ++++++++++++++++++++------- packages/dioxus-blitz/src/lib.rs | 11 +++--- packages/dioxus-blitz/src/window.rs | 5 +-- packages/dom/src/document.rs | 4 +++ 5 files changed, 69 insertions(+), 43 deletions(-) diff --git a/packages/blitz/src/renderer.rs b/packages/blitz/src/renderer.rs index 66873422..e2b41060 100644 --- a/packages/blitz/src/renderer.rs +++ b/packages/blitz/src/renderer.rs @@ -40,7 +40,9 @@ pub struct Renderer<'s, W, Doc: DocumentLike> { pub render_state: RenderState<'s, W>, + // Vello pub(crate) render_context: RenderContext, + pub(crate) scene: Scene, /// Our image cache // pub(crate) images: ImageCache, @@ -49,8 +51,6 @@ pub struct Renderer<'s, W, Doc: DocumentLike> { /// Whenever we encounter new fonts during parsing + mutations, this will become populated // pub(crate) fonts: FontCache, pub devtools: Devtools, - - scroll_offset: f64, mouse_pos: (f32, f32), } @@ -73,9 +73,9 @@ where Self { render_context, render_state: RenderState::Suspended(None), + scene: Scene::new(), dom, devtools: Default::default(), - scroll_offset: 0.0, mouse_pos: (0.0, 0.0), } } @@ -170,7 +170,7 @@ where }; let x = x / state.viewport.zoom(); - let y = (y - self.scroll_offset as f32) / state.viewport.zoom(); + let y = (y - self.dom.as_ref().scroll_offset as f32) / state.viewport.zoom(); // println!("Mouse move: ({}, {})", x, y); // println!("Unscaled: ({}, {})",); @@ -210,11 +210,11 @@ where // Invert scrolling on macos #[cfg(target_os = "macos")] { - self.scroll_offset += px; + self.dom.as_mut().scroll_offset += px; } #[cfg(not(target_os = "macos"))] { - self.scroll_offset -= px; + self.dom.as_mut().scroll_offset -= px; } self.clamp_scroll(); @@ -222,15 +222,11 @@ where /// Clamp scroll offset fn clamp_scroll(&mut self) { - let content_height = self.dom.as_ref().root_element().final_layout.size.height as f64; - let viewport_height = self - .dom - .as_mut() - .stylist_device() - .au_viewport_size() - .height - .to_f64_px(); - self.scroll_offset = self + let dom = self.dom.as_mut(); + let content_height = dom.root_element().final_layout.size.height as f64; + let viewport_height = dom.stylist_device().au_viewport_size().height.to_f64_px(); + + dom.scroll_offset = dom .scroll_offset .max(-(content_height - viewport_height)) .min(0.0); @@ -370,13 +366,10 @@ where } } - pub fn render(&mut self, scene: &mut Scene) { - self.generate_vello_scene(scene); - + pub fn render(&mut self) { let RenderState::Active(state) = &mut self.render_state else { return; }; - let surface_texture = match state.surface.surface.get_current_texture() { Ok(surface) => surface, // When resizing too aggresively, the surface can get outdated (another resize) before being rendered into @@ -393,12 +386,20 @@ where antialiasing_method: vello::AaConfig::Msaa16, }; + // Regenerate the vello scene + render::generate_vello_scene( + &mut self.scene, + self.dom.as_ref(), + state.viewport.scale_f64(), + self.devtools, + ); + state .renderer .render_to_surface( &device.device, &device.queue, - scene, + &self.scene, &surface_texture, &render_params, ) diff --git a/packages/blitz/src/renderer/render.rs b/packages/blitz/src/renderer/render.rs index 8802a6be..0fee9d2e 100644 --- a/packages/blitz/src/renderer/render.rs +++ b/packages/blitz/src/renderer/render.rs @@ -4,10 +4,13 @@ use crate::{ devtools::Devtools, util::{GradientSlice, StyloGradient, ToVelloColor}, }; -use blitz_dom::node::{TextBrush, TextInputData}; use blitz_dom::{ node::{NodeData, TextNodeData}, - DocumentLike, Node, + Node, +}; +use blitz_dom::{ + node::{TextBrush, TextInputData}, + Document, }; use html5ever::local_name; use image::{imageops::FilterType, DynamicImage}; @@ -41,9 +44,38 @@ use vello::{ }; use super::multicolor_rounded_rect::{Edge, ElementFrame}; -use super::{RenderState, Renderer}; -impl<'a, W: 'a, Doc: DocumentLike> Renderer<'a, W, Doc> { +/// Draw the current tree to current render surface +/// Eventually we'll want the surface itself to be passed into the render function, along with things like the viewport +/// +/// This assumes styles are resolved and layout is complete. +/// Make sure you do those before trying to render +pub fn generate_vello_scene( + scene: &mut Scene, + dom: &Document, + scale: f64, + devtool_config: Devtools, +) { + let generator = VelloSceneGenerator { + dom, + scale, + devtools: devtool_config, + scroll_offset: dom.scroll_offset, + }; + generator.generate_vello_scene(scene) +} + +/// A short-lived struct which holds a bunch of parameters for rendering a vello scene so +/// that we don't have to pass them down as parameters +pub struct VelloSceneGenerator<'dom> { + /// Input parameters (read only) for generating the Scene + dom: &'dom Document, + scale: f64, + devtools: Devtools, + scroll_offset: f64, +} + +impl<'dom> VelloSceneGenerator<'dom> { fn node_position(&self, node: usize, location: Point) -> (Layout, Point) { let layout = self.layout(node); let pos = location + Vec2::new(layout.location.x as f64, layout.location.y as f64); @@ -83,10 +115,7 @@ impl<'a, W: 'a, Doc: DocumentLike> Renderer<'a, W, Doc> { /// Renders a layout debugging overlay which visualises the content size, padding and border /// of the node with a transparent overlay. fn render_debug_overlay(&self, scene: &mut Scene, node_id: usize) { - let RenderState::Active(state) = &self.render_state else { - return; - }; - let scale = state.viewport.scale_f64(); + let scale = self.scale; let mut node = &self.dom.as_ref().tree()[node_id]; @@ -354,10 +383,6 @@ impl<'a, W: 'a, Doc: DocumentLike> Renderer<'a, W, Doc> { } fn element_cx<'w>(&'w self, element: &'w Node, location: Point) -> ElementCx { - let RenderState::Active(state) = &self.render_state else { - panic!("Renderer is not active"); - }; - let style = element .stylo_element_data .borrow() @@ -366,7 +391,7 @@ impl<'a, W: 'a, Doc: DocumentLike> Renderer<'a, W, Doc> { .unwrap_or(ComputedValues::initial_values().to_arc()); let (layout, pos) = self.node_position(element.id, location); - let scale = state.viewport.scale_f64(); + let scale = self.scale; // the bezpaths for every element are (potentially) cached (not yet, tbd) // By performing the transform, we prevent the cache from becoming invalid when the page shifts around diff --git a/packages/dioxus-blitz/src/lib.rs b/packages/dioxus-blitz/src/lib.rs index a9404719..49222b40 100644 --- a/packages/dioxus-blitz/src/lib.rs +++ b/packages/dioxus-blitz/src/lib.rs @@ -150,15 +150,14 @@ fn launch_with_window(window: View<'static, Doc>) { event_loop.set_control_flow(ControlFlow::Wait); let mut on_resume = || { + // Resume existing windows for (_, view) in windows.iter_mut() { view.resume(event_loop, &proxy, &rt); } - for view in pending_windows.iter_mut() { - view.resume(event_loop, &proxy, &rt); - } - - for window in pending_windows.drain(..) { + // Initialise pending windows + for mut window in pending_windows.drain(..) { + window.resume(event_loop, &proxy, &rt); let RenderState::Active(state) = &window.renderer.render_state else { continue; }; @@ -189,7 +188,7 @@ fn launch_with_window(window: View<'static, Doc>) { } => { if let Some(window) = windows.get_mut(&window_id) { window.renderer.dom.as_mut().resolve(); - window.renderer.render(&mut window.scene); + window.renderer.render(); }; } diff --git a/packages/dioxus-blitz/src/window.rs b/packages/dioxus-blitz/src/window.rs index a24be88e..06763a10 100644 --- a/packages/dioxus-blitz/src/window.rs +++ b/packages/dioxus-blitz/src/window.rs @@ -8,7 +8,6 @@ use wgpu::rwh::HasWindowHandle; use std::sync::Arc; use std::task::Waker; -use vello::Scene; use winit::dpi::LogicalSize; use winit::event::{ElementState, MouseButton}; use winit::event_loop::{ActiveEventLoop, EventLoopProxy}; @@ -26,7 +25,6 @@ struct State { pub(crate) struct View<'s, Doc: DocumentLike> { pub(crate) renderer: Renderer<'s, Window, Doc>, - pub(crate) scene: Scene, pub(crate) waker: Option, /// The state of the keyboard modifiers (ctrl, shift, etc). Winit/Tao don't track these for us so we /// need to store them in order to have access to them when processing keypress events @@ -40,7 +38,6 @@ impl<'a, Doc: DocumentLike> View<'a, Doc> { pub(crate) fn new(doc: Doc) -> Self { Self { renderer: Renderer::new(doc), - scene: Scene::new(), waker: None, keyboard_modifiers: Default::default(), #[cfg(any(feature = "accessibility", feature = "menu"))] @@ -362,7 +359,7 @@ impl<'a, Doc: DocumentLike> View<'a, Doc> { }; self.waker = Some(crate::waker::tao_waker(proxy, state.window.id())); - self.renderer.render(&mut self.scene); + self.renderer.render(); } pub fn suspend(&mut self) { diff --git a/packages/dom/src/document.rs b/packages/dom/src/document.rs index e4f9ea6d..8fe8fedc 100644 --- a/packages/dom/src/document.rs +++ b/packages/dom/src/document.rs @@ -94,6 +94,9 @@ pub struct Document { /// The node which is currently focussed (if any) pub(crate) focus_node_id: Option, + // TODO: move to nodes + pub scroll_offset: f64, + pub changed: HashSet, } @@ -127,6 +130,7 @@ impl Document { hover_node_id: None, focus_node_id: None, + scroll_offset: 0.0, changed: HashSet::new(), };