diff --git a/src/app_handle.rs b/src/app_handle.rs index 8d569bff..2b65ccd3 100644 --- a/src/app_handle.rs +++ b/src/app_handle.rs @@ -137,12 +137,6 @@ impl ApplicationHandle { None => return, }; - // We only start reacting to events once the window is ready - // I.e. once the renderer has acquired the necessary GPU resources (if any) and is initialized. - if !window_handle.is_initialized() { - return; - } - let start = window_handle.profile.is_some().then(|| { let name = match event { WindowEvent::ActivationTokenDone { .. } => "ActivationTokenDone", diff --git a/src/context.rs b/src/context.rs index 492222ae..f4afa101 100644 --- a/src/context.rs +++ b/src/context.rs @@ -16,6 +16,7 @@ use web_time::{Duration, Instant}; use taffy::prelude::NodeId; use crate::animate::{AnimStateKind, RepeatMode}; +use crate::renderer::Renderer; use crate::style::DisplayProp; use crate::view_state::IsHiddenState; use crate::{ @@ -1194,13 +1195,20 @@ impl<'a> PaintCx<'a> { // TODO: should this be private? pub enum PaintState { + /// The renderer is not yet initialized. This state is used to wait for the GPU resources to be acquired. PendingGpuResources { window: Arc, rx: crossbeam::channel::Receiver>, - scale: f64, - size: Size, font_embolden: f32, + /// This field holds an instance of `Renderer::Uninitialized` until the GPU resources are acquired, + /// which will be returned in `PaintState::renderer` and `PaintState::renderer_mut`. + /// All calls to renderer methods will be no-ops until the renderer is initialized. + /// + /// Previously, `PaintState::renderer` and `PaintState::renderer_mut` would panic if called when the renderer was uninitialized. + /// However, this turned out to be hard to handle properly and led to panics, especially since the rest of the application code can't control when the renderer is initialized. + renderer: crate::renderer::Renderer>, }, + /// The renderer is initialized and ready to paint. Initialized { renderer: crate::renderer::Renderer>, }, @@ -1216,10 +1224,9 @@ impl PaintState { ) -> Self { Self::PendingGpuResources { window, - scale, - size, rx, font_embolden, + renderer: Renderer::Uninitialized { scale, size }, } } @@ -1227,17 +1234,16 @@ impl PaintState { if let PaintState::PendingGpuResources { window, rx, - scale, - size, font_embolden, + renderer, } = self { let gpu_resources = rx.recv().unwrap().unwrap(); let renderer = crate::renderer::Renderer::new( window.clone(), gpu_resources, - *scale, - *size, + renderer.scale(), + renderer.size(), *font_embolden, ); *self = PaintState::Initialized { renderer }; @@ -1248,9 +1254,7 @@ impl PaintState { pub(crate) fn renderer(&self) -> &crate::renderer::Renderer> { match self { - PaintState::PendingGpuResources { .. } => { - panic!("Tried to access renderer before it was initialized") - } + PaintState::PendingGpuResources { renderer, .. } => renderer, PaintState::Initialized { renderer } => renderer, } } @@ -1259,9 +1263,7 @@ impl PaintState { &mut self, ) -> &mut crate::renderer::Renderer> { match self { - PaintState::PendingGpuResources { .. } => { - panic!("Tried to access renderer before it was initialized") - } + PaintState::PendingGpuResources { renderer, .. } => renderer, PaintState::Initialized { renderer } => renderer, } } diff --git a/src/renderer.rs b/src/renderer.rs index 4b2606dc..c71759a4 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -60,6 +60,12 @@ use peniko::BrushRef; pub enum Renderer { Vger(VgerRenderer), TinySkia(TinySkiaRenderer), + /// Uninitialized renderer, used to allow the renderer to be created lazily + /// All operations on this renderer are no-ops + Uninitialized { + scale: f64, + size: Size, + }, } impl Renderer { @@ -118,6 +124,7 @@ impl Renderer { match self { Renderer::Vger(r) => r.resize(size.width as u32, size.height as u32, scale), Renderer::TinySkia(r) => r.resize(size.width as u32, size.height as u32, scale), + Renderer::Uninitialized { .. } => {} } } @@ -125,6 +132,11 @@ impl Renderer { match self { Renderer::Vger(r) => r.set_scale(scale), Renderer::TinySkia(r) => r.set_scale(scale), + Renderer::Uninitialized { + scale: old_scale, .. + } => { + *old_scale = scale; + } } } @@ -132,6 +144,15 @@ impl Renderer { match self { Renderer::Vger(r) => r.scale(), Renderer::TinySkia(r) => r.scale(), + Renderer::Uninitialized { scale, .. } => *scale, + } + } + + pub fn size(&self) -> Size { + match self { + Renderer::Vger(r) => r.size(), + Renderer::TinySkia(r) => r.size(), + Renderer::Uninitialized { size, .. } => *size, } } } @@ -145,6 +166,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(r) => { r.begin(capture); } + Renderer::Uninitialized { .. } => {} } } @@ -156,6 +178,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.clip(shape); } + Renderer::Uninitialized { .. } => {} } } @@ -167,6 +190,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.clear_clip(); } + Renderer::Uninitialized { .. } => {} } } @@ -178,6 +202,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.stroke(shape, brush, width); } + Renderer::Uninitialized { .. } => {} } } @@ -194,6 +219,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.fill(path, brush, blur_radius); } + Renderer::Uninitialized { .. } => {} } } @@ -205,6 +231,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.draw_text(layout, pos); } + Renderer::Uninitialized { .. } => {} } } @@ -216,6 +243,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.draw_img(img, rect); } + Renderer::Uninitialized { .. } => {} } } @@ -232,6 +260,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.draw_svg(svg, rect, brush); } + Renderer::Uninitialized { .. } => {} } } @@ -243,6 +272,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.transform(transform); } + Renderer::Uninitialized { .. } => {} } } @@ -254,6 +284,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.set_z_index(z_index); } + Renderer::Uninitialized { .. } => {} } } @@ -261,6 +292,7 @@ impl floem_renderer::Renderer for Renderer { match self { Renderer::Vger(r) => r.finish(), Renderer::TinySkia(r) => r.finish(), + Renderer::Uninitialized { .. } => None, } } } diff --git a/src/window_handle.rs b/src/window_handle.rs index 0aedbf6e..055fa0f7 100644 --- a/src/window_handle.rs +++ b/src/window_handle.rs @@ -192,10 +192,6 @@ impl WindowHandle { self.render_frame(); } - pub(crate) fn is_initialized(&self) -> bool { - matches!(self.paint_state, PaintState::Initialized { .. }) - } - pub fn event(&mut self, event: Event) { set_current_view(self.id); let event = event.scale(self.app_state.scale); diff --git a/tiny_skia/src/lib.rs b/tiny_skia/src/lib.rs index b986193e..b1461894 100644 --- a/tiny_skia/src/lib.rs +++ b/tiny_skia/src/lib.rs @@ -8,7 +8,7 @@ use floem_renderer::tiny_skia::{ use floem_renderer::Img; use floem_renderer::Renderer; use image::DynamicImage; -use peniko::kurbo::PathEl; +use peniko::kurbo::{PathEl, Size}; use peniko::{ kurbo::{Affine, Point, Rect, Shape}, BrushRef, Color, GradientKind, @@ -115,6 +115,10 @@ impl f64 { self.scale } + + pub fn size(&self) -> Size { + Size::new(self.pixmap.width() as f64, self.pixmap.height() as f64) + } } fn to_color(color: Color) -> tiny_skia::Color { diff --git a/vger/src/lib.rs b/vger/src/lib.rs index 92904af3..9d915fbe 100644 --- a/vger/src/lib.rs +++ b/vger/src/lib.rs @@ -9,6 +9,7 @@ use floem_renderer::text::{CacheKey, TextLayout}; use floem_renderer::{tiny_skia, Img, Renderer}; use floem_vger_rs::{Image, PaintIndex, PixelFormat, Vger}; use image::{DynamicImage, EncodableLayout, RgbaImage}; +use peniko::kurbo::Size; use peniko::{ kurbo::{Affine, Point, Rect, Shape}, BrushRef, Color, GradientKind, @@ -117,6 +118,10 @@ impl VgerRenderer { pub fn scale(&self) -> f64 { self.scale } + + pub fn size(&self) -> Size { + Size::new(self.config.width as f64, self.config.height as f64) + } } impl VgerRenderer {