From 188db4da48954b95a3fe79bcd22689ffc3a661e0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 05:52:48 +0100 Subject: Draft support for dynamic custom renderer injection --- renderer/src/compositor.rs | 25 +++++++ renderer/src/custom.rs | 164 +++++++++++++++++++++++++++++++++++++++++ renderer/src/geometry.rs | 33 +++++++-- renderer/src/geometry/cache.rs | 9 +++ renderer/src/lib.rs | 74 ++++++++++++++++--- 5 files changed, 289 insertions(+), 16 deletions(-) create mode 100644 renderer/src/custom.rs (limited to 'renderer/src') diff --git a/renderer/src/compositor.rs b/renderer/src/compositor.rs index c23a814c..058fa36d 100644 --- a/renderer/src/compositor.rs +++ b/renderer/src/compositor.rs @@ -1,4 +1,5 @@ use crate::core::Color; +use crate::custom; use crate::graphics::compositor::{Information, SurfaceError, Window}; use crate::graphics::{Error, Viewport}; use crate::{Renderer, Settings}; @@ -10,12 +11,14 @@ pub enum Compositor { TinySkia(iced_tiny_skia::window::Compositor), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::window::Compositor), + Custom(Box), } pub enum Surface { TinySkia(iced_tiny_skia::window::Surface), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::window::Surface<'static>), + Custom(Box), } impl crate::graphics::Compositor for Compositor { @@ -56,6 +59,9 @@ impl crate::graphics::Compositor for Compositor { Compositor::Wgpu(compositor) => { Renderer::Wgpu(compositor.create_renderer()) } + Compositor::Custom(compositor) => { + Renderer::Custom(compositor.create_renderer()) + } } } @@ -73,6 +79,9 @@ impl crate::graphics::Compositor for Compositor { Self::Wgpu(compositor) => { Surface::Wgpu(compositor.create_surface(window, width, height)) } + Self::Custom(compositor) => Surface::Custom( + compositor.create_surface(Box::new(window), width, height), + ), } } @@ -90,6 +99,9 @@ impl crate::graphics::Compositor for Compositor { (Self::Wgpu(compositor), Surface::Wgpu(surface)) => { compositor.configure_surface(surface, width, height); } + (Self::Custom(compositor), Surface::Custom(surface)) => { + compositor.configure_surface(surface, width, height); + } #[allow(unreachable_patterns)] _ => panic!( "The provided surface is not compatible with the compositor." @@ -102,6 +114,7 @@ impl crate::graphics::Compositor for Compositor { Self::TinySkia(compositor) => compositor.fetch_information(), #[cfg(feature = "wgpu")] Self::Wgpu(compositor) => compositor.fetch_information(), + Self::Custom(compositor) => compositor.fetch_information(), } } @@ -144,6 +157,18 @@ impl crate::graphics::Compositor for Compositor { overlay, ) }), + + #[cfg(feature = "wgpu")] + ( + Self::Custom(compositor), + crate::Renderer::Custom(renderer), + Surface::Custom(surface), + ) => renderer.present( + surface.as_mut(), + viewport, + background_color, + compositor.as_mut(), + ), #[allow(unreachable_patterns)] _ => panic!( "The provided renderer or surface are not compatible \ diff --git a/renderer/src/custom.rs b/renderer/src/custom.rs new file mode 100644 index 00000000..680aa0b5 --- /dev/null +++ b/renderer/src/custom.rs @@ -0,0 +1,164 @@ +use crate::core::image; +use crate::core::renderer; +use crate::core::svg; +use crate::core::text::Text; +use crate::core::{ + Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, +}; +use crate::graphics::compositor; +use crate::graphics::text::{Editor, Paragraph}; +use crate::graphics::{Mesh, Viewport}; + +#[cfg(feature = "geometry")] +use crate::graphics::geometry::{self, Fill, Path, Stroke}; + +use std::borrow::Cow; + +pub trait Renderer { + fn draw_mesh(&mut self, mesh: Mesh); + + fn start_layer(&mut self); + + fn end_layer(&mut self, bounds: Rectangle); + + fn start_transformation(&mut self); + + fn end_transformation(&mut self, transformation: Transformation); + + fn fill_quad(&mut self, quad: renderer::Quad, background: Background); + + fn clear(&mut self); + + fn default_font(&self) -> Font; + + fn default_size(&self) -> Pixels; + + fn load_font(&mut self, bytes: Cow<'static, [u8]>); + + fn fill_paragraph( + &mut self, + paragraph: &Paragraph, + position: Point, + color: Color, + clip_bounds: Rectangle, + ); + + fn fill_editor( + &mut self, + editor: &Editor, + position: Point, + color: Color, + clip_bounds: Rectangle, + ); + + fn fill_text( + &mut self, + text: Text<'_, Font>, + position: Point, + color: Color, + clip_bounds: Rectangle, + ); + + fn measure_image(&self, handle: &image::Handle) -> Size; + + fn draw_image( + &mut self, + handle: image::Handle, + filter_method: image::FilterMethod, + bounds: Rectangle, + ); + + fn measure_svg(&self, handle: &svg::Handle) -> Size; + + fn draw_svg( + &mut self, + handle: crate::core::svg::Handle, + color: Option, + bounds: Rectangle, + ); + + #[cfg(feature = "geometry")] + fn new_frame(&self, size: Size) -> Box; + + #[cfg(feature = "geometry")] + fn draw_geometry(&mut self, geometry: Box); + + fn present( + &mut self, + surface: &mut dyn Surface, + viewport: &Viewport, + background_color: Color, + compositor: &mut dyn Compositor, + ) -> Result<(), compositor::SurfaceError>; +} + +#[cfg(feature = "geometry")] +pub trait Frame: std::any::Any { + fn new(&self, size: Size) -> Box; + + fn width(&self) -> f32; + + fn height(&self) -> f32; + + fn size(&self) -> Size; + + fn center(&self) -> Point; + + fn fill(&mut self, path: &Path, fill: Fill); + + fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: Fill); + + fn stroke<'a>(&mut self, path: &Path, stroke: Stroke<'a>); + + fn fill_text(&mut self, text: geometry::Text); + + fn translate(&mut self, translation: crate::core::Vector); + + fn rotate(&mut self, angle: crate::core::Radians); + + fn scale(&mut self, scale: f32); + + fn scale_nonuniform(&mut self, scale: crate::core::Vector); + + fn push_transform(&mut self); + + fn pop_transform(&mut self); + + fn clip(&mut self, frame: Box, origin: Point); + + fn into_geometry(self: Box) -> Box; +} + +#[cfg(feature = "geometry")] +pub trait Geometry: std::any::Any + std::fmt::Debug { + fn transform( + self: Box, + transformation: Transformation, + ) -> Box; + + fn cache(self: Box) -> std::sync::Arc; + + fn load(self: std::sync::Arc) -> Box; +} + +pub trait Compositor: std::any::Any { + fn create_renderer(&self) -> Box; + + fn create_surface( + &mut self, + window: Box, + width: u32, + height: u32, + ) -> Box; + + fn configure_surface( + &mut self, + surface: &mut Box, + width: u32, + height: u32, + ); + + fn fetch_information(&self) -> compositor::Information; +} + +pub trait Surface: std::any::Any {} diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs index 36435148..bf70c7fa 100644 --- a/renderer/src/geometry.rs +++ b/renderer/src/geometry.rs @@ -3,6 +3,7 @@ mod cache; pub use cache::Cache; use crate::core::{Point, Radians, Rectangle, Size, Transformation, Vector}; +use crate::custom; use crate::graphics::geometry::{Fill, Path, Stroke, Text}; use crate::Renderer; @@ -12,6 +13,7 @@ macro_rules! delegate { Self::TinySkia($name) => $body, #[cfg(feature = "wgpu")] Self::Wgpu($name) => $body, + Self::Custom($name) => $body, } }; } @@ -20,6 +22,7 @@ pub enum Geometry { TinySkia(iced_tiny_skia::Primitive), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::Primitive), + Custom(Box), } impl Geometry { @@ -32,6 +35,9 @@ impl Geometry { Self::Wgpu(primitive) => { Self::Wgpu(primitive.transform(transformation)) } + Self::Custom(geometry) => { + Self::Custom(geometry.transform(transformation)) + } } } } @@ -40,6 +46,7 @@ pub enum Frame { TinySkia(iced_tiny_skia::geometry::Frame), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::geometry::Frame), + Custom(Box), } impl Frame { @@ -52,6 +59,9 @@ impl Frame { Renderer::Wgpu(_) => { Frame::Wgpu(iced_wgpu::geometry::Frame::new(size)) } + Renderer::Custom(renderer) => { + Frame::Custom(renderer.new_frame(size)) + } } } @@ -82,7 +92,7 @@ impl Frame { /// Draws the given [`Path`] on the [`Frame`] by filling it with the /// provided style. pub fn fill(&mut self, path: &Path, fill: impl Into) { - delegate!(self, frame, frame.fill(path, fill)); + delegate!(self, frame, frame.fill(path, fill.into())); } /// Draws an axis-aligned rectangle given its top-left corner coordinate and @@ -93,13 +103,17 @@ impl Frame { size: Size, fill: impl Into, ) { - delegate!(self, frame, frame.fill_rectangle(top_left, size, fill)); + delegate!( + self, + frame, + frame.fill_rectangle(top_left, size, fill.into()) + ); } /// Draws the stroke of the given [`Path`] on the [`Frame`] with the /// provided style. pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>) { - delegate!(self, frame, frame.stroke(path, stroke)); + delegate!(self, frame, frame.stroke(path, stroke.into())); } /// Draws the characters of the given [`Text`] on the [`Frame`], filling @@ -116,7 +130,7 @@ impl Frame { /// Support for vectorial text is planned, and should address all these /// limitations. pub fn fill_text(&mut self, text: impl Into) { - delegate!(self, frame, frame.fill_text(text)); + delegate!(self, frame, frame.fill_text(text.into())); } /// Stores the current transform of the [`Frame`] and executes the given @@ -155,6 +169,7 @@ impl Frame { Self::Wgpu(_) => { Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size())) } + Self::Custom(frame) => Self::Custom(frame.new(region.size())), }; let result = f(&mut frame); @@ -169,6 +184,9 @@ impl Frame { (Self::Wgpu(target), Self::Wgpu(frame)) => { target.clip(frame, origin); } + (Self::Custom(target), Self::Custom(frame)) => { + target.clip(frame, origin); + } #[allow(unreachable_patterns)] _ => unreachable!(), }; @@ -185,19 +203,19 @@ impl Frame { /// Applies a rotation in radians to the current transform of the [`Frame`]. #[inline] pub fn rotate(&mut self, angle: impl Into) { - delegate!(self, frame, frame.rotate(angle)); + delegate!(self, frame, frame.rotate(angle.into())); } /// Applies a uniform scaling to the current transform of the [`Frame`]. #[inline] pub fn scale(&mut self, scale: impl Into) { - delegate!(self, frame, frame.scale(scale)); + delegate!(self, frame, frame.scale(scale.into())); } /// Applies a non-uniform scaling to the current transform of the [`Frame`]. #[inline] pub fn scale_nonuniform(&mut self, scale: impl Into) { - delegate!(self, frame, frame.scale_nonuniform(scale)); + delegate!(self, frame, frame.scale_nonuniform(scale.into())); } pub fn into_geometry(self) -> Geometry { @@ -205,6 +223,7 @@ impl Frame { Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()), #[cfg(feature = "wgpu")] Self::Wgpu(frame) => Geometry::Wgpu(frame.into_primitive()), + Self::Custom(frame) => Geometry::Custom(frame.into_geometry()), } } } diff --git a/renderer/src/geometry/cache.rs b/renderer/src/geometry/cache.rs index 3aff76b9..6a43ddb6 100644 --- a/renderer/src/geometry/cache.rs +++ b/renderer/src/geometry/cache.rs @@ -1,4 +1,5 @@ use crate::core::Size; +use crate::custom; use crate::geometry::{Frame, Geometry}; use crate::Renderer; @@ -29,6 +30,7 @@ enum Internal { TinySkia(Arc), #[cfg(feature = "wgpu")] Wgpu(Arc), + Custom(Arc), } impl Cache { @@ -82,6 +84,9 @@ impl Cache { content: primitive.clone(), }); } + Internal::Custom(geometry) => { + return Geometry::Custom(geometry.clone().load()) + } } } } @@ -100,6 +105,9 @@ impl Cache { Geometry::Wgpu(primitive) => { Internal::Wgpu(Arc::new(primitive)) } + Geometry::Custom(geometry) => { + Internal::Custom(geometry.cache()) + } } }; @@ -120,6 +128,7 @@ impl Cache { content: primitive, }) } + Internal::Custom(geometry) => Geometry::Custom(geometry.load()), } } } diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 757c264d..70741356 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -5,6 +5,7 @@ pub use iced_wgpu as wgpu; pub mod compositor; +pub mod custom; #[cfg(feature = "geometry")] pub mod geometry; @@ -38,6 +39,7 @@ pub enum Renderer { TinySkia(iced_tiny_skia::Renderer), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::Renderer), + Custom(Box), } macro_rules! delegate { @@ -46,6 +48,7 @@ macro_rules! delegate { Self::TinySkia($name) => $body, #[cfg(feature = "wgpu")] Self::Wgpu($name) => $body, + Self::Custom($name) => $body, } }; } @@ -62,6 +65,9 @@ impl Renderer { iced_wgpu::primitive::Custom::Mesh(mesh), )); } + Self::Custom(renderer) => { + renderer.draw_mesh(mesh); + } } } } @@ -96,6 +102,18 @@ impl core::Renderer for Renderer { _ => unreachable!(), } } + Self::Custom(renderer) => { + renderer.start_layer(); + + f(self); + + match self { + Self::Custom(renderer) => { + renderer.end_layer(bounds); + } + _ => unreachable!(), + } + } } } @@ -132,6 +150,18 @@ impl core::Renderer for Renderer { _ => unreachable!(), } } + Self::Custom(renderer) => { + renderer.start_transformation(); + + f(self); + + match self { + Self::Custom(renderer) => { + renderer.end_transformation(transformation); + } + _ => unreachable!(), + } + } } } @@ -140,7 +170,7 @@ impl core::Renderer for Renderer { quad: renderer::Quad, background: impl Into, ) { - delegate!(self, renderer, renderer.fill_quad(quad, background)); + delegate!(self, renderer, renderer.fill_quad(quad, background.into())); } fn clear(&mut self) { @@ -216,36 +246,43 @@ impl text::Renderer for Renderer { impl crate::core::image::Renderer for Renderer { type Handle = crate::core::image::Handle; - fn dimensions( + fn measure_image( &self, handle: &crate::core::image::Handle, ) -> core::Size { - delegate!(self, renderer, renderer.dimensions(handle)) + delegate!(self, renderer, renderer.measure_image(handle)) } - fn draw( + fn draw_image( &mut self, handle: crate::core::image::Handle, filter_method: crate::core::image::FilterMethod, bounds: Rectangle, ) { - delegate!(self, renderer, renderer.draw(handle, filter_method, bounds)); + delegate!( + self, + renderer, + renderer.draw_image(handle, filter_method, bounds) + ); } } #[cfg(feature = "svg")] impl crate::core::svg::Renderer for Renderer { - fn dimensions(&self, handle: &crate::core::svg::Handle) -> core::Size { - delegate!(self, renderer, renderer.dimensions(handle)) + fn measure_svg( + &self, + handle: &crate::core::svg::Handle, + ) -> core::Size { + delegate!(self, renderer, renderer.measure_svg(handle)) } - fn draw( + fn draw_svg( &mut self, handle: crate::core::svg::Handle, color: Option, bounds: Rectangle, ) { - delegate!(self, renderer, renderer.draw(handle, color, bounds)); + delegate!(self, renderer, renderer.draw_svg(handle, color, bounds)); } } @@ -263,6 +300,7 @@ impl crate::graphics::geometry::Renderer for Renderer { } #[cfg(feature = "wgpu")] crate::Geometry::Wgpu(_) => unreachable!(), + crate::Geometry::Custom(_) => unreachable!(), } } } @@ -274,6 +312,19 @@ impl crate::graphics::geometry::Renderer for Renderer { renderer.draw_primitive(primitive); } crate::Geometry::TinySkia(_) => unreachable!(), + crate::Geometry::Custom(_) => unreachable!(), + } + } + } + Self::Custom(renderer) => { + for layer in layers { + match layer { + crate::Geometry::Custom(geometry) => { + renderer.draw_geometry(geometry); + } + crate::Geometry::TinySkia(_) => unreachable!(), + #[cfg(feature = "wgpu")] + crate::Geometry::Wgpu(_) => unreachable!(), } } } @@ -297,6 +348,11 @@ impl iced_wgpu::primitive::pipeline::Renderer for Renderer { Self::Wgpu(renderer) => { renderer.draw_pipeline_primitive(bounds, primitive); } + Self::Custom(_renderer) => { + log::warn!( + "Custom shader primitive is unavailable with custom renderer." + ); + } } } } -- cgit From 9171df1e356530410a7ceadadd78fd3dcf150dfd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 06:00:55 +0100 Subject: Gate `Custom` variants in `iced_renderer` behind `custom` feature --- renderer/src/compositor.rs | 13 +++++++++---- renderer/src/geometry.rs | 13 ++++++++++--- renderer/src/geometry/cache.rs | 7 +++++-- renderer/src/lib.rs | 9 +++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) (limited to 'renderer/src') diff --git a/renderer/src/compositor.rs b/renderer/src/compositor.rs index 058fa36d..012ad3c0 100644 --- a/renderer/src/compositor.rs +++ b/renderer/src/compositor.rs @@ -1,5 +1,4 @@ use crate::core::Color; -use crate::custom; use crate::graphics::compositor::{Information, SurfaceError, Window}; use crate::graphics::{Error, Viewport}; use crate::{Renderer, Settings}; @@ -11,14 +10,16 @@ pub enum Compositor { TinySkia(iced_tiny_skia::window::Compositor), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::window::Compositor), - Custom(Box), + #[cfg(feature = "custom")] + Custom(Box), } pub enum Surface { TinySkia(iced_tiny_skia::window::Surface), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::window::Surface<'static>), - Custom(Box), + #[cfg(feature = "custom")] + Custom(Box), } impl crate::graphics::Compositor for Compositor { @@ -59,6 +60,7 @@ impl crate::graphics::Compositor for Compositor { Compositor::Wgpu(compositor) => { Renderer::Wgpu(compositor.create_renderer()) } + #[cfg(feature = "custom")] Compositor::Custom(compositor) => { Renderer::Custom(compositor.create_renderer()) } @@ -79,6 +81,7 @@ impl crate::graphics::Compositor for Compositor { Self::Wgpu(compositor) => { Surface::Wgpu(compositor.create_surface(window, width, height)) } + #[cfg(feature = "custom")] Self::Custom(compositor) => Surface::Custom( compositor.create_surface(Box::new(window), width, height), ), @@ -99,6 +102,7 @@ impl crate::graphics::Compositor for Compositor { (Self::Wgpu(compositor), Surface::Wgpu(surface)) => { compositor.configure_surface(surface, width, height); } + #[cfg(feature = "custom")] (Self::Custom(compositor), Surface::Custom(surface)) => { compositor.configure_surface(surface, width, height); } @@ -114,6 +118,7 @@ impl crate::graphics::Compositor for Compositor { Self::TinySkia(compositor) => compositor.fetch_information(), #[cfg(feature = "wgpu")] Self::Wgpu(compositor) => compositor.fetch_information(), + #[cfg(feature = "custom")] Self::Custom(compositor) => compositor.fetch_information(), } } @@ -158,7 +163,7 @@ impl crate::graphics::Compositor for Compositor { ) }), - #[cfg(feature = "wgpu")] + #[cfg(feature = "custom")] ( Self::Custom(compositor), crate::Renderer::Custom(renderer), diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs index bf70c7fa..a16cecd5 100644 --- a/renderer/src/geometry.rs +++ b/renderer/src/geometry.rs @@ -3,7 +3,6 @@ mod cache; pub use cache::Cache; use crate::core::{Point, Radians, Rectangle, Size, Transformation, Vector}; -use crate::custom; use crate::graphics::geometry::{Fill, Path, Stroke, Text}; use crate::Renderer; @@ -13,6 +12,7 @@ macro_rules! delegate { Self::TinySkia($name) => $body, #[cfg(feature = "wgpu")] Self::Wgpu($name) => $body, + #[cfg(feature = "custom")] Self::Custom($name) => $body, } }; @@ -22,7 +22,8 @@ pub enum Geometry { TinySkia(iced_tiny_skia::Primitive), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::Primitive), - Custom(Box), + #[cfg(feature = "custom")] + Custom(Box), } impl Geometry { @@ -35,6 +36,7 @@ impl Geometry { Self::Wgpu(primitive) => { Self::Wgpu(primitive.transform(transformation)) } + #[cfg(feature = "custom")] Self::Custom(geometry) => { Self::Custom(geometry.transform(transformation)) } @@ -46,7 +48,8 @@ pub enum Frame { TinySkia(iced_tiny_skia::geometry::Frame), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::geometry::Frame), - Custom(Box), + #[cfg(feature = "custom")] + Custom(Box), } impl Frame { @@ -59,6 +62,7 @@ impl Frame { Renderer::Wgpu(_) => { Frame::Wgpu(iced_wgpu::geometry::Frame::new(size)) } + #[cfg(feature = "custom")] Renderer::Custom(renderer) => { Frame::Custom(renderer.new_frame(size)) } @@ -169,6 +173,7 @@ impl Frame { Self::Wgpu(_) => { Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size())) } + #[cfg(feature = "custom")] Self::Custom(frame) => Self::Custom(frame.new(region.size())), }; @@ -184,6 +189,7 @@ impl Frame { (Self::Wgpu(target), Self::Wgpu(frame)) => { target.clip(frame, origin); } + #[cfg(feature = "custom")] (Self::Custom(target), Self::Custom(frame)) => { target.clip(frame, origin); } @@ -223,6 +229,7 @@ impl Frame { Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()), #[cfg(feature = "wgpu")] Self::Wgpu(frame) => Geometry::Wgpu(frame.into_primitive()), + #[cfg(feature = "custom")] Self::Custom(frame) => Geometry::Custom(frame.into_geometry()), } } diff --git a/renderer/src/geometry/cache.rs b/renderer/src/geometry/cache.rs index 6a43ddb6..20f73f22 100644 --- a/renderer/src/geometry/cache.rs +++ b/renderer/src/geometry/cache.rs @@ -1,5 +1,4 @@ use crate::core::Size; -use crate::custom; use crate::geometry::{Frame, Geometry}; use crate::Renderer; @@ -30,7 +29,8 @@ enum Internal { TinySkia(Arc), #[cfg(feature = "wgpu")] Wgpu(Arc), - Custom(Arc), + #[cfg(feature = "custom")] + Custom(Arc), } impl Cache { @@ -84,6 +84,7 @@ impl Cache { content: primitive.clone(), }); } + #[cfg(feature = "custom")] Internal::Custom(geometry) => { return Geometry::Custom(geometry.clone().load()) } @@ -105,6 +106,7 @@ impl Cache { Geometry::Wgpu(primitive) => { Internal::Wgpu(Arc::new(primitive)) } + #[cfg(feature = "custom")] Geometry::Custom(geometry) => { Internal::Custom(geometry.cache()) } @@ -128,6 +130,7 @@ impl Cache { content: primitive, }) } + #[cfg(feature = "custom")] Internal::Custom(geometry) => Geometry::Custom(geometry.load()), } } diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 70741356..67096115 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -39,6 +39,7 @@ pub enum Renderer { TinySkia(iced_tiny_skia::Renderer), #[cfg(feature = "wgpu")] Wgpu(iced_wgpu::Renderer), + #[cfg(feature = "custom")] Custom(Box), } @@ -48,6 +49,7 @@ macro_rules! delegate { Self::TinySkia($name) => $body, #[cfg(feature = "wgpu")] Self::Wgpu($name) => $body, + #[cfg(feature = "custom")] Self::Custom($name) => $body, } }; @@ -65,6 +67,7 @@ impl Renderer { iced_wgpu::primitive::Custom::Mesh(mesh), )); } + #[cfg(feature = "custom")] Self::Custom(renderer) => { renderer.draw_mesh(mesh); } @@ -102,6 +105,7 @@ impl core::Renderer for Renderer { _ => unreachable!(), } } + #[cfg(feature = "custom")] Self::Custom(renderer) => { renderer.start_layer(); @@ -150,6 +154,7 @@ impl core::Renderer for Renderer { _ => unreachable!(), } } + #[cfg(feature = "custom")] Self::Custom(renderer) => { renderer.start_transformation(); @@ -300,6 +305,7 @@ impl crate::graphics::geometry::Renderer for Renderer { } #[cfg(feature = "wgpu")] crate::Geometry::Wgpu(_) => unreachable!(), + #[cfg(feature = "custom")] crate::Geometry::Custom(_) => unreachable!(), } } @@ -312,10 +318,12 @@ impl crate::graphics::geometry::Renderer for Renderer { renderer.draw_primitive(primitive); } crate::Geometry::TinySkia(_) => unreachable!(), + #[cfg(feature = "custom")] crate::Geometry::Custom(_) => unreachable!(), } } } + #[cfg(feature = "custom")] Self::Custom(renderer) => { for layer in layers { match layer { @@ -348,6 +356,7 @@ impl iced_wgpu::primitive::pipeline::Renderer for Renderer { Self::Wgpu(renderer) => { renderer.draw_pipeline_primitive(bounds, primitive); } + #[cfg(feature = "custom")] Self::Custom(_renderer) => { log::warn!( "Custom shader primitive is unavailable with custom renderer." -- cgit From 7e4ae8450e1f28c15717ca5ca9748981af9c9541 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 06:03:31 +0100 Subject: Use `&mut dyn Surface` instead of `&mut Box` --- renderer/src/compositor.rs | 2 +- renderer/src/custom.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'renderer/src') diff --git a/renderer/src/compositor.rs b/renderer/src/compositor.rs index 012ad3c0..3d0b3ad0 100644 --- a/renderer/src/compositor.rs +++ b/renderer/src/compositor.rs @@ -104,7 +104,7 @@ impl crate::graphics::Compositor for Compositor { } #[cfg(feature = "custom")] (Self::Custom(compositor), Surface::Custom(surface)) => { - compositor.configure_surface(surface, width, height); + compositor.configure_surface(surface.as_mut(), width, height); } #[allow(unreachable_patterns)] _ => panic!( diff --git a/renderer/src/custom.rs b/renderer/src/custom.rs index 680aa0b5..04090ccb 100644 --- a/renderer/src/custom.rs +++ b/renderer/src/custom.rs @@ -153,7 +153,7 @@ pub trait Compositor: std::any::Any { fn configure_surface( &mut self, - surface: &mut Box, + surface: &mut dyn Surface, width: u32, height: u32, ); -- cgit From 3645d34d6a1ba1247238e830e9eefd52d9e5b986 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 22:27:17 +0100 Subject: Implement composable, type-safe renderer fallback --- renderer/src/compositor.rs | 299 ------------------------ renderer/src/custom.rs | 4 +- renderer/src/fallback.rs | 562 +++++++++++++++++++++++++++++++++++++++++++++ renderer/src/lib.rs | 368 ++--------------------------- renderer/src/settings.rs | 21 ++ 5 files changed, 607 insertions(+), 647 deletions(-) create mode 100644 renderer/src/fallback.rs (limited to 'renderer/src') diff --git a/renderer/src/compositor.rs b/renderer/src/compositor.rs index 3d0b3ad0..8b137891 100644 --- a/renderer/src/compositor.rs +++ b/renderer/src/compositor.rs @@ -1,300 +1 @@ -use crate::core::Color; -use crate::graphics::compositor::{Information, SurfaceError, Window}; -use crate::graphics::{Error, Viewport}; -use crate::{Renderer, Settings}; -use std::env; -use std::future::Future; - -pub enum Compositor { - TinySkia(iced_tiny_skia::window::Compositor), - #[cfg(feature = "wgpu")] - Wgpu(iced_wgpu::window::Compositor), - #[cfg(feature = "custom")] - Custom(Box), -} - -pub enum Surface { - TinySkia(iced_tiny_skia::window::Surface), - #[cfg(feature = "wgpu")] - Wgpu(iced_wgpu::window::Surface<'static>), - #[cfg(feature = "custom")] - Custom(Box), -} - -impl crate::graphics::Compositor for Compositor { - type Settings = Settings; - type Renderer = Renderer; - type Surface = Surface; - - fn new( - settings: Self::Settings, - compatible_window: W, - ) -> impl Future> { - let candidates = - Candidate::list_from_env().unwrap_or(Candidate::default_list()); - - async move { - let mut error = Error::GraphicsAdapterNotFound; - - for candidate in candidates { - match candidate.build(settings, compatible_window.clone()).await - { - Ok(compositor) => return Ok(compositor), - Err(new_error) => { - error = new_error; - } - } - } - - Err(error) - } - } - - fn create_renderer(&self) -> Self::Renderer { - match self { - Compositor::TinySkia(compositor) => { - Renderer::TinySkia(compositor.create_renderer()) - } - #[cfg(feature = "wgpu")] - Compositor::Wgpu(compositor) => { - Renderer::Wgpu(compositor.create_renderer()) - } - #[cfg(feature = "custom")] - Compositor::Custom(compositor) => { - Renderer::Custom(compositor.create_renderer()) - } - } - } - - fn create_surface( - &mut self, - window: W, - width: u32, - height: u32, - ) -> Surface { - match self { - Self::TinySkia(compositor) => Surface::TinySkia( - compositor.create_surface(window, width, height), - ), - #[cfg(feature = "wgpu")] - Self::Wgpu(compositor) => { - Surface::Wgpu(compositor.create_surface(window, width, height)) - } - #[cfg(feature = "custom")] - Self::Custom(compositor) => Surface::Custom( - compositor.create_surface(Box::new(window), width, height), - ), - } - } - - fn configure_surface( - &mut self, - surface: &mut Surface, - width: u32, - height: u32, - ) { - match (self, surface) { - (Self::TinySkia(compositor), Surface::TinySkia(surface)) => { - compositor.configure_surface(surface, width, height); - } - #[cfg(feature = "wgpu")] - (Self::Wgpu(compositor), Surface::Wgpu(surface)) => { - compositor.configure_surface(surface, width, height); - } - #[cfg(feature = "custom")] - (Self::Custom(compositor), Surface::Custom(surface)) => { - compositor.configure_surface(surface.as_mut(), width, height); - } - #[allow(unreachable_patterns)] - _ => panic!( - "The provided surface is not compatible with the compositor." - ), - } - } - - fn fetch_information(&self) -> Information { - match self { - Self::TinySkia(compositor) => compositor.fetch_information(), - #[cfg(feature = "wgpu")] - Self::Wgpu(compositor) => compositor.fetch_information(), - #[cfg(feature = "custom")] - Self::Custom(compositor) => compositor.fetch_information(), - } - } - - fn present>( - &mut self, - renderer: &mut Self::Renderer, - surface: &mut Self::Surface, - viewport: &Viewport, - background_color: Color, - overlay: &[T], - ) -> Result<(), SurfaceError> { - match (self, renderer, surface) { - ( - Self::TinySkia(_compositor), - crate::Renderer::TinySkia(renderer), - Surface::TinySkia(surface), - ) => renderer.with_primitives(|backend, primitives| { - iced_tiny_skia::window::compositor::present( - backend, - surface, - primitives, - viewport, - background_color, - overlay, - ) - }), - #[cfg(feature = "wgpu")] - ( - Self::Wgpu(compositor), - crate::Renderer::Wgpu(renderer), - Surface::Wgpu(surface), - ) => renderer.with_primitives(|backend, primitives| { - iced_wgpu::window::compositor::present( - compositor, - backend, - surface, - primitives, - viewport, - background_color, - overlay, - ) - }), - - #[cfg(feature = "custom")] - ( - Self::Custom(compositor), - crate::Renderer::Custom(renderer), - Surface::Custom(surface), - ) => renderer.present( - surface.as_mut(), - viewport, - background_color, - compositor.as_mut(), - ), - #[allow(unreachable_patterns)] - _ => panic!( - "The provided renderer or surface are not compatible \ - with the compositor." - ), - } - } - - fn screenshot>( - &mut self, - renderer: &mut Self::Renderer, - surface: &mut Self::Surface, - viewport: &Viewport, - background_color: Color, - overlay: &[T], - ) -> Vec { - match (self, renderer, surface) { - ( - Self::TinySkia(_compositor), - Renderer::TinySkia(renderer), - Surface::TinySkia(surface), - ) => renderer.with_primitives(|backend, primitives| { - iced_tiny_skia::window::compositor::screenshot( - surface, - backend, - primitives, - viewport, - background_color, - overlay, - ) - }), - #[cfg(feature = "wgpu")] - ( - Self::Wgpu(compositor), - Renderer::Wgpu(renderer), - Surface::Wgpu(_), - ) => renderer.with_primitives(|backend, primitives| { - iced_wgpu::window::compositor::screenshot( - compositor, - backend, - primitives, - viewport, - background_color, - overlay, - ) - }), - #[allow(unreachable_patterns)] - _ => panic!( - "The provided renderer or backend are not compatible \ - with the compositor." - ), - } - } -} - -enum Candidate { - Wgpu, - TinySkia, -} - -impl Candidate { - fn default_list() -> Vec { - vec![ - #[cfg(feature = "wgpu")] - Self::Wgpu, - Self::TinySkia, - ] - } - - fn list_from_env() -> Option> { - let backends = env::var("ICED_BACKEND").ok()?; - - Some( - backends - .split(',') - .map(str::trim) - .map(|backend| match backend { - "wgpu" => Self::Wgpu, - "tiny-skia" => Self::TinySkia, - _ => panic!("unknown backend value: \"{backend}\""), - }) - .collect(), - ) - } - - async fn build( - self, - settings: Settings, - _compatible_window: W, - ) -> Result { - match self { - Self::TinySkia => { - let compositor = iced_tiny_skia::window::compositor::new( - iced_tiny_skia::Settings { - default_font: settings.default_font, - default_text_size: settings.default_text_size, - }, - _compatible_window, - ); - - Ok(Compositor::TinySkia(compositor)) - } - #[cfg(feature = "wgpu")] - Self::Wgpu => { - let compositor = iced_wgpu::window::compositor::new( - iced_wgpu::Settings { - default_font: settings.default_font, - default_text_size: settings.default_text_size, - antialiasing: settings.antialiasing, - ..iced_wgpu::Settings::from_env() - }, - _compatible_window, - ) - .await?; - - Ok(Compositor::Wgpu(compositor)) - } - #[cfg(not(feature = "wgpu"))] - Self::Wgpu => { - panic!("`wgpu` feature was not enabled in `iced_renderer`") - } - } - } -} diff --git a/renderer/src/custom.rs b/renderer/src/custom.rs index 04090ccb..4addeb86 100644 --- a/renderer/src/custom.rs +++ b/renderer/src/custom.rs @@ -94,8 +94,6 @@ pub trait Renderer { #[cfg(feature = "geometry")] pub trait Frame: std::any::Any { - fn new(&self, size: Size) -> Box; - fn width(&self) -> f32; fn height(&self) -> f32; @@ -108,7 +106,7 @@ pub trait Frame: std::any::Any { fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: Fill); - fn stroke<'a>(&mut self, path: &Path, stroke: Stroke<'a>); + fn stroke(&mut self, path: &Path, stroke: Stroke<'_>); fn fill_text(&mut self, text: geometry::Text); diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs new file mode 100644 index 00000000..a4c725c0 --- /dev/null +++ b/renderer/src/fallback.rs @@ -0,0 +1,562 @@ +use crate::core::image; +use crate::core::renderer; +use crate::core::svg; +use crate::core::{ + self, Background, Color, Point, Rectangle, Size, Transformation, +}; +use crate::graphics; +use crate::graphics::compositor; +use crate::graphics::mesh; + +pub enum Renderer +where + L: core::Renderer, + R: core::Renderer, +{ + Left(L), + Right(R), +} + +macro_rules! delegate { + ($renderer:expr, $name:ident, $body:expr) => { + match $renderer { + Self::Left($name) => $body, + Self::Right($name) => $body, + } + }; +} + +impl Renderer +where + L: core::Renderer, + R: core::Renderer, +{ + #[cfg(feature = "geometry")] + pub fn draw_geometry( + &mut self, + layers: impl IntoIterator, + ) where + L: graphics::geometry::Renderer, + R: graphics::geometry::Renderer, + + Geometry: Into>, + { + use graphics::geometry::Renderer; + + for layer in layers { + ::draw_geometry(self, layer.into()); + } + } +} + +impl core::Renderer for Renderer +where + L: core::Renderer, + R: core::Renderer, +{ + fn fill_quad( + &mut self, + quad: renderer::Quad, + background: impl Into, + ) { + delegate!(self, renderer, renderer.fill_quad(quad, background.into())); + } + + fn clear(&mut self) { + delegate!(self, renderer, renderer.clear()); + } + + fn start_layer(&mut self) { + delegate!(self, renderer, renderer.start_layer()); + } + + fn end_layer(&mut self, bounds: Rectangle) { + delegate!(self, renderer, renderer.end_layer(bounds)); + } + + fn start_transformation(&mut self) { + delegate!(self, renderer, renderer.start_transformation()); + } + + fn end_transformation(&mut self, transformation: Transformation) { + delegate!(self, renderer, renderer.end_transformation(transformation)); + } +} + +impl core::text::Renderer for Renderer +where + L: core::text::Renderer, + R: core::text::Renderer< + Font = L::Font, + Paragraph = L::Paragraph, + Editor = L::Editor, + >, +{ + type Font = L::Font; + type Paragraph = L::Paragraph; + type Editor = L::Editor; + + const ICON_FONT: Self::Font = L::ICON_FONT; + const CHECKMARK_ICON: char = L::CHECKMARK_ICON; + const ARROW_DOWN_ICON: char = L::ARROW_DOWN_ICON; + + fn default_font(&self) -> Self::Font { + delegate!(self, renderer, renderer.default_font()) + } + + fn default_size(&self) -> core::Pixels { + delegate!(self, renderer, renderer.default_size()) + } + + fn load_font(&mut self, font: std::borrow::Cow<'static, [u8]>) { + delegate!(self, renderer, renderer.load_font(font)); + } + + fn fill_paragraph( + &mut self, + text: &Self::Paragraph, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.fill_paragraph(text, position, color, clip_bounds) + ); + } + + fn fill_editor( + &mut self, + editor: &Self::Editor, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.fill_editor(editor, position, color, clip_bounds) + ); + } + + fn fill_text( + &mut self, + text: core::Text<'_, Self::Font>, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.fill_text(text, position, color, clip_bounds) + ); + } +} + +impl image::Renderer for Renderer +where + L: image::Renderer, + R: image::Renderer, +{ + type Handle = L::Handle; + + fn measure_image(&self, handle: &Self::Handle) -> Size { + delegate!(self, renderer, renderer.measure_image(handle)) + } + + fn draw_image( + &mut self, + handle: Self::Handle, + filter_method: image::FilterMethod, + bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.draw_image(handle, filter_method, bounds) + ); + } +} + +impl svg::Renderer for Renderer +where + L: svg::Renderer, + R: svg::Renderer, +{ + fn measure_svg(&self, handle: &svg::Handle) -> Size { + delegate!(self, renderer, renderer.measure_svg(handle)) + } + + fn draw_svg( + &mut self, + handle: svg::Handle, + color: Option, + bounds: Rectangle, + ) { + delegate!(self, renderer, renderer.draw_svg(handle, color, bounds)); + } +} + +impl mesh::Renderer for Renderer +where + L: mesh::Renderer, + R: mesh::Renderer, +{ + fn draw_mesh(&mut self, mesh: graphics::Mesh) { + delegate!(self, renderer, renderer.draw_mesh(mesh)); + } +} + +pub enum Compositor +where + L: graphics::Compositor, + R: graphics::Compositor, +{ + Left(L), + Right(R), +} + +pub enum Surface { + Left(L), + Right(R), +} + +impl graphics::Compositor for Compositor +where + L: graphics::Compositor, + R: graphics::Compositor, + L::Settings: From, + R::Settings: From, +{ + type Settings = crate::Settings; + type Renderer = Renderer; + type Surface = Surface; + + async fn new( + settings: Self::Settings, + compatible_window: W, + ) -> Result { + if let Ok(left) = L::new(settings.into(), compatible_window.clone()) + .await + .map(Self::Left) + { + return Ok(left); + } + + R::new(settings.into(), compatible_window) + .await + .map(Self::Right) + } + + fn create_renderer(&self) -> Self::Renderer { + match self { + Self::Left(compositor) => { + Renderer::Left(compositor.create_renderer()) + } + Self::Right(compositor) => { + Renderer::Right(compositor.create_renderer()) + } + } + } + + fn create_surface( + &mut self, + window: W, + width: u32, + height: u32, + ) -> Self::Surface { + match self { + Self::Left(compositor) => { + Surface::Left(compositor.create_surface(window, width, height)) + } + Self::Right(compositor) => { + Surface::Right(compositor.create_surface(window, width, height)) + } + } + } + + fn configure_surface( + &mut self, + surface: &mut Self::Surface, + width: u32, + height: u32, + ) { + match (self, surface) { + (Self::Left(compositor), Surface::Left(surface)) => { + compositor.configure_surface(surface, width, height); + } + (Self::Right(compositor), Surface::Right(surface)) => { + compositor.configure_surface(surface, width, height); + } + _ => unreachable!(), + } + } + + fn fetch_information(&self) -> compositor::Information { + delegate!(self, compositor, compositor.fetch_information()) + } + + fn present>( + &mut self, + renderer: &mut Self::Renderer, + surface: &mut Self::Surface, + viewport: &graphics::Viewport, + background_color: Color, + overlay: &[T], + ) -> Result<(), compositor::SurfaceError> { + match (self, renderer, surface) { + ( + Self::Left(compositor), + Renderer::Left(renderer), + Surface::Left(surface), + ) => compositor.present( + renderer, + surface, + viewport, + background_color, + overlay, + ), + ( + Self::Right(compositor), + Renderer::Right(renderer), + Surface::Right(surface), + ) => compositor.present( + renderer, + surface, + viewport, + background_color, + overlay, + ), + _ => unreachable!(), + } + } + + fn screenshot>( + &mut self, + renderer: &mut Self::Renderer, + surface: &mut Self::Surface, + viewport: &graphics::Viewport, + background_color: Color, + overlay: &[T], + ) -> Vec { + match (self, renderer, surface) { + ( + Self::Left(compositor), + Renderer::Left(renderer), + Surface::Left(surface), + ) => compositor.screenshot( + renderer, + surface, + viewport, + background_color, + overlay, + ), + ( + Self::Right(compositor), + Renderer::Right(renderer), + Surface::Right(surface), + ) => compositor.screenshot( + renderer, + surface, + viewport, + background_color, + overlay, + ), + _ => unreachable!(), + } + } +} + +#[cfg(feature = "wgpu")] +impl iced_wgpu::primitive::pipeline::Renderer for Renderer +where + L: iced_wgpu::primitive::pipeline::Renderer, + R: core::Renderer, +{ + fn draw_pipeline_primitive( + &mut self, + bounds: Rectangle, + primitive: impl iced_wgpu::primitive::pipeline::Primitive, + ) { + match self { + Self::Left(renderer) => { + renderer.draw_pipeline_primitive(bounds, primitive); + } + Self::Right(_) => { + log::warn!( + "Custom shader primitive is not supported with this renderer." + ); + } + } + } +} + +#[cfg(feature = "geometry")] +mod geometry { + use super::Renderer; + use crate::core::{Point, Radians, Size, Vector}; + use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; + + impl geometry::Renderer for Renderer + where + L: geometry::Renderer, + R: geometry::Renderer, + { + type Geometry = Geometry; + type Frame = Frame; + + fn new_frame(&self, size: iced_graphics::core::Size) -> Self::Frame { + match self { + Self::Left(renderer) => Frame::Left(renderer.new_frame(size)), + Self::Right(renderer) => Frame::Right(renderer.new_frame(size)), + } + } + + fn draw_geometry(&mut self, geometry: Self::Geometry) { + match (self, geometry) { + (Self::Left(renderer), Geometry::Left(geometry)) => { + renderer.draw_geometry(geometry); + } + (Self::Right(renderer), Geometry::Right(geometry)) => { + renderer.draw_geometry(geometry); + } + _ => unreachable!(), + } + } + } + + pub enum Geometry { + Left(L), + Right(R), + } + + impl geometry::Geometry for Geometry + where + L: geometry::Geometry, + R: geometry::Geometry, + { + type Cache = Geometry; + + fn load(cache: &Self::Cache) -> Self { + match cache { + Geometry::Left(cache) => Self::Left(L::load(cache)), + Geometry::Right(cache) => Self::Right(R::load(cache)), + } + } + + fn cache(self) -> Self::Cache { + match self { + Self::Left(geometry) => Geometry::Left(geometry.cache()), + Self::Right(geometry) => Geometry::Right(geometry.cache()), + } + } + } + + pub enum Frame { + Left(L), + Right(R), + } + + impl geometry::Frame for Frame + where + L: geometry::Frame, + R: geometry::Frame, + { + type Geometry = Geometry; + + fn width(&self) -> f32 { + delegate!(self, frame, frame.width()) + } + + fn height(&self) -> f32 { + delegate!(self, frame, frame.height()) + } + + fn size(&self) -> Size { + delegate!(self, frame, frame.size()) + } + + fn center(&self) -> Point { + delegate!(self, frame, frame.center()) + } + + fn fill(&mut self, path: &Path, fill: impl Into) { + delegate!(self, frame, frame.fill(path, fill)); + } + + fn fill_rectangle( + &mut self, + top_left: Point, + size: Size, + fill: impl Into, + ) { + delegate!(self, frame, frame.fill_rectangle(top_left, size, fill)); + } + + fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>) { + delegate!(self, frame, frame.stroke(path, stroke)); + } + + fn fill_text(&mut self, text: impl Into) { + delegate!(self, frame, frame.fill_text(text)); + } + + fn push_transform(&mut self) { + delegate!(self, frame, frame.push_transform()); + } + + fn pop_transform(&mut self) { + delegate!(self, frame, frame.pop_transform()); + } + + fn draft(&mut self, size: Size) -> Self { + match self { + Self::Left(frame) => Self::Left(frame.draft(size)), + Self::Right(frame) => Self::Right(frame.draft(size)), + } + } + + fn paste(&mut self, frame: Self, at: Point) { + match (self, frame) { + (Self::Left(target), Self::Left(source)) => { + target.paste(source, at); + } + (Self::Right(target), Self::Right(source)) => { + target.paste(source, at); + } + _ => unreachable!(), + } + } + + fn translate(&mut self, translation: Vector) { + delegate!(self, frame, frame.translate(translation)); + } + + fn rotate(&mut self, angle: impl Into) { + delegate!(self, frame, frame.rotate(angle)); + } + + fn scale(&mut self, scale: impl Into) { + delegate!(self, frame, frame.scale(scale)); + } + + fn scale_nonuniform(&mut self, scale: impl Into) { + delegate!(self, frame, frame.scale_nonuniform(scale)); + } + } + + impl From> for Geometry + where + L: geometry::Frame, + R: geometry::Frame, + { + fn from(frame: Frame) -> Self { + match frame { + Frame::Left(frame) => Self::Left(frame.into()), + Frame::Right(frame) => Self::Right(frame.into()), + } + } + } +} diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 67096115..f8aa1157 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -4,364 +4,42 @@ #[cfg(feature = "wgpu")] pub use iced_wgpu as wgpu; -pub mod compositor; -pub mod custom; - -#[cfg(feature = "geometry")] -pub mod geometry; +pub mod fallback; mod settings; pub use iced_graphics as graphics; pub use iced_graphics::core; -pub use compositor::Compositor; -pub use settings::Settings; - #[cfg(feature = "geometry")] -pub use geometry::Geometry; - -use crate::core::renderer; -use crate::core::text::{self, Text}; -use crate::core::{ - Background, Color, Font, Pixels, Point, Rectangle, Transformation, -}; -use crate::graphics::text::Editor; -use crate::graphics::text::Paragraph; -use crate::graphics::Mesh; +pub use iced_graphics::geometry; -use std::borrow::Cow; +pub use settings::Settings; /// The default graphics renderer for [`iced`]. /// /// [`iced`]: https://github.com/iced-rs/iced -pub enum Renderer { - TinySkia(iced_tiny_skia::Renderer), - #[cfg(feature = "wgpu")] - Wgpu(iced_wgpu::Renderer), - #[cfg(feature = "custom")] - Custom(Box), -} - -macro_rules! delegate { - ($renderer:expr, $name:ident, $body:expr) => { - match $renderer { - Self::TinySkia($name) => $body, - #[cfg(feature = "wgpu")] - Self::Wgpu($name) => $body, - #[cfg(feature = "custom")] - Self::Custom($name) => $body, - } - }; -} - -impl Renderer { - pub fn draw_mesh(&mut self, mesh: Mesh) { - match self { - Self::TinySkia(_) => { - log::warn!("Unsupported mesh primitive: {mesh:?}"); - } - #[cfg(feature = "wgpu")] - Self::Wgpu(renderer) => { - renderer.draw_primitive(iced_wgpu::Primitive::Custom( - iced_wgpu::primitive::Custom::Mesh(mesh), - )); - } - #[cfg(feature = "custom")] - Self::Custom(renderer) => { - renderer.draw_mesh(mesh); - } - } - } -} - -impl core::Renderer for Renderer { - fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) { - match self { - Self::TinySkia(renderer) => { - let primitives = renderer.start_layer(); - - f(self); - - match self { - Self::TinySkia(renderer) => { - renderer.end_layer(primitives, bounds); - } - #[cfg(feature = "wgpu")] - _ => unreachable!(), - } - } - #[cfg(feature = "wgpu")] - Self::Wgpu(renderer) => { - let primitives = renderer.start_layer(); - - f(self); - - match self { - #[cfg(feature = "wgpu")] - Self::Wgpu(renderer) => { - renderer.end_layer(primitives, bounds); - } - _ => unreachable!(), - } - } - #[cfg(feature = "custom")] - Self::Custom(renderer) => { - renderer.start_layer(); - - f(self); - - match self { - Self::Custom(renderer) => { - renderer.end_layer(bounds); - } - _ => unreachable!(), - } - } - } - } - - fn with_transformation( - &mut self, - transformation: Transformation, - f: impl FnOnce(&mut Self), - ) { - match self { - Self::TinySkia(renderer) => { - let primitives = renderer.start_transformation(); - - f(self); - - match self { - Self::TinySkia(renderer) => { - renderer.end_transformation(primitives, transformation); - } - #[cfg(feature = "wgpu")] - _ => unreachable!(), - } - } - #[cfg(feature = "wgpu")] - Self::Wgpu(renderer) => { - let primitives = renderer.start_transformation(); - - f(self); - - match self { - #[cfg(feature = "wgpu")] - Self::Wgpu(renderer) => { - renderer.end_transformation(primitives, transformation); - } - _ => unreachable!(), - } - } - #[cfg(feature = "custom")] - Self::Custom(renderer) => { - renderer.start_transformation(); - - f(self); - - match self { - Self::Custom(renderer) => { - renderer.end_transformation(transformation); - } - _ => unreachable!(), - } - } - } - } - - fn fill_quad( - &mut self, - quad: renderer::Quad, - background: impl Into, - ) { - delegate!(self, renderer, renderer.fill_quad(quad, background.into())); - } - - fn clear(&mut self) { - delegate!(self, renderer, renderer.clear()); - } -} +#[cfg(not(feature = "wgpu"))] +pub type Renderer = iced_tiny_skia::Renderer; -impl text::Renderer for Renderer { - type Font = Font; - type Paragraph = Paragraph; - type Editor = Editor; - - const ICON_FONT: Font = iced_tiny_skia::Renderer::ICON_FONT; - const CHECKMARK_ICON: char = iced_tiny_skia::Renderer::CHECKMARK_ICON; - const ARROW_DOWN_ICON: char = iced_tiny_skia::Renderer::ARROW_DOWN_ICON; - - fn default_font(&self) -> Self::Font { - delegate!(self, renderer, renderer.default_font()) - } - - fn default_size(&self) -> Pixels { - delegate!(self, renderer, renderer.default_size()) - } - - fn load_font(&mut self, bytes: Cow<'static, [u8]>) { - delegate!(self, renderer, renderer.load_font(bytes)); - } - - fn fill_paragraph( - &mut self, - paragraph: &Self::Paragraph, - position: Point, - color: Color, - clip_bounds: Rectangle, - ) { - delegate!( - self, - renderer, - renderer.fill_paragraph(paragraph, position, color, clip_bounds) - ); - } - - fn fill_editor( - &mut self, - editor: &Self::Editor, - position: Point, - color: Color, - clip_bounds: Rectangle, - ) { - delegate!( - self, - renderer, - renderer.fill_editor(editor, position, color, clip_bounds) - ); - } - - fn fill_text( - &mut self, - text: Text<'_, Self::Font>, - position: Point, - color: Color, - clip_bounds: Rectangle, - ) { - delegate!( - self, - renderer, - renderer.fill_text(text, position, color, clip_bounds) - ); - } -} - -#[cfg(feature = "image")] -impl crate::core::image::Renderer for Renderer { - type Handle = crate::core::image::Handle; - - fn measure_image( - &self, - handle: &crate::core::image::Handle, - ) -> core::Size { - delegate!(self, renderer, renderer.measure_image(handle)) - } - - fn draw_image( - &mut self, - handle: crate::core::image::Handle, - filter_method: crate::core::image::FilterMethod, - bounds: Rectangle, - ) { - delegate!( - self, - renderer, - renderer.draw_image(handle, filter_method, bounds) - ); - } -} - -#[cfg(feature = "svg")] -impl crate::core::svg::Renderer for Renderer { - fn measure_svg( - &self, - handle: &crate::core::svg::Handle, - ) -> core::Size { - delegate!(self, renderer, renderer.measure_svg(handle)) - } - - fn draw_svg( - &mut self, - handle: crate::core::svg::Handle, - color: Option, - bounds: Rectangle, - ) { - delegate!(self, renderer, renderer.draw_svg(handle, color, bounds)); - } -} - -#[cfg(feature = "geometry")] -impl crate::graphics::geometry::Renderer for Renderer { - type Geometry = crate::Geometry; +/// The default graphics renderer for [`iced`]. +/// +/// [`iced`]: https://github.com/iced-rs/iced +#[cfg(feature = "wgpu")] +pub type Renderer = + fallback::Renderer; - fn draw(&mut self, layers: Vec) { - match self { - Self::TinySkia(renderer) => { - for layer in layers { - match layer { - crate::Geometry::TinySkia(primitive) => { - renderer.draw_primitive(primitive); - } - #[cfg(feature = "wgpu")] - crate::Geometry::Wgpu(_) => unreachable!(), - #[cfg(feature = "custom")] - crate::Geometry::Custom(_) => unreachable!(), - } - } - } - #[cfg(feature = "wgpu")] - Self::Wgpu(renderer) => { - for layer in layers { - match layer { - crate::Geometry::Wgpu(primitive) => { - renderer.draw_primitive(primitive); - } - crate::Geometry::TinySkia(_) => unreachable!(), - #[cfg(feature = "custom")] - crate::Geometry::Custom(_) => unreachable!(), - } - } - } - #[cfg(feature = "custom")] - Self::Custom(renderer) => { - for layer in layers { - match layer { - crate::Geometry::Custom(geometry) => { - renderer.draw_geometry(geometry); - } - crate::Geometry::TinySkia(_) => unreachable!(), - #[cfg(feature = "wgpu")] - crate::Geometry::Wgpu(_) => unreachable!(), - } - } - } - } - } -} +/// The default graphics compositor for [`iced`]. +/// +/// [`iced`]: https://github.com/iced-rs/iced +#[cfg(not(feature = "wgpu"))] +pub type Compositor = iced_tiny_skia::window::Compositor; +/// The default graphics renderer for [`iced`]. +/// +/// [`iced`]: https://github.com/iced-rs/iced #[cfg(feature = "wgpu")] -impl iced_wgpu::primitive::pipeline::Renderer for Renderer { - fn draw_pipeline_primitive( - &mut self, - bounds: Rectangle, - primitive: impl wgpu::primitive::pipeline::Primitive, - ) { - match self { - Self::TinySkia(_renderer) => { - log::warn!( - "Custom shader primitive is unavailable with tiny-skia." - ); - } - Self::Wgpu(renderer) => { - renderer.draw_pipeline_primitive(bounds, primitive); - } - #[cfg(feature = "custom")] - Self::Custom(_renderer) => { - log::warn!( - "Custom shader primitive is unavailable with custom renderer." - ); - } - } - } -} +pub type Compositor = fallback::Compositor< + iced_wgpu::window::Compositor, + iced_tiny_skia::window::Compositor, +>; diff --git a/renderer/src/settings.rs b/renderer/src/settings.rs index 432eb8a0..940daa15 100644 --- a/renderer/src/settings.rs +++ b/renderer/src/settings.rs @@ -27,3 +27,24 @@ impl Default for Settings { } } } + +impl From for iced_tiny_skia::Settings { + fn from(settings: Settings) -> Self { + Self { + default_font: settings.default_font, + default_text_size: settings.default_text_size, + } + } +} + +#[cfg(feature = "wgpu")] +impl From for iced_wgpu::Settings { + fn from(settings: Settings) -> Self { + Self { + default_font: settings.default_font, + default_text_size: settings.default_text_size, + antialiasing: settings.antialiasing, + ..iced_wgpu::Settings::default() + } + } +} -- cgit From 3d17cf8790a18bd0dfe968739c9802833c0bb647 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 22:47:43 +0100 Subject: Remove `custom` module from `iced_renderer` --- renderer/src/custom.rs | 162 ------------------------------------------------- 1 file changed, 162 deletions(-) delete mode 100644 renderer/src/custom.rs (limited to 'renderer/src') diff --git a/renderer/src/custom.rs b/renderer/src/custom.rs deleted file mode 100644 index 4addeb86..00000000 --- a/renderer/src/custom.rs +++ /dev/null @@ -1,162 +0,0 @@ -use crate::core::image; -use crate::core::renderer; -use crate::core::svg; -use crate::core::text::Text; -use crate::core::{ - Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, -}; -use crate::graphics::compositor; -use crate::graphics::text::{Editor, Paragraph}; -use crate::graphics::{Mesh, Viewport}; - -#[cfg(feature = "geometry")] -use crate::graphics::geometry::{self, Fill, Path, Stroke}; - -use std::borrow::Cow; - -pub trait Renderer { - fn draw_mesh(&mut self, mesh: Mesh); - - fn start_layer(&mut self); - - fn end_layer(&mut self, bounds: Rectangle); - - fn start_transformation(&mut self); - - fn end_transformation(&mut self, transformation: Transformation); - - fn fill_quad(&mut self, quad: renderer::Quad, background: Background); - - fn clear(&mut self); - - fn default_font(&self) -> Font; - - fn default_size(&self) -> Pixels; - - fn load_font(&mut self, bytes: Cow<'static, [u8]>); - - fn fill_paragraph( - &mut self, - paragraph: &Paragraph, - position: Point, - color: Color, - clip_bounds: Rectangle, - ); - - fn fill_editor( - &mut self, - editor: &Editor, - position: Point, - color: Color, - clip_bounds: Rectangle, - ); - - fn fill_text( - &mut self, - text: Text<'_, Font>, - position: Point, - color: Color, - clip_bounds: Rectangle, - ); - - fn measure_image(&self, handle: &image::Handle) -> Size; - - fn draw_image( - &mut self, - handle: image::Handle, - filter_method: image::FilterMethod, - bounds: Rectangle, - ); - - fn measure_svg(&self, handle: &svg::Handle) -> Size; - - fn draw_svg( - &mut self, - handle: crate::core::svg::Handle, - color: Option, - bounds: Rectangle, - ); - - #[cfg(feature = "geometry")] - fn new_frame(&self, size: Size) -> Box; - - #[cfg(feature = "geometry")] - fn draw_geometry(&mut self, geometry: Box); - - fn present( - &mut self, - surface: &mut dyn Surface, - viewport: &Viewport, - background_color: Color, - compositor: &mut dyn Compositor, - ) -> Result<(), compositor::SurfaceError>; -} - -#[cfg(feature = "geometry")] -pub trait Frame: std::any::Any { - fn width(&self) -> f32; - - fn height(&self) -> f32; - - fn size(&self) -> Size; - - fn center(&self) -> Point; - - fn fill(&mut self, path: &Path, fill: Fill); - - fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: Fill); - - fn stroke(&mut self, path: &Path, stroke: Stroke<'_>); - - fn fill_text(&mut self, text: geometry::Text); - - fn translate(&mut self, translation: crate::core::Vector); - - fn rotate(&mut self, angle: crate::core::Radians); - - fn scale(&mut self, scale: f32); - - fn scale_nonuniform(&mut self, scale: crate::core::Vector); - - fn push_transform(&mut self); - - fn pop_transform(&mut self); - - fn clip(&mut self, frame: Box, origin: Point); - - fn into_geometry(self: Box) -> Box; -} - -#[cfg(feature = "geometry")] -pub trait Geometry: std::any::Any + std::fmt::Debug { - fn transform( - self: Box, - transformation: Transformation, - ) -> Box; - - fn cache(self: Box) -> std::sync::Arc; - - fn load(self: std::sync::Arc) -> Box; -} - -pub trait Compositor: std::any::Any { - fn create_renderer(&self) -> Box; - - fn create_surface( - &mut self, - window: Box, - width: u32, - height: u32, - ) -> Box; - - fn configure_surface( - &mut self, - surface: &mut dyn Surface, - width: u32, - height: u32, - ); - - fn fetch_information(&self) -> compositor::Information; -} - -pub trait Surface: std::any::Any {} -- cgit From 53a183fe0d6aed460fbb8155ac9541757277aab3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 01:35:14 +0100 Subject: Restore `canvas::Frame` API --- renderer/src/fallback.rs | 20 ++-- renderer/src/geometry.rs | 236 ----------------------------------------- renderer/src/geometry/cache.rs | 137 ------------------------ 3 files changed, 7 insertions(+), 386 deletions(-) delete mode 100644 renderer/src/geometry.rs delete mode 100644 renderer/src/geometry/cache.rs (limited to 'renderer/src') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index a4c725c0..659f253d 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -459,10 +459,10 @@ mod geometry { Right(R), } - impl geometry::Frame for Frame + impl geometry::frame::Backend for Frame where - L: geometry::Frame, - R: geometry::Frame, + L: geometry::frame::Backend, + R: geometry::frame::Backend, { type Geometry = Geometry; @@ -545,17 +545,11 @@ mod geometry { fn scale_nonuniform(&mut self, scale: impl Into) { delegate!(self, frame, frame.scale_nonuniform(scale)); } - } - impl From> for Geometry - where - L: geometry::Frame, - R: geometry::Frame, - { - fn from(frame: Frame) -> Self { - match frame { - Frame::Left(frame) => Self::Left(frame.into()), - Frame::Right(frame) => Self::Right(frame.into()), + fn into_geometry(self) -> Self::Geometry { + match self { + Frame::Left(frame) => Geometry::Left(frame.into_geometry()), + Frame::Right(frame) => Geometry::Right(frame.into_geometry()), } } } diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs deleted file mode 100644 index a16cecd5..00000000 --- a/renderer/src/geometry.rs +++ /dev/null @@ -1,236 +0,0 @@ -mod cache; - -pub use cache::Cache; - -use crate::core::{Point, Radians, Rectangle, Size, Transformation, Vector}; -use crate::graphics::geometry::{Fill, Path, Stroke, Text}; -use crate::Renderer; - -macro_rules! delegate { - ($frame:expr, $name:ident, $body:expr) => { - match $frame { - Self::TinySkia($name) => $body, - #[cfg(feature = "wgpu")] - Self::Wgpu($name) => $body, - #[cfg(feature = "custom")] - Self::Custom($name) => $body, - } - }; -} - -pub enum Geometry { - TinySkia(iced_tiny_skia::Primitive), - #[cfg(feature = "wgpu")] - Wgpu(iced_wgpu::Primitive), - #[cfg(feature = "custom")] - Custom(Box), -} - -impl Geometry { - pub fn transform(self, transformation: Transformation) -> Self { - match self { - Self::TinySkia(primitive) => { - Self::TinySkia(primitive.transform(transformation)) - } - #[cfg(feature = "wgpu")] - Self::Wgpu(primitive) => { - Self::Wgpu(primitive.transform(transformation)) - } - #[cfg(feature = "custom")] - Self::Custom(geometry) => { - Self::Custom(geometry.transform(transformation)) - } - } - } -} - -pub enum Frame { - TinySkia(iced_tiny_skia::geometry::Frame), - #[cfg(feature = "wgpu")] - Wgpu(iced_wgpu::geometry::Frame), - #[cfg(feature = "custom")] - Custom(Box), -} - -impl Frame { - pub fn new(renderer: &Renderer, size: Size) -> Self { - match renderer { - Renderer::TinySkia(_) => { - Frame::TinySkia(iced_tiny_skia::geometry::Frame::new(size)) - } - #[cfg(feature = "wgpu")] - Renderer::Wgpu(_) => { - Frame::Wgpu(iced_wgpu::geometry::Frame::new(size)) - } - #[cfg(feature = "custom")] - Renderer::Custom(renderer) => { - Frame::Custom(renderer.new_frame(size)) - } - } - } - - /// Returns the width of the [`Frame`]. - #[inline] - pub fn width(&self) -> f32 { - delegate!(self, frame, frame.width()) - } - - /// Returns the height of the [`Frame`]. - #[inline] - pub fn height(&self) -> f32 { - delegate!(self, frame, frame.height()) - } - - /// Returns the dimensions of the [`Frame`]. - #[inline] - pub fn size(&self) -> Size { - delegate!(self, frame, frame.size()) - } - - /// Returns the coordinate of the center of the [`Frame`]. - #[inline] - pub fn center(&self) -> Point { - delegate!(self, frame, frame.center()) - } - - /// Draws the given [`Path`] on the [`Frame`] by filling it with the - /// provided style. - pub fn fill(&mut self, path: &Path, fill: impl Into) { - delegate!(self, frame, frame.fill(path, fill.into())); - } - - /// Draws an axis-aligned rectangle given its top-left corner coordinate and - /// its `Size` on the [`Frame`] by filling it with the provided style. - pub fn fill_rectangle( - &mut self, - top_left: Point, - size: Size, - fill: impl Into, - ) { - delegate!( - self, - frame, - frame.fill_rectangle(top_left, size, fill.into()) - ); - } - - /// Draws the stroke of the given [`Path`] on the [`Frame`] with the - /// provided style. - pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>) { - delegate!(self, frame, frame.stroke(path, stroke.into())); - } - - /// Draws the characters of the given [`Text`] on the [`Frame`], filling - /// them with the given color. - /// - /// __Warning:__ Text currently does not work well with rotations and scale - /// transforms! The position will be correctly transformed, but the - /// resulting glyphs will not be rotated or scaled properly. - /// - /// Additionally, all text will be rendered on top of all the layers of - /// a `Canvas`. Therefore, it is currently only meant to be used for - /// overlays, which is the most common use case. - /// - /// Support for vectorial text is planned, and should address all these - /// limitations. - pub fn fill_text(&mut self, text: impl Into) { - delegate!(self, frame, frame.fill_text(text.into())); - } - - /// Stores the current transform of the [`Frame`] and executes the given - /// drawing operations, restoring the transform afterwards. - /// - /// This method is useful to compose transforms and perform drawing - /// operations in different coordinate systems. - #[inline] - pub fn with_save(&mut self, f: impl FnOnce(&mut Frame) -> R) -> R { - delegate!(self, frame, frame.push_transform()); - - let result = f(self); - - delegate!(self, frame, frame.pop_transform()); - - result - } - - /// Executes the given drawing operations within a [`Rectangle`] region, - /// clipping any geometry that overflows its bounds. Any transformations - /// performed are local to the provided closure. - /// - /// This method is useful to perform drawing operations that need to be - /// clipped. - #[inline] - pub fn with_clip( - &mut self, - region: Rectangle, - f: impl FnOnce(&mut Frame) -> R, - ) -> R { - let mut frame = match self { - Self::TinySkia(_) => Self::TinySkia( - iced_tiny_skia::geometry::Frame::new(region.size()), - ), - #[cfg(feature = "wgpu")] - Self::Wgpu(_) => { - Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size())) - } - #[cfg(feature = "custom")] - Self::Custom(frame) => Self::Custom(frame.new(region.size())), - }; - - let result = f(&mut frame); - - let origin = Point::new(region.x, region.y); - - match (self, frame) { - (Self::TinySkia(target), Self::TinySkia(frame)) => { - target.clip(frame, origin); - } - #[cfg(feature = "wgpu")] - (Self::Wgpu(target), Self::Wgpu(frame)) => { - target.clip(frame, origin); - } - #[cfg(feature = "custom")] - (Self::Custom(target), Self::Custom(frame)) => { - target.clip(frame, origin); - } - #[allow(unreachable_patterns)] - _ => unreachable!(), - }; - - result - } - - /// Applies a translation to the current transform of the [`Frame`]. - #[inline] - pub fn translate(&mut self, translation: Vector) { - delegate!(self, frame, frame.translate(translation)); - } - - /// Applies a rotation in radians to the current transform of the [`Frame`]. - #[inline] - pub fn rotate(&mut self, angle: impl Into) { - delegate!(self, frame, frame.rotate(angle.into())); - } - - /// Applies a uniform scaling to the current transform of the [`Frame`]. - #[inline] - pub fn scale(&mut self, scale: impl Into) { - delegate!(self, frame, frame.scale(scale.into())); - } - - /// Applies a non-uniform scaling to the current transform of the [`Frame`]. - #[inline] - pub fn scale_nonuniform(&mut self, scale: impl Into) { - delegate!(self, frame, frame.scale_nonuniform(scale.into())); - } - - pub fn into_geometry(self) -> Geometry { - match self { - Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()), - #[cfg(feature = "wgpu")] - Self::Wgpu(frame) => Geometry::Wgpu(frame.into_primitive()), - #[cfg(feature = "custom")] - Self::Custom(frame) => Geometry::Custom(frame.into_geometry()), - } - } -} diff --git a/renderer/src/geometry/cache.rs b/renderer/src/geometry/cache.rs deleted file mode 100644 index 20f73f22..00000000 --- a/renderer/src/geometry/cache.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::core::Size; -use crate::geometry::{Frame, Geometry}; -use crate::Renderer; - -use std::cell::RefCell; -use std::sync::Arc; - -/// A simple cache that stores generated [`Geometry`] to avoid recomputation. -/// -/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer -/// change or it is explicitly cleared. -#[derive(Debug, Default)] -pub struct Cache { - state: RefCell, -} - -#[derive(Debug, Default)] -enum State { - #[default] - Empty, - Filled { - bounds: Size, - primitive: Internal, - }, -} - -#[derive(Debug, Clone)] -enum Internal { - TinySkia(Arc), - #[cfg(feature = "wgpu")] - Wgpu(Arc), - #[cfg(feature = "custom")] - Custom(Arc), -} - -impl Cache { - /// Creates a new empty [`Cache`]. - pub fn new() -> Self { - Cache { - state: RefCell::default(), - } - } - - /// Clears the [`Cache`], forcing a redraw the next time it is used. - pub fn clear(&self) { - *self.state.borrow_mut() = State::Empty; - } - - /// Draws [`Geometry`] using the provided closure and stores it in the - /// [`Cache`]. - /// - /// The closure will only be called when - /// - the bounds have changed since the previous draw call. - /// - the [`Cache`] is empty or has been explicitly cleared. - /// - /// Otherwise, the previously stored [`Geometry`] will be returned. The - /// [`Cache`] is not cleared in this case. In other words, it will keep - /// returning the stored [`Geometry`] if needed. - pub fn draw( - &self, - renderer: &Renderer, - bounds: Size, - draw_fn: impl FnOnce(&mut Frame), - ) -> Geometry { - use std::ops::Deref; - - if let State::Filled { - bounds: cached_bounds, - primitive, - } = self.state.borrow().deref() - { - if *cached_bounds == bounds { - match primitive { - Internal::TinySkia(primitive) => { - return Geometry::TinySkia( - iced_tiny_skia::Primitive::Cache { - content: primitive.clone(), - }, - ); - } - #[cfg(feature = "wgpu")] - Internal::Wgpu(primitive) => { - return Geometry::Wgpu(iced_wgpu::Primitive::Cache { - content: primitive.clone(), - }); - } - #[cfg(feature = "custom")] - Internal::Custom(geometry) => { - return Geometry::Custom(geometry.clone().load()) - } - } - } - } - - let mut frame = Frame::new(renderer, bounds); - draw_fn(&mut frame); - - let primitive = { - let geometry = frame.into_geometry(); - - match geometry { - Geometry::TinySkia(primitive) => { - Internal::TinySkia(Arc::new(primitive)) - } - #[cfg(feature = "wgpu")] - Geometry::Wgpu(primitive) => { - Internal::Wgpu(Arc::new(primitive)) - } - #[cfg(feature = "custom")] - Geometry::Custom(geometry) => { - Internal::Custom(geometry.cache()) - } - } - }; - - *self.state.borrow_mut() = State::Filled { - bounds, - primitive: primitive.clone(), - }; - - match primitive { - Internal::TinySkia(primitive) => { - Geometry::TinySkia(iced_tiny_skia::Primitive::Cache { - content: primitive, - }) - } - #[cfg(feature = "wgpu")] - Internal::Wgpu(primitive) => { - Geometry::Wgpu(iced_wgpu::Primitive::Cache { - content: primitive, - }) - } - #[cfg(feature = "custom")] - Internal::Custom(geometry) => Geometry::Custom(geometry.load()), - } - } -} -- cgit From 85800c99ab285efd244c0addfdcf3c732a98de1d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 01:53:48 +0100 Subject: Fix broken links in documentation --- renderer/src/fallback.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'renderer/src') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 659f253d..249da9e9 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -398,6 +398,7 @@ mod geometry { use super::Renderer; use crate::core::{Point, Radians, Size, Vector}; use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; + use crate::graphics::Cached; impl geometry::Renderer for Renderer where @@ -432,10 +433,10 @@ mod geometry { Right(R), } - impl geometry::Geometry for Geometry + impl Cached for Geometry where - L: geometry::Geometry, - R: geometry::Geometry, + L: Cached, + R: Cached, { type Cache = Geometry; -- cgit From 1f13a91361258a1607c71f4840a26a6437f88612 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 05:27:31 +0100 Subject: Make `iced_tiny_skia` optional with a `tiny-skia` feature --- renderer/src/fallback.rs | 29 +------------------------- renderer/src/lib.rs | 53 ++++++++++++++++++++++++++++++------------------ renderer/src/settings.rs | 5 +++++ 3 files changed, 39 insertions(+), 48 deletions(-) (limited to 'renderer/src') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 249da9e9..4431606a 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -8,11 +8,7 @@ use crate::graphics; use crate::graphics::compositor; use crate::graphics::mesh; -pub enum Renderer -where - L: core::Renderer, - R: core::Renderer, -{ +pub enum Renderer { Left(L), Right(R), } @@ -26,29 +22,6 @@ macro_rules! delegate { }; } -impl Renderer -where - L: core::Renderer, - R: core::Renderer, -{ - #[cfg(feature = "geometry")] - pub fn draw_geometry( - &mut self, - layers: impl IntoIterator, - ) where - L: graphics::geometry::Renderer, - R: graphics::geometry::Renderer, - - Geometry: Into>, - { - use graphics::geometry::Renderer; - - for layer in layers { - ::draw_geometry(self, layer.into()); - } - } -} - impl core::Renderer for Renderer where L: core::Renderer, diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index f8aa1157..199b431e 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -19,27 +19,40 @@ pub use settings::Settings; /// The default graphics renderer for [`iced`]. /// /// [`iced`]: https://github.com/iced-rs/iced -#[cfg(not(feature = "wgpu"))] -pub type Renderer = iced_tiny_skia::Renderer; - -/// The default graphics renderer for [`iced`]. -/// -/// [`iced`]: https://github.com/iced-rs/iced -#[cfg(feature = "wgpu")] -pub type Renderer = - fallback::Renderer; +pub type Renderer = renderer::Renderer; /// The default graphics compositor for [`iced`]. /// /// [`iced`]: https://github.com/iced-rs/iced -#[cfg(not(feature = "wgpu"))] -pub type Compositor = iced_tiny_skia::window::Compositor; - -/// The default graphics renderer for [`iced`]. -/// -/// [`iced`]: https://github.com/iced-rs/iced -#[cfg(feature = "wgpu")] -pub type Compositor = fallback::Compositor< - iced_wgpu::window::Compositor, - iced_tiny_skia::window::Compositor, ->; +pub type Compositor = renderer::Compositor; + +#[cfg(all(feature = "wgpu", feature = "tiny-skia"))] +mod renderer { + pub type Renderer = crate::fallback::Renderer< + iced_wgpu::Renderer, + iced_tiny_skia::Renderer, + >; + + pub type Compositor = crate::fallback::Compositor< + iced_wgpu::window::Compositor, + iced_tiny_skia::window::Compositor, + >; +} + +#[cfg(all(feature = "wgpu", not(feature = "tiny-skia")))] +mod renderer { + pub type Renderer = iced_wgpu::Renderer; + pub type Compositor = iced_wgpu::window::Compositor; +} + +#[cfg(all(not(feature = "wgpu"), feature = "tiny-skia"))] +mod renderer { + pub type Renderer = iced_tiny_skia::Renderer; + pub type Compositor = iced_tiny_skia::window::Compositor; +} + +#[cfg(not(any(feature = "wgpu", feature = "tiny-skia")))] +mod renderer { + pub type Renderer = (); + pub type Compositor = (); +} diff --git a/renderer/src/settings.rs b/renderer/src/settings.rs index 940daa15..27788db9 100644 --- a/renderer/src/settings.rs +++ b/renderer/src/settings.rs @@ -28,6 +28,7 @@ impl Default for Settings { } } +#[cfg(feature = "tiny-skia")] impl From for iced_tiny_skia::Settings { fn from(settings: Settings) -> Self { Self { @@ -48,3 +49,7 @@ impl From for iced_wgpu::Settings { } } } + +impl From for () { + fn from(_settings: Settings) -> Self {} +} -- cgit From 5137d655e6bbd29581fc1469d0385515113f2999 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 07:09:51 +0100 Subject: Allow custom renderers in `Program` and `Application` --- renderer/src/fallback.rs | 13 ++++++++---- renderer/src/lib.rs | 4 ---- renderer/src/settings.rs | 55 ------------------------------------------------ 3 files changed, 9 insertions(+), 63 deletions(-) delete mode 100644 renderer/src/settings.rs (limited to 'renderer/src') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 4431606a..28e73dd8 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -200,15 +200,12 @@ impl graphics::Compositor for Compositor where L: graphics::Compositor, R: graphics::Compositor, - L::Settings: From, - R::Settings: From, { - type Settings = crate::Settings; type Renderer = Renderer; type Surface = Surface; async fn new( - settings: Self::Settings, + settings: graphics::Settings, compatible_window: W, ) -> Result { if let Ok(left) = L::new(settings.into(), compatible_window.clone()) @@ -528,3 +525,11 @@ mod geometry { } } } + +impl compositor::Renderer for Renderer +where + L: compositor::Renderer, + R: compositor::Renderer, +{ + type Compositor = Compositor; +} diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 199b431e..7c48995d 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -6,16 +6,12 @@ pub use iced_wgpu as wgpu; pub mod fallback; -mod settings; - pub use iced_graphics as graphics; pub use iced_graphics::core; #[cfg(feature = "geometry")] pub use iced_graphics::geometry; -pub use settings::Settings; - /// The default graphics renderer for [`iced`]. /// /// [`iced`]: https://github.com/iced-rs/iced diff --git a/renderer/src/settings.rs b/renderer/src/settings.rs deleted file mode 100644 index 27788db9..00000000 --- a/renderer/src/settings.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::core::{Font, Pixels}; -use crate::graphics::Antialiasing; - -/// The settings of a Backend. -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Settings { - /// The default [`Font`] to use. - pub default_font: Font, - - /// The default size of text. - /// - /// By default, it will be set to `16.0`. - pub default_text_size: Pixels, - - /// The antialiasing strategy that will be used for triangle primitives. - /// - /// By default, it is `None`. - pub antialiasing: Option, -} - -impl Default for Settings { - fn default() -> Settings { - Settings { - default_font: Font::default(), - default_text_size: Pixels(16.0), - antialiasing: None, - } - } -} - -#[cfg(feature = "tiny-skia")] -impl From for iced_tiny_skia::Settings { - fn from(settings: Settings) -> Self { - Self { - default_font: settings.default_font, - default_text_size: settings.default_text_size, - } - } -} - -#[cfg(feature = "wgpu")] -impl From for iced_wgpu::Settings { - fn from(settings: Settings) -> Self { - Self { - default_font: settings.default_font, - default_text_size: settings.default_text_size, - antialiasing: settings.antialiasing, - ..iced_wgpu::Settings::default() - } - } -} - -impl From for () { - fn from(_settings: Settings) -> Self {} -} -- cgit From a2c897792ccb8f91a8479c1eca9146c439e9173b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 07:12:46 +0100 Subject: Fix unnecessary `into` calls in `iced_renderer::fallback` --- renderer/src/fallback.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'renderer/src') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 28e73dd8..8daab74f 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -208,16 +208,14 @@ where settings: graphics::Settings, compatible_window: W, ) -> Result { - if let Ok(left) = L::new(settings.into(), compatible_window.clone()) + if let Ok(left) = L::new(settings, compatible_window.clone()) .await .map(Self::Left) { return Ok(left); } - R::new(settings.into(), compatible_window) - .await - .map(Self::Right) + R::new(settings, compatible_window).await.map(Self::Right) } fn create_renderer(&self) -> Self::Renderer { -- cgit From 441e9237cd1c9c9b61d9b144b5b4dafa236ace28 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 19:35:19 +0100 Subject: Rename `compositor::Renderer` to `Default` --- renderer/src/fallback.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'renderer/src') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 8daab74f..ca445746 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -524,10 +524,10 @@ mod geometry { } } -impl compositor::Renderer for Renderer +impl compositor::Default for Renderer where - L: compositor::Renderer, - R: compositor::Renderer, + L: compositor::Default, + R: compositor::Default, { type Compositor = Compositor; } -- cgit From 4f5b63f1f4cd7d3ab72289c697f4abc767114eca Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 24 Mar 2024 08:04:28 +0100 Subject: Reintroduce backend selection through `ICED_BACKEND` env var --- renderer/src/fallback.rs | 51 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'renderer/src') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index ca445746..ef9cc9a9 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -204,18 +204,55 @@ where type Renderer = Renderer; type Surface = Surface; - async fn new( + async fn with_backend( settings: graphics::Settings, compatible_window: W, + backend: Option<&str>, ) -> Result { - if let Ok(left) = L::new(settings, compatible_window.clone()) - .await - .map(Self::Left) - { - return Ok(left); + use std::env; + + let backends = backend + .map(str::to_owned) + .or_else(|| env::var("ICED_BACKEND").ok()); + + let mut candidates: Vec<_> = backends + .map(|backends| { + backends + .split(',') + .filter(|candidate| !candidate.is_empty()) + .map(str::to_owned) + .map(Some) + .collect() + }) + .unwrap_or_default(); + + if candidates.is_empty() { + candidates.push(None); } - R::new(settings, compatible_window).await.map(Self::Right) + let mut errors = vec![]; + + for backend in candidates.iter().map(Option::as_deref) { + match L::with_backend(settings, compatible_window.clone(), backend) + .await + { + Ok(compositor) => return Ok(Self::Left(compositor)), + Err(error) => { + errors.push(error); + } + } + + match R::with_backend(settings, compatible_window.clone(), backend) + .await + { + Ok(compositor) => return Ok(Self::Right(compositor)), + Err(error) => { + errors.push(error); + } + } + } + + Err(graphics::Error::List(errors)) } fn create_renderer(&self) -> Self::Renderer { -- cgit