diff --git a/core/embed/gfx/bitblt/gfx_bitblt_rgba8888.c b/core/embed/gfx/bitblt/gfx_bitblt_rgba8888.c index dea5c4881e..216b74e33d 100644 --- a/core/embed/gfx/bitblt/gfx_bitblt_rgba8888.c +++ b/core/embed/gfx/bitblt/gfx_bitblt_rgba8888.c @@ -125,10 +125,10 @@ void gfx_rgba8888_copy_rgba8888(const gfx_bitblt_t* bb) { while (height-- > 0) { for (int x = 0; x < bb->width; x++) { - dst_ptr[x] = src_ptr[x]; + dst_ptr[x] = src_ptr[x << bb->src_downscale]; } dst_ptr += bb->dst_stride / sizeof(*dst_ptr); - src_ptr += bb->src_stride / sizeof(*src_ptr); + src_ptr += (bb->src_stride / sizeof(*src_ptr)) << bb->src_downscale; } } } diff --git a/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c b/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c index cf682c0199..dbeab190e1 100644 --- a/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c +++ b/core/embed/gfx/bitblt/stm32/dma2d_bitblt.c @@ -771,6 +771,10 @@ bool dma2d_rgba8888_copy_rgba8888(const gfx_bitblt_t* bb) { return false; } + if (bb->src_downscale > 0) { + return false; + } + drv->handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; drv->handle.Init.Mode = DMA2D_M2M_PFC; drv->handle.Init.OutputOffset = bb->dst_stride / sizeof(uint32_t) - bb->width; diff --git a/core/embed/gfx/inc/gfx/gfx_bitblt.h b/core/embed/gfx/inc/gfx/gfx_bitblt.h index 27ddaa2557..a458566048 100644 --- a/core/embed/gfx/inc/gfx/gfx_bitblt.h +++ b/core/embed/gfx/inc/gfx/gfx_bitblt.h @@ -72,6 +72,9 @@ typedef struct { gfx_color_t src_bg; // Alpha value for fill operation (255 => normal fill, 0 => noop) uint8_t src_alpha; + // Downscaling for the source bitmap + // (0 => no downscaling, 1 => 1/2, 2 => 1/4, 3 => 1/8) + uint8_t src_downscale; } gfx_bitblt_t; diff --git a/core/embed/rust/src/trezorhal/bitblt.rs b/core/embed/rust/src/trezorhal/bitblt.rs index 7d4fcc2f00..58715f3a65 100644 --- a/core/embed/rust/src/trezorhal/bitblt.rs +++ b/core/embed/rust/src/trezorhal/bitblt.rs @@ -31,6 +31,7 @@ impl Default for ffi::gfx_bitblt_t { src_x: 0, src_y: 0, src_alpha: 255, + src_downscale: 0, } } } @@ -128,6 +129,15 @@ impl ffi::gfx_bitblt_t { ..self } } + + /// Sets the downscaling for the source bitmap. + /// (0 = no downscale, 1 = 1/2, 2 = 1/4, 3 = 1/8) + fn with_downscale(self, downscale: u8) -> Self { + Self { + src_downscale: downscale, + ..self + } + } } /// Rectangle filling operation. @@ -250,16 +260,18 @@ impl<'a> BitBltCopy<'a> { // Clip with the bitmap top-left if r.x0 > r_dst.x0 { - offset.x += r.x0 - r_dst.x0; + offset.x += (r.x0 - r_dst.x0) << src.downscale; } if r.y0 > r_dst.y0 { - offset.y += r.y0 - r_dst.y0; + offset.y += (r.y0 - r_dst.y0) << src.downscale; } // Clip with the bitmap size - r.x1 = r.x1.min(r.x0 + src.size().x - offset.x); - r.y1 = r.y1.min(r.y0 + src.size().y - offset.y); + r.x1 = + r.x1.min(r.x0 + ((src.size().x - offset.x) >> src.downscale)); + r.y1 = + r.y1.min(r.y0 + ((src.size().y - offset.y) >> src.downscale)); if !r.is_empty() { Some(Self { @@ -280,6 +292,7 @@ impl<'a> BitBltCopy<'a> { .with_bg(src.bg_color) .with_fg(src.fg_color) .with_alpha(src.alpha) + .with_downscale(src.downscale) }, src, }) diff --git a/core/embed/rust/src/ui/shape/bitmap.rs b/core/embed/rust/src/ui/shape/bitmap.rs index e828412dd2..b13868cab3 100644 --- a/core/embed/rust/src/ui/shape/bitmap.rs +++ b/core/embed/rust/src/ui/shape/bitmap.rs @@ -300,6 +300,7 @@ pub struct BitmapView<'a> { pub fg_color: Color, pub bg_color: Color, pub alpha: u8, + pub downscale: u8, } impl<'a> BitmapView<'a> { @@ -311,6 +312,7 @@ impl<'a> BitmapView<'a> { fg_color: Color::black(), bg_color: Color::black(), alpha: 255, + downscale: 0, } } @@ -337,6 +339,12 @@ impl<'a> BitmapView<'a> { Self { alpha, ..self } } + /// Builds a new structure with downscale set to the specified value + /// (0 means no downscale, 1 means 1/2, 2 means 1/4, etc.) + pub fn with_downscale(self, downscale: u8) -> Self { + Self { downscale, ..self } + } + /// Returns the bitmap width and height in pixels pub fn size(&self) -> Offset { self.bitmap.size diff --git a/core/embed/rust/src/ui/shape/jpeg.rs b/core/embed/rust/src/ui/shape/jpeg.rs index 2fa5f27e71..f6574c07da 100644 --- a/core/embed/rust/src/ui/shape/jpeg.rs +++ b/core/embed/rust/src/ui/shape/jpeg.rs @@ -108,8 +108,6 @@ impl<'a> Shape<'a> for JpegImage<'a> { let bounds = self.bounds(); let clip = canvas.viewport().relative_clip(bounds).clip; - let vp = canvas.set_clip(clip); - // Translate clip to JPEG relative coordinates let clip = clip.translate(-canvas.viewport().origin); let clip = clip.translate((-bounds.top_left()).into()); @@ -119,6 +117,13 @@ impl<'a> Shape<'a> for JpegImage<'a> { let mut jpegdec = unwrap!(JpegDecoder::new(self.jpeg)); let _ = jpegdec.decode(&mut buff[..], &mut |slice_r, slice| { + let slice = slice.with_downscale(self.scale); + let slice_r = Rect { + x0: slice_r.x0 >> self.scale, + y0: slice_r.y0 >> self.scale, + x1: slice_r.x1 >> self.scale, + y1: slice_r.y1 >> self.scale, + }; // Draw single slice canvas.draw_bitmap(slice_r.translate(bounds.top_left().into()), slice); // Return true if we are not done yet @@ -136,8 +141,6 @@ impl<'a> Shape<'a> for JpegImage<'a> { // Blur the image canvas.blur_rect(clip, self.blur_radius, cache); } - - canvas.set_viewport(vp); } // This is a little bit slower implementation suitable for ProgressiveRenderer