From acbd0d54043246f84cbd2faf7e49aee777c343d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20S=C3=BCberkr=C3=BCb?= Date: Tue, 1 Oct 2024 22:08:15 +0200 Subject: [PATCH 1/5] Add Uninitialized variant to Renderer Thereby we don't need to panic when PaintState is uninitialized. --- src/context.rs | 21 +++++++++------------ src/renderer.rs | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/context.rs b/src/context.rs index 492222ae..84169002 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::{ @@ -1197,9 +1198,9 @@ pub enum PaintState { PendingGpuResources { window: Arc, rx: crossbeam::channel::Receiver>, - scale: f64, - size: Size, font_embolden: f32, + size: Size, + renderer: crate::renderer::Renderer>, }, Initialized { renderer: crate::renderer::Renderer>, @@ -1216,10 +1217,10 @@ impl PaintState { ) -> Self { Self::PendingGpuResources { window, - scale, - size, rx, + size, font_embolden, + renderer: Renderer::Uninitialized { scale, size }, } } @@ -1227,16 +1228,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, + renderer.scale(), *size, *font_embolden, ); @@ -1248,9 +1249,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 +1258,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..35fbae54 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -60,6 +60,7 @@ use peniko::BrushRef; pub enum Renderer { Vger(VgerRenderer), TinySkia(TinySkiaRenderer), + Uninitialized { scale: f64, size: Size }, } impl Renderer { @@ -118,6 +119,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 +127,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 +139,7 @@ impl Renderer { match self { Renderer::Vger(r) => r.scale(), Renderer::TinySkia(r) => r.scale(), + Renderer::Uninitialized { scale, .. } => *scale, } } } @@ -145,6 +153,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(r) => { r.begin(capture); } + Renderer::Uninitialized { .. } => {} } } @@ -156,6 +165,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.clip(shape); } + Renderer::Uninitialized { .. } => {} } } @@ -167,6 +177,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.clear_clip(); } + Renderer::Uninitialized { .. } => {} } } @@ -178,6 +189,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.stroke(shape, brush, width); } + Renderer::Uninitialized { .. } => {} } } @@ -194,6 +206,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.fill(path, brush, blur_radius); } + Renderer::Uninitialized { .. } => {} } } @@ -205,6 +218,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.draw_text(layout, pos); } + Renderer::Uninitialized { .. } => {} } } @@ -216,6 +230,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.draw_img(img, rect); } + Renderer::Uninitialized { .. } => {} } } @@ -232,6 +247,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.draw_svg(svg, rect, brush); } + Renderer::Uninitialized { .. } => {} } } @@ -243,6 +259,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.transform(transform); } + Renderer::Uninitialized { .. } => {} } } @@ -254,6 +271,7 @@ impl floem_renderer::Renderer for Renderer { Renderer::TinySkia(v) => { v.set_z_index(z_index); } + Renderer::Uninitialized { .. } => {} } } @@ -261,6 +279,7 @@ impl floem_renderer::Renderer for Renderer { match self { Renderer::Vger(r) => r.finish(), Renderer::TinySkia(r) => r.finish(), + Renderer::Uninitialized { .. } => None, } } } From 89635038d5163945dd5aae716b416da6da338063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20S=C3=BCberkr=C3=BCb?= Date: Tue, 1 Oct 2024 22:23:22 +0200 Subject: [PATCH 2/5] Remove now redundant is_initialized check --- src/app_handle.rs | 6 ------ src/window_handle.rs | 4 ---- 2 files changed, 10 deletions(-) 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/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); From 90f9a04d503bec1c6a4cfbc92d5a5e4c8bb2278f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20S=C3=BCberkr=C3=BCb?= Date: Tue, 1 Oct 2024 22:31:52 +0200 Subject: [PATCH 3/5] Make Renderer own the size --- src/context.rs | 5 +---- src/renderer.rs | 8 ++++++++ tiny_skia/src/lib.rs | 6 +++++- vger/src/lib.rs | 5 +++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/context.rs b/src/context.rs index 84169002..7aaadea1 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1199,7 +1199,6 @@ pub enum PaintState { window: Arc, rx: crossbeam::channel::Receiver>, font_embolden: f32, - size: Size, renderer: crate::renderer::Renderer>, }, Initialized { @@ -1218,7 +1217,6 @@ impl PaintState { Self::PendingGpuResources { window, rx, - size, font_embolden, renderer: Renderer::Uninitialized { scale, size }, } @@ -1228,7 +1226,6 @@ impl PaintState { if let PaintState::PendingGpuResources { window, rx, - size, font_embolden, renderer, } = self @@ -1238,7 +1235,7 @@ impl PaintState { window.clone(), gpu_resources, renderer.scale(), - *size, + renderer.size(), *font_embolden, ); *self = PaintState::Initialized { renderer }; diff --git a/src/renderer.rs b/src/renderer.rs index 35fbae54..bd603533 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -142,6 +142,14 @@ impl Renderer { 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, + } + } } impl floem_renderer::Renderer for Renderer { 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 { From e39704d34e2c8fc9274ca053618cb6a45046d8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20S=C3=BCberkr=C3=BCb?= Date: Tue, 1 Oct 2024 22:38:27 +0200 Subject: [PATCH 4/5] Add some doc comments --- src/context.rs | 8 ++++++++ src/renderer.rs | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/context.rs b/src/context.rs index 7aaadea1..a11d04be 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1195,12 +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 loaded. PendingGpuResources { window: Arc, rx: crossbeam::channel::Receiver>, font_embolden: f32, + /// This field holds an instance of `Renderer::Uninitialized` until the GPU resources are loaded, + /// 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>, }, diff --git a/src/renderer.rs b/src/renderer.rs index bd603533..c71759a4 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -60,7 +60,12 @@ use peniko::BrushRef; pub enum Renderer { Vger(VgerRenderer), TinySkia(TinySkiaRenderer), - Uninitialized { scale: f64, size: Size }, + /// 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 { From 71aa81a50f95607b823ca03d4aaf009e0439dd5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20S=C3=BCberkr=C3=BCb?= Date: Tue, 1 Oct 2024 22:41:04 +0200 Subject: [PATCH 5/5] Improve wording --- src/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context.rs b/src/context.rs index a11d04be..f4afa101 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1195,12 +1195,12 @@ 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 loaded. + /// 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>, font_embolden: f32, - /// This field holds an instance of `Renderer::Uninitialized` until the GPU resources are loaded, + /// 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. ///