diff --git a/core/embed/rust/src/ui/shape/cache/drawing_cache.rs b/core/embed/rust/src/ui/shape/cache/drawing_cache.rs index 6f64d7f43c..b0d431b6f4 100644 --- a/core/embed/rust/src/ui/shape/cache/drawing_cache.rs +++ b/core/embed/rust/src/ui/shape/cache/drawing_cache.rs @@ -11,9 +11,9 @@ use without_alloc::alloc::LocalAllocLeakExt; const ALIGN_PAD: usize = 8; -#[cfg(feature = "xframebuff")] +#[cfg(feature = "xframebuffer")] const ZLIB_CACHE_SLOTS: usize = 1; -#[cfg(not(feature = "xframebuff"))] +#[cfg(not(feature = "xframebuffer"))] const ZLIB_CACHE_SLOTS: usize = 3; const RENDER_BUFF_SIZE: usize = (240 * 2 * 16) + ALIGN_PAD; @@ -39,7 +39,7 @@ pub struct DrawingCache<'a> { #[cfg(feature = "ui_blurring")] blur_cache: RefCell>, - #[cfg(not(feature = "xframebuff"))] + #[cfg(not(feature = "xframebuffer"))] render_buff: &'a RefCell, } @@ -67,7 +67,7 @@ impl<'a> DrawingCache<'a> { #[cfg(feature = "ui_blurring")] blur_cache: RefCell::new(unwrap!(BlurCache::new(bump_a), "Blur cache alloc")), - #[cfg(not(feature = "xframebuff"))] + #[cfg(not(feature = "xframebuffer"))] render_buff: unwrap!(alloc_buf(bump_b), "Render buff alloc"), } } @@ -90,7 +90,7 @@ impl<'a> DrawingCache<'a> { } /// Returns a buffer used for ProgressiveRenderer slice - #[cfg(not(feature = "xframebuff"))] + #[cfg(not(feature = "xframebuffer"))] pub fn render_buff(&self) -> Option> { self.render_buff.try_borrow_mut().ok() } @@ -122,7 +122,7 @@ impl<'a> DrawingCache<'a> { pub const fn get_bump_b_size() -> usize { let mut size = 0; - #[cfg(not(feature = "xframebuff"))] + #[cfg(not(feature = "xframebuffer"))] { size += core::mem::size_of::>(); } diff --git a/core/embed/rust/src/ui/shape/display/mod.rs b/core/embed/rust/src/ui/shape/display/mod.rs index 3da85bbf30..5fba9b1b57 100644 --- a/core/embed/rust/src/ui/shape/display/mod.rs +++ b/core/embed/rust/src/ui/shape/display/mod.rs @@ -10,7 +10,7 @@ pub mod fb_mono8; pub mod fb_rgb565; #[cfg(all(feature = "xframebuffer", feature = "display_rgba8888",))] pub mod fb_rgba8888; -#[cfg(feature = "display_rgb565")] +#[cfg(all(not(feature = "xframebuffer"), feature = "display_rgb565"))] pub mod nofb_rgb565; #[cfg(not(feature = "new_rendering"))] diff --git a/core/embed/rust/src/ui/shape/mod.rs b/core/embed/rust/src/ui/shape/mod.rs index 7497ee224a..fd9a70a2c7 100644 --- a/core/embed/rust/src/ui/shape/mod.rs +++ b/core/embed/rust/src/ui/shape/mod.rs @@ -10,6 +10,8 @@ mod corner_highlight; mod display; #[cfg(feature = "ui_jpeg_decoder")] mod jpeg; +#[cfg(not(feature = "xframebuffer"))] +mod progressive_render; mod qrcode; mod rawimage; mod render; @@ -31,9 +33,12 @@ pub use corner_highlight::CornerHighlight; pub use display::{render_on_canvas, render_on_display, unlock_bumps_on_failure, ConcreteRenderer}; #[cfg(feature = "ui_jpeg_decoder")] pub use jpeg::JpegImage; +#[cfg(not(feature = "xframebuffer"))] +pub use progressive_render::ProgressiveRenderer; pub use qrcode::QrImage; pub use rawimage::RawImage; -pub use render::{DirectRenderer, ProgressiveRenderer, Renderer, ScopedRenderer}; +pub use render::{DirectRenderer, Renderer, ScopedRenderer}; + pub use text::Text; pub use toif::ToifImage; #[cfg(feature = "ui_image_buffer")] diff --git a/core/embed/rust/src/ui/shape/progressive_render.rs b/core/embed/rust/src/ui/shape/progressive_render.rs new file mode 100644 index 0000000000..a38cc36b93 --- /dev/null +++ b/core/embed/rust/src/ui/shape/progressive_render.rs @@ -0,0 +1,143 @@ +use crate::ui::{ + display::Color, + geometry::{Offset, Point, Rect}, + shape::{BasicCanvas, Canvas, DrawingCache, Renderer, Shape, ShapeClone, Viewport}, +}; +use without_alloc::{alloc::LocalAllocLeakExt, FixedVec}; + +use super::Rgb565Canvas; + +struct ShapeHolder<'a> { + shape: &'a mut dyn Shape<'a>, + viewport: Viewport, +} + +/// A more advanced Renderer implementation that supports deferred rendering. +pub struct ProgressiveRenderer<'a, 'alloc, T, C> +where + T: LocalAllocLeakExt<'alloc>, + C: BasicCanvas, +{ + /// Target canvas + canvas: &'a mut C, + /// Bump for cloning shapes + bump: &'alloc T, + /// List of rendered shapes + shapes: FixedVec<'alloc, ShapeHolder<'alloc>>, + /// Current viewport + viewport: Viewport, + // Default background color + bg_color: Option, + /// Drawing cache (decompression context, scratch-pad memory) + cache: &'a DrawingCache<'alloc>, +} + +impl<'a, 'alloc, T, C> ProgressiveRenderer<'a, 'alloc, T, C> +where + T: LocalAllocLeakExt<'alloc>, + C: BasicCanvas, +{ + /// Creates a new ProgressiveRenderer instance + pub fn new( + canvas: &'a mut C, + bg_color: Option, + cache: &'a DrawingCache<'alloc>, + bump: &'alloc T, + max_shapes: usize, + ) -> Self { + let viewport = canvas.viewport(); + Self { + canvas, + bump, + shapes: unwrap!(bump.fixed_vec(max_shapes), "No shape memory"), + viewport, + bg_color, + cache, + } + } + + /// Renders stored shapes onto the specified canvas + pub fn render(&mut self, lines: usize) { + let canvas_clip = self.canvas.viewport().clip; + + if canvas_clip.is_empty() { + return; + } + + let buff = &mut unwrap!(self.cache.render_buff(), "No render buffer"); + + let mut slice = unwrap!( + Rgb565Canvas::new( + Offset::new(canvas_clip.width(), lines as i16), + None, + Some(1), + &mut buff[..], + ), + "No render memory" + ); + + let lines = slice.height() as usize; + + for y in (canvas_clip.y0..canvas_clip.y1).step_by(lines) { + // Calculate the coordinates of the slice we will draw into + let slice_r = Rect::new( + // slice_r is in absolute coordinates + Point::new(canvas_clip.x0, y), + Point::new(canvas_clip.x1, y + lines as i16), + ); + + // Clear the slice background + if let Some(color) = self.bg_color { + slice.set_viewport(Viewport::from_size(slice_r.size())); + slice.fill_background(color); + } + + // Draw all shapes that overlaps the slice + for holder in self.shapes.iter_mut() { + let shape_viewport = holder.viewport.absolute_clip(slice_r); + let shape_bounds = holder.shape.bounds(); + + // Is the shape overlapping the current slice? + if shape_viewport.contains(shape_bounds) { + slice.set_viewport(shape_viewport.translate((-slice_r.top_left()).into())); + holder.shape.draw(&mut slice, self.cache); + + if shape_bounds.y1 + shape_viewport.origin.y <= shape_viewport.clip.y1 { + // The shape will never be drawn again + holder.shape.cleanup(self.cache); + } + } + } + self.canvas.draw_bitmap(slice_r, slice.view()); + } + } +} + +impl<'a, 'alloc, T, C> Renderer<'alloc> for ProgressiveRenderer<'a, 'alloc, T, C> +where + T: LocalAllocLeakExt<'alloc>, + C: BasicCanvas, +{ + fn viewport(&self) -> Viewport { + self.viewport + } + + fn set_viewport(&mut self, viewport: Viewport) { + self.viewport = viewport.absolute_clip(self.canvas.bounds()); + } + + fn render_shape(&mut self, shape: S) + where + S: Shape<'alloc> + ShapeClone<'alloc>, + { + // Is the shape visible? + if self.viewport.contains(shape.bounds()) { + // Clone the shape & push it to the list + let holder = ShapeHolder { + shape: unwrap!(shape.clone_at_bump(self.bump), "No shape memory"), + viewport: self.viewport, + }; + unwrap!(self.shapes.push(holder), "Shape list full"); + } + } +} diff --git a/core/embed/rust/src/ui/shape/render.rs b/core/embed/rust/src/ui/shape/render.rs index 7551febc09..9a59a996a0 100644 --- a/core/embed/rust/src/ui/shape/render.rs +++ b/core/embed/rust/src/ui/shape/render.rs @@ -1,11 +1,9 @@ use crate::ui::{ display::Color, - geometry::{Offset, Point, Rect}, + geometry::{Offset, Rect}, }; -use super::{BasicCanvas, Canvas, DrawingCache, Rgb565Canvas, Shape, ShapeClone, Viewport}; - -use without_alloc::{alloc::LocalAllocLeakExt, FixedVec}; +use super::{Canvas, DrawingCache, Shape, ShapeClone, Viewport}; // ========================================================================== // trait Renderer @@ -114,145 +112,6 @@ where } } -// ========================================================================== -// struct ProgressiveRenderer -// ========================================================================== - -struct ShapeHolder<'a> { - shape: &'a mut dyn Shape<'a>, - viewport: Viewport, -} - -/// A more advanced Renderer implementation that supports deferred rendering. -pub struct ProgressiveRenderer<'a, 'alloc, T, C> -where - T: LocalAllocLeakExt<'alloc>, - C: BasicCanvas, -{ - /// Target canvas - canvas: &'a mut C, - /// Bump for cloning shapes - bump: &'alloc T, - /// List of rendered shapes - shapes: FixedVec<'alloc, ShapeHolder<'alloc>>, - /// Current viewport - viewport: Viewport, - // Default background color - bg_color: Option, - /// Drawing cache (decompression context, scratch-pad memory) - cache: &'a DrawingCache<'alloc>, -} - -impl<'a, 'alloc, T, C> ProgressiveRenderer<'a, 'alloc, T, C> -where - T: LocalAllocLeakExt<'alloc>, - C: BasicCanvas, -{ - /// Creates a new ProgressiveRenderer instance - pub fn new( - canvas: &'a mut C, - bg_color: Option, - cache: &'a DrawingCache<'alloc>, - bump: &'alloc T, - max_shapes: usize, - ) -> Self { - let viewport = canvas.viewport(); - Self { - canvas, - bump, - shapes: unwrap!(bump.fixed_vec(max_shapes), "No shape memory"), - viewport, - bg_color, - cache, - } - } - - /// Renders stored shapes onto the specified canvas - pub fn render(&mut self, lines: usize) { - let canvas_clip = self.canvas.viewport().clip; - - if canvas_clip.is_empty() { - return; - } - - let buff = &mut unwrap!(self.cache.render_buff(), "No render buffer"); - - let mut slice = unwrap!( - Rgb565Canvas::new( - Offset::new(canvas_clip.width(), lines as i16), - None, - Some(1), - &mut buff[..], - ), - "No render memory" - ); - - let lines = slice.height() as usize; - - for y in (canvas_clip.y0..canvas_clip.y1).step_by(lines) { - // Calculate the coordinates of the slice we will draw into - let slice_r = Rect::new( - // slice_r is in absolute coordinates - Point::new(canvas_clip.x0, y), - Point::new(canvas_clip.x1, y + lines as i16), - ); - - // Clear the slice background - if let Some(color) = self.bg_color { - slice.set_viewport(Viewport::from_size(slice_r.size())); - slice.fill_background(color); - } - - // Draw all shapes that overlaps the slice - for holder in self.shapes.iter_mut() { - let shape_viewport = holder.viewport.absolute_clip(slice_r); - let shape_bounds = holder.shape.bounds(); - - // Is the shape overlapping the current slice? - if shape_viewport.contains(shape_bounds) { - slice.set_viewport(shape_viewport.translate((-slice_r.top_left()).into())); - holder.shape.draw(&mut slice, self.cache); - - if shape_bounds.y1 + shape_viewport.origin.y <= shape_viewport.clip.y1 { - // The shape will never be drawn again - holder.shape.cleanup(self.cache); - } - } - } - self.canvas.draw_bitmap(slice_r, slice.view()); - } - } -} - -impl<'a, 'alloc, T, C> Renderer<'alloc> for ProgressiveRenderer<'a, 'alloc, T, C> -where - T: LocalAllocLeakExt<'alloc>, - C: BasicCanvas, -{ - fn viewport(&self) -> Viewport { - self.viewport - } - - fn set_viewport(&mut self, viewport: Viewport) { - self.viewport = viewport.absolute_clip(self.canvas.bounds()); - } - - fn render_shape(&mut self, shape: S) - where - S: Shape<'alloc> + ShapeClone<'alloc>, - { - // Is the shape visible? - if self.viewport.contains(shape.bounds()) { - // Clone the shape & push it to the list - let holder = ShapeHolder { - shape: unwrap!(shape.clone_at_bump(self.bump), "No shape memory"), - viewport: self.viewport, - }; - unwrap!(self.shapes.push(holder), "Shape list full"); - } - } -} - pub struct ScopedRenderer<'alloc, 'env, T> where 'env: 'alloc,