From 2a123b3c5e8ebf0b57b35525ff6f90a0d777f11c Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Fri, 3 May 2024 13:49:53 +0200 Subject: [PATCH] feat(core): add alpha capabilities to 4-bit blending [no changelog] --- core/embed/lib/gfx_bitblt_mono8.c | 3 +- core/embed/lib/gfx_bitblt_rgb565.c | 3 +- core/embed/lib/gfx_bitblt_rgba8888.c | 3 +- core/embed/lib/gfx_color.h | 17 ++++++ core/embed/rust/src/trezorhal/bitblt.rs | 1 + core/embed/rust/src/ui/shape/bitmap.rs | 7 +++ core/embed/trezorhal/stm32f4/dma2d_bitblt.c | 61 ++++++++++++++------- 7 files changed, 71 insertions(+), 24 deletions(-) diff --git a/core/embed/lib/gfx_bitblt_mono8.c b/core/embed/lib/gfx_bitblt_mono8.c index 30966c6e08..c1cb85d660 100644 --- a/core/embed/lib/gfx_bitblt_mono8.c +++ b/core/embed/lib/gfx_bitblt_mono8.c @@ -102,7 +102,8 @@ void gfx_mono8_blend_mono4(const gfx_bitblt_t* bb) { for (int x = 0; x < bb->width; x++) { uint8_t src_data = src_row[(x + bb->src_x) / 2]; uint8_t src_alpha = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0x0F; - dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (15 - src_alpha)) / 15; + src_alpha = src_alpha * bb->src_alpha / 15; + dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (255 - src_alpha)); } dst_ptr += bb->dst_stride / sizeof(*dst_ptr); src_row += bb->src_stride / sizeof(*src_row); diff --git a/core/embed/lib/gfx_bitblt_rgb565.c b/core/embed/lib/gfx_bitblt_rgb565.c index a881ca12ab..5ee3059d3e 100644 --- a/core/embed/lib/gfx_bitblt_rgb565.c +++ b/core/embed/lib/gfx_bitblt_rgb565.c @@ -126,7 +126,8 @@ void gfx_rgb565_blend_mono4(const gfx_bitblt_t* bb) { for (int x = 0; x < bb->width; x++) { uint8_t fg_data = src_row[(x + bb->src_x) / 2]; uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F; - dst_ptr[x] = gfx_color16_blend_a4( + fg_alpha = fg_alpha * bb->src_alpha / 15; + dst_ptr[x] = gfx_color16_blend_a8( bb->src_fg, gfx_color16_to_color(dst_ptr[x]), fg_alpha); } dst_ptr += bb->dst_stride / sizeof(*dst_ptr); diff --git a/core/embed/lib/gfx_bitblt_rgba8888.c b/core/embed/lib/gfx_bitblt_rgba8888.c index 69a88bfde2..a7c50ddcc0 100644 --- a/core/embed/lib/gfx_bitblt_rgba8888.c +++ b/core/embed/lib/gfx_bitblt_rgba8888.c @@ -146,7 +146,8 @@ void gfx_rgba8888_blend_mono4(const gfx_bitblt_t* bb) { for (int x = 0; x < bb->width; x++) { uint8_t fg_data = src_row[(x + bb->src_x) / 2]; uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F; - dst_ptr[x] = gfx_color32_blend_a4( + fg_alpha = fg_alpha * bb->src_alpha / 15; + dst_ptr[x] = gfx_color32_blend_a8( bb->src_fg, gfx_color32_to_color(dst_ptr[x]), fg_alpha); } dst_ptr += bb->dst_stride / sizeof(*dst_ptr); diff --git a/core/embed/lib/gfx_color.h b/core/embed/lib/gfx_color.h index 4aac35d982..2258980981 100644 --- a/core/embed/lib/gfx_color.h +++ b/core/embed/lib/gfx_color.h @@ -75,6 +75,8 @@ typedef uint32_t gfx_color32_t; #define gfx_color32_to_g(c) (((c) & 0x0000FF00) >> 8) // Extracts blue component from gfx_color32_t #define gfx_color32_to_b(c) (((c) & 0x000000FF) >> 0) +// Extracts alpha component from gfx_color32_t +#define gfx_color32_to_a(c) (((c) & 0xFF000000) >> 0) // 4-bit linear interpolation between `fg` and `bg` #define a4_lerp(fg, bg, alpha) (((fg) * (alpha) + ((bg) * (15 - (alpha)))) / 15) @@ -95,6 +97,13 @@ static inline gfx_color32_t gfx_color32_rgb(uint8_t r, uint8_t g, uint8_t b) { return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } +// Constructs a 32-bit color from the given red (r), +// green (g), blue (b) and alhpa (a) values in the range 0..255. +static inline gfx_color32_t gfx_color32_rgba(uint8_t r, uint8_t g, uint8_t b, + uint8_t a) { + return (a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + // Converts a 16-bit color to a 32-bit color; alpha is set to 255 static inline gfx_color32_t gfx_color16_to_color32(gfx_color16_t color) { uint32_t r = gfx_color16_to_r(color); @@ -342,4 +351,12 @@ const gfx_color16_t* gfx_color16_gradient_a4(gfx_color_t fg, gfx_color_t bg); // the background (`bg`) color and `retval[15]` the foreground (`fg`) color const gfx_color32_t* gfx_color32_gradient_a4(gfx_color_t fg, gfx_color_t bg); +// Returns a color with alpha channel set +// +// The original color is not modified +static inline gfx_color32_t gfx_color32_set_alpha(gfx_color32_t c, + uint8_t alpha) { + return (c & 0xFFFFFF) | (alpha << 24); +} + #endif // GFX_COLOR_H diff --git a/core/embed/rust/src/trezorhal/bitblt.rs b/core/embed/rust/src/trezorhal/bitblt.rs index f5b6a2dd9c..4803a76593 100644 --- a/core/embed/rust/src/trezorhal/bitblt.rs +++ b/core/embed/rust/src/trezorhal/bitblt.rs @@ -281,6 +281,7 @@ impl<'a> BitBltCopy<'a> { .with_src(src.bitmap, offset.x, offset.y) .with_bg(src.bg_color) .with_fg(src.fg_color) + .with_alpha(src.alpha) }, src, }) diff --git a/core/embed/rust/src/ui/shape/bitmap.rs b/core/embed/rust/src/ui/shape/bitmap.rs index 2143c8dcc1..7c760ec846 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 offset: Offset, pub fg_color: Color, pub bg_color: Color, + pub alpha: u8, } impl<'a> BitmapView<'a> { @@ -310,6 +311,7 @@ impl<'a> BitmapView<'a> { offset: Offset::zero(), fg_color: Color::black(), bg_color: Color::black(), + alpha: 255, } } @@ -331,6 +333,11 @@ impl<'a> BitmapView<'a> { Self { bg_color, ..self } } + /// Builds a new structure with alpha set to the specified value + pub fn with_alpha(self, alpha: u8) -> Self { + Self { alpha, ..self } + } + /// Returns the bitmap width and height in pixels pub fn size(&self) -> Offset { self.bitmap.size diff --git a/core/embed/trezorhal/stm32f4/dma2d_bitblt.c b/core/embed/trezorhal/stm32f4/dma2d_bitblt.c index 8d43e5dbcc..36ec4762cb 100644 --- a/core/embed/trezorhal/stm32f4/dma2d_bitblt.c +++ b/core/embed/trezorhal/stm32f4/dma2d_bitblt.c @@ -97,13 +97,14 @@ bool dma2d_rgb565_fill(const gfx_bitblt_t* bb) { return true; } -static void dma2d_config_clut(uint32_t layer, gfx_color_t fg, gfx_color_t bg) { +static void dma2d_config_clut(uint32_t layer, gfx_color32_t fg, + gfx_color32_t bg) { #define LAYER_COUNT 2 #define GRADIENT_STEPS 16 static struct { - gfx_color_t c_fg; - gfx_color_t c_bg; + gfx_color32_t c_fg; + gfx_color32_t c_bg; } cache[LAYER_COUNT] = {0}; if (layer >= LAYER_COUNT) { @@ -118,15 +119,19 @@ static void dma2d_config_clut(uint32_t layer, gfx_color_t fg, gfx_color_t bg) { cache[layer].c_bg = bg; for (int step = 0; step < GRADIENT_STEPS; step++) { - clut[step] = gfx_color32_blend_a4(fg, bg, step); + clut[step] = gfx_color32_rgba( + a4_lerp(gfx_color32_to_r(fg), gfx_color32_to_r(bg), step), + a4_lerp(gfx_color32_to_g(fg), gfx_color32_to_g(bg), step), + a4_lerp(gfx_color32_to_b(fg), gfx_color32_to_b(bg), step), + a4_lerp(gfx_color32_to_a(fg), gfx_color32_to_a(bg), step)); } - DMA2D_CLUTCfgTypeDef clut; - clut.CLUTColorMode = DMA2D_CCM_ARGB8888; - clut.Size = GRADIENT_STEPS - 1; - clut.pCLUT = 0; // ??? + DMA2D_CLUTCfgTypeDef clut_def = {0}; + clut_def.CLUTColorMode = DMA2D_CCM_ARGB8888; + clut_def.Size = GRADIENT_STEPS - 1; + clut_def.pCLUT = 0; // ??? - HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut, layer); + HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut_def, layer); } } @@ -204,7 +209,8 @@ bool dma2d_rgb565_copy_mono4(const gfx_bitblt_t* params) { dma2d_handle.LayerCfg[1].InputAlpha = 0; HAL_DMA2D_ConfigLayer(&dma2d_handle, 1); - dma2d_config_clut(1, bb->src_fg, bb->src_bg); + dma2d_config_clut(1, gfx_color_to_color32(bb->src_fg), + gfx_color_to_color32(bb->src_bg)); HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2, (uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t), @@ -247,7 +253,8 @@ static void dma2d_rgb565_blend_mono4_first_col(const gfx_bitblt_t* bb) { while (height-- > 0) { uint8_t fg_alpha = src_ptr[0] >> 4; - dst_ptr[0] = gfx_color16_blend_a4( + fg_alpha = (fg_alpha * bb->src_alpha) / 15; + dst_ptr[0] = gfx_color16_blend_a8( bb->src_fg, gfx_color16_to_color(dst_ptr[0]), fg_alpha); dst_ptr += bb->dst_stride / sizeof(*dst_ptr); src_ptr += bb->src_stride / sizeof(*src_ptr); @@ -262,7 +269,8 @@ static void dma2d_rgb565_blend_mono4_last_col(const gfx_bitblt_t* bb) { while (height-- > 0) { uint8_t fg_alpha = src_ptr[0] & 0x0F; - dst_ptr[0] = gfx_color16_blend_a4( + fg_alpha = (fg_alpha * bb->src_alpha) / 15; + dst_ptr[0] = gfx_color16_blend_a8( bb->src_fg, gfx_color16_to_color(dst_ptr[0]), fg_alpha); dst_ptr += bb->dst_stride / sizeof(*dst_ptr); src_ptr += bb->src_stride / sizeof(*src_ptr); @@ -302,12 +310,16 @@ bool dma2d_rgb565_blend_mono4(const gfx_bitblt_t* params) { bb->dst_stride / sizeof(uint16_t) - bb->width; HAL_DMA2D_Init(&dma2d_handle); - dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4; + dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4; dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width; - dma2d_handle.LayerCfg[1].AlphaMode = 0; - dma2d_handle.LayerCfg[1].InputAlpha = gfx_color_to_color32(bb->src_fg); + dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; + dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha; HAL_DMA2D_ConfigLayer(&dma2d_handle, 1); + dma2d_config_clut( + 1, gfx_color_to_color32(bb->src_fg), + gfx_color32_set_alpha(gfx_color_to_color32(bb->src_fg), 0)); + dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565; dma2d_handle.LayerCfg[0].InputOffset = bb->dst_stride / sizeof(uint16_t) - bb->width; @@ -450,7 +462,8 @@ bool dma2d_rgba8888_copy_mono4(const gfx_bitblt_t* params) { dma2d_handle.LayerCfg[1].InputAlpha = 0; HAL_DMA2D_ConfigLayer(&dma2d_handle, 1); - dma2d_config_clut(1, bb->src_fg, bb->src_bg); + dma2d_config_clut(1, gfx_color_to_color32(bb->src_fg), + gfx_color_to_color32(bb->src_bg)); HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2, (uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t), @@ -493,7 +506,8 @@ static void dma2d_rgba8888_blend_mono4_first_col(const gfx_bitblt_t* bb) { while (height-- > 0) { uint8_t fg_alpha = src_ptr[0] >> 4; - dst_ptr[0] = gfx_color32_blend_a4( + fg_alpha = (fg_alpha * bb->src_alpha) / 15; + dst_ptr[0] = gfx_color32_blend_a8( bb->src_fg, gfx_color32_to_color(dst_ptr[0]), fg_alpha); dst_ptr += bb->dst_stride / sizeof(*dst_ptr); src_ptr += bb->src_stride / sizeof(*src_ptr); @@ -508,7 +522,8 @@ static void dma2d_rgba8888_blend_mono4_last_col(const gfx_bitblt_t* bb) { while (height-- > 0) { uint8_t fg_alpha = src_ptr[0] & 0x0F; - dst_ptr[0] = gfx_color32_blend_a4( + fg_alpha = (fg_alpha * bb->src_alpha) / 15; + dst_ptr[0] = gfx_color32_blend_a8( bb->src_fg, gfx_color32_to_color(dst_ptr[0]), fg_alpha); dst_ptr += bb->dst_stride / sizeof(*dst_ptr); src_ptr += bb->src_stride / sizeof(*src_ptr); @@ -548,12 +563,16 @@ bool dma2d_rgba8888_blend_mono4(const gfx_bitblt_t* params) { bb->dst_stride / sizeof(uint32_t) - bb->width; HAL_DMA2D_Init(&dma2d_handle); - dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4; + dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4; dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width; - dma2d_handle.LayerCfg[1].AlphaMode = 0; - dma2d_handle.LayerCfg[1].InputAlpha = gfx_color_to_color32(bb->src_fg); + dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; + dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha; HAL_DMA2D_ConfigLayer(&dma2d_handle, 1); + dma2d_config_clut( + 1, gfx_color_to_color32(bb->src_fg), + gfx_color32_set_alpha(gfx_color_to_color32(bb->src_fg), 0)); + dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888; dma2d_handle.LayerCfg[0].InputOffset = bb->dst_stride / sizeof(uint32_t) - bb->width;