mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 06:18:07 +00:00
feat(core): add alpha capabilities to 4-bit blending
[no changelog]
This commit is contained in:
parent
28aa0a7ee3
commit
2a123b3c5e
@ -102,7 +102,8 @@ void gfx_mono8_blend_mono4(const gfx_bitblt_t* bb) {
|
|||||||
for (int x = 0; x < bb->width; x++) {
|
for (int x = 0; x < bb->width; x++) {
|
||||||
uint8_t src_data = src_row[(x + bb->src_x) / 2];
|
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;
|
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);
|
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||||
src_row += bb->src_stride / sizeof(*src_row);
|
src_row += bb->src_stride / sizeof(*src_row);
|
||||||
|
@ -126,7 +126,8 @@ void gfx_rgb565_blend_mono4(const gfx_bitblt_t* bb) {
|
|||||||
for (int x = 0; x < bb->width; x++) {
|
for (int x = 0; x < bb->width; x++) {
|
||||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
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;
|
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);
|
bb->src_fg, gfx_color16_to_color(dst_ptr[x]), fg_alpha);
|
||||||
}
|
}
|
||||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||||
|
@ -146,7 +146,8 @@ void gfx_rgba8888_blend_mono4(const gfx_bitblt_t* bb) {
|
|||||||
for (int x = 0; x < bb->width; x++) {
|
for (int x = 0; x < bb->width; x++) {
|
||||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
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;
|
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);
|
bb->src_fg, gfx_color32_to_color(dst_ptr[x]), fg_alpha);
|
||||||
}
|
}
|
||||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||||
|
@ -75,6 +75,8 @@ typedef uint32_t gfx_color32_t;
|
|||||||
#define gfx_color32_to_g(c) (((c) & 0x0000FF00) >> 8)
|
#define gfx_color32_to_g(c) (((c) & 0x0000FF00) >> 8)
|
||||||
// Extracts blue component from gfx_color32_t
|
// Extracts blue component from gfx_color32_t
|
||||||
#define gfx_color32_to_b(c) (((c) & 0x000000FF) >> 0)
|
#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`
|
// 4-bit linear interpolation between `fg` and `bg`
|
||||||
#define a4_lerp(fg, bg, alpha) (((fg) * (alpha) + ((bg) * (15 - (alpha)))) / 15)
|
#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;
|
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
|
// 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) {
|
static inline gfx_color32_t gfx_color16_to_color32(gfx_color16_t color) {
|
||||||
uint32_t r = gfx_color16_to_r(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
|
// 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);
|
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
|
#endif // GFX_COLOR_H
|
||||||
|
@ -281,6 +281,7 @@ impl<'a> BitBltCopy<'a> {
|
|||||||
.with_src(src.bitmap, offset.x, offset.y)
|
.with_src(src.bitmap, offset.x, offset.y)
|
||||||
.with_bg(src.bg_color)
|
.with_bg(src.bg_color)
|
||||||
.with_fg(src.fg_color)
|
.with_fg(src.fg_color)
|
||||||
|
.with_alpha(src.alpha)
|
||||||
},
|
},
|
||||||
src,
|
src,
|
||||||
})
|
})
|
||||||
|
@ -300,6 +300,7 @@ pub struct BitmapView<'a> {
|
|||||||
pub offset: Offset,
|
pub offset: Offset,
|
||||||
pub fg_color: Color,
|
pub fg_color: Color,
|
||||||
pub bg_color: Color,
|
pub bg_color: Color,
|
||||||
|
pub alpha: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BitmapView<'a> {
|
impl<'a> BitmapView<'a> {
|
||||||
@ -310,6 +311,7 @@ impl<'a> BitmapView<'a> {
|
|||||||
offset: Offset::zero(),
|
offset: Offset::zero(),
|
||||||
fg_color: Color::black(),
|
fg_color: Color::black(),
|
||||||
bg_color: Color::black(),
|
bg_color: Color::black(),
|
||||||
|
alpha: 255,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +333,11 @@ impl<'a> BitmapView<'a> {
|
|||||||
Self { bg_color, ..self }
|
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
|
/// Returns the bitmap width and height in pixels
|
||||||
pub fn size(&self) -> Offset {
|
pub fn size(&self) -> Offset {
|
||||||
self.bitmap.size
|
self.bitmap.size
|
||||||
|
@ -97,13 +97,14 @@ bool dma2d_rgb565_fill(const gfx_bitblt_t* bb) {
|
|||||||
return true;
|
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 LAYER_COUNT 2
|
||||||
#define GRADIENT_STEPS 16
|
#define GRADIENT_STEPS 16
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
gfx_color_t c_fg;
|
gfx_color32_t c_fg;
|
||||||
gfx_color_t c_bg;
|
gfx_color32_t c_bg;
|
||||||
} cache[LAYER_COUNT] = {0};
|
} cache[LAYER_COUNT] = {0};
|
||||||
|
|
||||||
if (layer >= LAYER_COUNT) {
|
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;
|
cache[layer].c_bg = bg;
|
||||||
|
|
||||||
for (int step = 0; step < GRADIENT_STEPS; step++) {
|
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;
|
DMA2D_CLUTCfgTypeDef clut_def = {0};
|
||||||
clut.CLUTColorMode = DMA2D_CCM_ARGB8888;
|
clut_def.CLUTColorMode = DMA2D_CCM_ARGB8888;
|
||||||
clut.Size = GRADIENT_STEPS - 1;
|
clut_def.Size = GRADIENT_STEPS - 1;
|
||||||
clut.pCLUT = 0; // ???
|
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;
|
dma2d_handle.LayerCfg[1].InputAlpha = 0;
|
||||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
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,
|
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),
|
(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) {
|
while (height-- > 0) {
|
||||||
uint8_t fg_alpha = src_ptr[0] >> 4;
|
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);
|
bb->src_fg, gfx_color16_to_color(dst_ptr[0]), fg_alpha);
|
||||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||||
src_ptr += bb->src_stride / sizeof(*src_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) {
|
while (height-- > 0) {
|
||||||
uint8_t fg_alpha = src_ptr[0] & 0x0F;
|
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);
|
bb->src_fg, gfx_color16_to_color(dst_ptr[0]), fg_alpha);
|
||||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||||
src_ptr += bb->src_stride / sizeof(*src_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;
|
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||||
HAL_DMA2D_Init(&dma2d_handle);
|
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].InputOffset = bb->src_stride * 2 - bb->width;
|
||||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
|
||||||
dma2d_handle.LayerCfg[1].InputAlpha = gfx_color_to_color32(bb->src_fg);
|
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
|
||||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
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].InputColorMode = DMA2D_INPUT_RGB565;
|
||||||
dma2d_handle.LayerCfg[0].InputOffset =
|
dma2d_handle.LayerCfg[0].InputOffset =
|
||||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
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;
|
dma2d_handle.LayerCfg[1].InputAlpha = 0;
|
||||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
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,
|
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),
|
(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) {
|
while (height-- > 0) {
|
||||||
uint8_t fg_alpha = src_ptr[0] >> 4;
|
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);
|
bb->src_fg, gfx_color32_to_color(dst_ptr[0]), fg_alpha);
|
||||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||||
src_ptr += bb->src_stride / sizeof(*src_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) {
|
while (height-- > 0) {
|
||||||
uint8_t fg_alpha = src_ptr[0] & 0x0F;
|
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);
|
bb->src_fg, gfx_color32_to_color(dst_ptr[0]), fg_alpha);
|
||||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||||
src_ptr += bb->src_stride / sizeof(*src_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;
|
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||||
HAL_DMA2D_Init(&dma2d_handle);
|
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].InputOffset = bb->src_stride * 2 - bb->width;
|
||||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
|
||||||
dma2d_handle.LayerCfg[1].InputAlpha = gfx_color_to_color32(bb->src_fg);
|
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
|
||||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
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].InputColorMode = DMA2D_INPUT_ARGB8888;
|
||||||
dma2d_handle.LayerCfg[0].InputOffset =
|
dma2d_handle.LayerCfg[0].InputOffset =
|
||||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||||
|
Loading…
Reference in New Issue
Block a user