WIP - drawlib - rgba8888 support

cepetr/drawlib-integration
cepetr 2 months ago
parent 320aca2ab2
commit 8054de618b

@ -68,6 +68,7 @@ SOURCE_MOD += [
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_dma2d_rgb565.c',
'embed/lib/gl_dma2d_rgba8888.c',
'embed/lib/gl_dma2d_mono8.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',

@ -93,6 +93,7 @@ SOURCE_MOD += [
'embed/lib/gl_color.c',
'embed/lib/gl_dma2d_mono8.c',
'embed/lib/gl_dma2d_rgb565.c',
'embed/lib/gl_dma2d_rgba8888.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',
'embed/lib/terminal.c',

@ -90,6 +90,7 @@ SOURCE_MOD += [
'embed/lib/gl_color.c',
'embed/lib/gl_dma2d_mono8.c',
'embed/lib/gl_dma2d_rgb565.c',
'embed/lib/gl_dma2d_rgba8888.c',
'embed/lib/image.c',
'embed/lib/terminal.c',
'embed/lib/touch.c',

@ -210,6 +210,7 @@ SOURCE_MOD += [
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_dma2d_rgb565.c',
'embed/lib/gl_dma2d_rgba8888.c',
'embed/lib/gl_dma2d_mono8.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',

@ -210,6 +210,7 @@ SOURCE_MOD += [
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_dma2d_rgb565.c',
'embed/lib/gl_dma2d_rgba8888.c',
'embed/lib/gl_dma2d_mono8.c',
'embed/lib/image.c',
'embed/lib/terminal.c',

@ -114,8 +114,8 @@ static inline uint8_t gl_color16_lum(gl_color16_t color) {
//
// Returns a color in 16-bit format
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
// If `alpha` is 0, the function returns the background color
// If `alpha` is 15, the function returns the foreground color
static inline gl_color16_t gl_color16_blend_a4(gl_color16_t fg, gl_color16_t bg,
uint8_t alpha) {
uint16_t fg_r = (fg & 0xF800) >> 11;
@ -138,8 +138,8 @@ static inline gl_color16_t gl_color16_blend_a4(gl_color16_t fg, gl_color16_t bg,
//
// Returns a color in 16-bit format
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
// If `alpha` is 0, the function returns the background color
// If `alpha` is 15, the function returns the foreground color
static inline gl_color16_t gl_color16_blend_a8(gl_color16_t fg, gl_color16_t bg,
uint8_t alpha) {
uint16_t fg_r = (fg & 0xF800) >> 11;
@ -173,9 +173,9 @@ static inline gl_color32_t gl_color32_blend_a4(gl_color16_t fg, gl_color16_t bg,
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
uint16_t fg_g = (fg & 0x07E0) >> 2;
uint16_t fg_g = (fg & 0x07E0) >> 3;
fg_g |= fg_g >> 6;
uint16_t bg_g = (bg & 0x07E0) >> 2;
uint16_t bg_g = (bg & 0x07E0) >> 3;
bg_g |= bg_g >> 6;
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
@ -188,14 +188,44 @@ static inline gl_color32_t gl_color32_blend_a4(gl_color16_t fg, gl_color16_t bg,
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
// Blends foreground and background colors with 8-bit alpha
//
// Returns a color in 32-bit format
//
// If `alpha` is 0, the function returns the background color
// If `alpha` is 255, the function returns the foreground color
static inline gl_color32_t gl_color32_blend_a8(gl_color16_t fg, gl_color16_t bg,
uint8_t alpha) {
uint16_t fg_r = (fg & 0xF800) >> 8;
fg_r |= fg_r >> 5;
uint16_t bg_r = (bg & 0xF800) >> 8;
bg_r |= bg_r >> 5;
uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255;
uint16_t fg_g = (fg & 0x07E0) >> 3;
fg_g |= fg_g >> 6;
uint16_t bg_g = (bg & 0x07E0) >> 3;
bg_g |= bg_g >> 6;
uint16_t g = (fg_g * alpha + (bg_g * (255 - alpha))) / 255;
uint16_t fg_b = (fg & 0x001F) << 3;
fg_b |= fg_b >> 5;
uint16_t bg_b = (bg & 0x001F) << 3;
bg_b |= bg_b >> 5;
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
#elif GL_COLOR_32BIT
// Blends foreground and background colors with 4-bit alpha
//
// Returns a color in 16-bit format
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
// If `alpha` is 0, the function returns the background color
// If `alpha` is 15, the function returns the foreground color
static inline gl_color16_t gl_color16_blend_a4(gl_color32_t fg, gl_color32_t bg,
uint8_t alpha) {
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
@ -217,8 +247,8 @@ static inline gl_color16_t gl_color16_blend_a4(gl_color32_t fg, gl_color32_t bg,
//
// Returns a color in 16-bit format
//
// If alpha is 0, the function returns the background color
// If alpha is 255, the function returns the foreground color
// If `alpha` is 0, the function returns the background color
// If `alpha` is 255, the function returns the foreground color
static inline gl_color16_t gl_color16_blend_a8(gl_color32_t fg, gl_color32_t bg,
uint8_t alpha) {
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
@ -240,8 +270,8 @@ static inline gl_color16_t gl_color16_blend_a8(gl_color32_t fg, gl_color32_t bg,
//
// Returns a color in 32-bit format
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
// If `alpha` is 0, the function returns the background color
// If `alpha` is 15, the function returns the foreground color
static inline gl_color32_t gl_color32_blend_a4(gl_color32_t fg, gl_color32_t bg,
uint8_t alpha) {
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
@ -265,14 +295,14 @@ static inline gl_color32_t gl_color32_blend_a4(gl_color32_t fg, gl_color32_t bg,
// Returns a gradient as an array of 16 consecutive 16-bit colors
//
// Each element in the array represents a color, with retval[0] being
// the background (bg) color and retval[15] the foreground (fg) color
// Each element in the array represents a color, with `retval[0]` being
// the background (`bg`) color and `retval[15]` the foreground (`fg`) color
const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg, gl_color_t bg);
// Returns a gradient as an array of 16 consecutive 32-bit colors
//
// Each element in the array represents a color, with retval[0] being
// the background (bg) color and retval[15] the foreground (fg) color
// Each element in the array represents a color, with `retval[0]` being
// the background (`bg`) color and `retval[15]` the foreground (`fg`) color
const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg, gl_color_t bg);
#endif // TREZORHAL_GL_COLOR_H

@ -0,0 +1,155 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gl_dma2d.h"
#if USE_DMA2D
#include "dma2d.h"
#endif
bool rgba8888_fill(const dma2d_params_t* dp) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(dp->dst_row)) {
return dma2d_rgba8888_fill(dp);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint16_t height = dp->height;
if (dp->src_alpha == 255) {
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
dst_ptr[x] = gl_color_to_color32(dp->src_fg);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
}
} else {
uint8_t alpha = dp->src_alpha;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
dst_ptr[x] = gl_color32_blend_a8(
dp->src_fg, gl_color32_to_color(dst_ptr[x]), alpha);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
}
}
return true;
}
}
bool rgba8888_copy_mono4(const dma2d_params_t* dp) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(dp->dst_row) && dma2d_accessible(dp->src_row)) {
return dma2d_rgba8888_copy_mono4(dp);
} else
#endif
{
const gl_color32_t* gradient =
gl_color32_gradient_a4(dp->src_fg, dp->src_bg);
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint8_t* src_row = (uint8_t*)dp->src_row;
uint16_t height = dp->height;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
uint8_t fg_data = src_row[(x + dp->src_x) / 2];
uint8_t fg_lum = (x + dp->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
dst_ptr[x] = gradient[fg_lum];
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_row += dp->src_stride / sizeof(*src_row);
}
return true;
}
}
bool rgba8888_copy_rgb565(const dma2d_params_t* dp) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(dp->dst_row) && dma2d_accessible(dp->src_row)) {
return dma2d_rgba8888_copy_rgb565(dp);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint16_t* src_ptr = (uint16_t*)dp->src_row + dp->src_x;
uint16_t height = dp->height;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
dst_ptr[x] = gl_color16_to_color32(src_ptr[x]);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
return true;
}
}
bool rgba8888_copy_rgba8888(const dma2d_params_t* dp) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(dp->dst_row) && dma2d_accessible(dp->src_row)) {
return dma2d_rgba8888_copy_rgba8888(dp);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint32_t* src_ptr = (uint32_t*)dp->src_row + dp->src_x;
uint16_t height = dp->height;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
dst_ptr[x] = src_ptr[x];
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
return true;
}
}
bool rgba8888_blend_mono4(const dma2d_params_t* dp) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(dp->dst_row) && dma2d_accessible(dp->src_row)) {
return dma2d_rgba8888_blend_mono4(dp);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint8_t* src_row = (uint8_t*)dp->src_row;
uint16_t height = dp->height;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
uint8_t fg_data = src_row[(x + dp->src_x) / 2];
uint8_t fg_alpha = (x + dp->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
dst_ptr[x] = gl_color32_blend_a4(
dp->src_fg, gl_color32_to_color(dst_ptr[x]), fg_alpha);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_row += dp->src_stride / sizeof(*src_row);
}
return true;
}
}

@ -252,7 +252,8 @@ void display_text(int x, int y, const char* text, int textlen, int font,
.bg_color = bg_color,
};
gl_draw_text(gl_offset(x, y), text, textlen, &attr);
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
gl_draw_text(gl_offset(x, y), text, maxlen, &attr);
}
void display_text_center(int x, int y, const char* text, int textlen, int font,
@ -263,6 +264,7 @@ void display_text_center(int x, int y, const char* text, int textlen, int font,
.bg_color = bg_color,
};
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
int w = font_text_width(font, text, textlen);
gl_draw_text(gl_offset(x - w / 2, y), text, textlen, &attr);
gl_draw_text(gl_offset(x - w / 2, y), text, maxlen, &attr);
}

@ -22,7 +22,10 @@
#include "gl_color.h"
// 2D rectangle coordinates (x1, y1 point is not included)
// 2D rectangle coordinates
//
// `x0`, `y0` - top-left coordinates
// `x1`, `y1` - bottom-right coordinates point (not included)
typedef struct {
int16_t x0;
int16_t y0;
@ -30,7 +33,7 @@ typedef struct {
int16_t y1;
} gl_rect_t;
// Creates a rectangle from top-left coordinates and dimensions
// Builds a rectangle (`gl_rect_t`) from top-left coordinates and dimensions
static inline gl_rect_t gl_rect_wh(int16_t x, int16_t y, int16_t w, int16_t h) {
gl_rect_t rect = {
.x0 = x,
@ -42,7 +45,7 @@ static inline gl_rect_t gl_rect_wh(int16_t x, int16_t y, int16_t w, int16_t h) {
return rect;
}
// Creates a rectangle from top-left and bottom-right coordinates
// Builds a rectangle (`gl_rect_t`) from top-left and bottom-right coordinates
static inline gl_rect_t gl_rect(int16_t x0, int16_t y0, int16_t x1,
int16_t y1) {
gl_rect_t rect = {
@ -61,6 +64,7 @@ typedef struct {
int16_t y;
} gl_offset_t;
// Builds a `gl_offset_t` structure
static inline gl_offset_t gl_offset(int16_t x, int16_t y) {
gl_offset_t offset = {
.x = x,
@ -76,6 +80,7 @@ typedef struct {
int16_t y;
} gl_size_t;
// Builds a `gl_size_t` structure
static inline gl_size_t gl_size(int16_t x, int16_t y) {
gl_size_t size = {
.x = x,
@ -85,7 +90,7 @@ static inline gl_size_t gl_size(int16_t x, int16_t y) {
return size;
}
// Bitmap pixel format
// Format of pixels in a bitmap
typedef enum {
GL_FORMAT_UNKNOWN, //
GL_FORMAT_MONO1P, // 1-bpp per pixel (packed)
@ -94,7 +99,7 @@ typedef enum {
GL_FORMAT_RGBA8888, // 32-bpp
} gl_format_t;
// 2D bitmap references
// 2D bitmap reference
typedef struct {
// pointer to top-left pixel
void* ptr;
@ -112,23 +117,32 @@ typedef struct {
gl_color_t bg_color;
} gl_bitmap_t;
// Text attributes
// Text attributes (font and color)
typedef struct {
// Font identifier
int font;
// Foreground color
gl_color_t fg_color;
// Background color
gl_color_t bg_color;
} gl_text_attr_t;
// Fills a rectangle with a specified color
// Fills a rectangle with a specified color.
void gl_draw_bar(gl_rect_t rect, gl_color_t color);
// Draws a bitmap into the specified rectangle
// Draws a bitmap into the specified rectangle.
//
// The destination rectangle may not be fully filled if the source bitmap
// is smaller then destination rectangle or if the bitmap is translated by
// an offset partially or completely outside the destination rectangle.
void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap);
// !@# TODO
// Draws a text to the specified position.
//
// `offset` - the most left point on the font baseline
// `text` - utf-8 text
// `maxlen` - maximum number of characters displayed (use SIZE_MAX when not
// specified) `attr` - font & text color
void gl_draw_text(gl_offset_t offset, const char* text, size_t maxlen,
const gl_text_attr_t* attr);

@ -348,7 +348,8 @@ fn generate_trezorhal_bindings() {
.allowlist_var("DISPLAY_FRAMEBUFFER_OFFSET_Y")
.allowlist_var("DISPLAY_RESX")
.allowlist_var("DISPLAY_RESY")
.allowlist_function("display_get_frame_addr")
.allowlist_type("display_fb_info_t")
.allowlist_function("display_get_frame_buffer")
.allowlist_function("display_fill")
.allowlist_function("display_copy_rgb565")
// dma2d

@ -182,6 +182,15 @@ pub fn clear() {
}
#[cfg(feature = "xframebuffer")]
pub fn get_frame_addr() -> *mut cty::c_void {
unsafe { ffi::display_get_frame_addr() }
pub fn get_frame_buffer() -> (&'static mut [u8], usize) {
let fb_info = unsafe { ffi::display_get_frame_buffer() };
let fb = unsafe {
core::slice::from_raw_parts_mut(
fb_info.ptr as *mut u8,
DISPLAY_RESY as usize * fb_info.stride as usize,
)
};
(fb, fb_info.stride)
}

@ -209,6 +209,7 @@ impl<'a> JpegCacheSlot<'a> {
Rgb565Canvas::new(
Offset::new(decoder.width() / divisor, decoder.mcu_height() / divisor),
None,
None,
canvas_buff
),
"Buffer too small"

@ -24,8 +24,13 @@ impl<'a> Mono8Canvas<'a> {
/// of the new bitmap is adjusted to the buffer size.
///
/// Returns None if the buffer is not big enough.
pub fn new(size: Offset, min_height: Option<i16>, buff: &'a mut [u8]) -> Option<Self> {
let bitmap = Bitmap::new_mut(BitmapFormat::MONO8, None, size, min_height, buff)?;
pub fn new(
size: Offset,
stride: Option<usize>,
min_height: Option<i16>,
buff: &'a mut [u8],
) -> Option<Self> {
let bitmap = Bitmap::new_mut(BitmapFormat::MONO8, stride, size, min_height, buff)?;
let viewport = Viewport::from_size(bitmap.size());
Some(Self { bitmap, viewport })
}

@ -24,8 +24,13 @@ impl<'a> Rgb565Canvas<'a> {
/// of the new bitmap is adjusted to the buffer size.
///
/// Returns None if the buffer is not big enough.
pub fn new(size: Offset, min_height: Option<i16>, buff: &'a mut [u8]) -> Option<Self> {
let bitmap = Bitmap::new_mut(BitmapFormat::RGB565, None, size, min_height, buff)?;
pub fn new(
size: Offset,
stride: Option<usize>,
min_height: Option<i16>,
buff: &'a mut [u8],
) -> Option<Self> {
let bitmap = Bitmap::new_mut(BitmapFormat::RGB565, stride, size, min_height, buff)?;
let viewport = Viewport::from_size(bitmap.size());
Some(Self { bitmap, viewport })
}

@ -24,8 +24,13 @@ impl<'a> Rgba8888Canvas<'a> {
/// of the new bitmap is adjusted to the buffer size.
///
/// Returns None if the buffer is not big enough.
pub fn new(size: Offset, min_height: Option<i16>, buff: &'a mut [u8]) -> Option<Self> {
let bitmap = Bitmap::new_mut(BitmapFormat::RGBA8888, None, size, min_height, buff)?;
pub fn new(
size: Offset,
stride: Option<usize>,
min_height: Option<i16>,
buff: &'a mut [u8],
) -> Option<Self> {
let bitmap = Bitmap::new_mut(BitmapFormat::RGBA8888, stride, size, min_height, buff)?;
let viewport = Viewport::from_size(bitmap.size());
Some(Self { bitmap, viewport })
}
@ -72,13 +77,35 @@ impl<'a> Canvas for Rgba8888Canvas<'a> {
let pt = pt + self.viewport.origin;
if self.viewport.clip.contains(pt) {
if let Some(row) = self.row_mut(pt.y) {
row[pt.x as usize] = color.into();
row[pt.x as usize] = color.to_u32();
}
}
}
fn blend_pixel(&mut self, _pt: Point, _color: Color, _alpha: u8) {
// TODO: not implemented yet, requires 32-bit color blending routines
fn blend_pixel(&mut self, pt: Point, color: Color, alpha: u8) {
let pt = pt + self.viewport.origin;
if self.viewport.clip.contains(pt) {
if let Some(row) = self.row_mut(pt.y) {
let bg = row[pt.x as usize];
let bg_r = ((bg & 0x00FF0000) >> 16) as u16;
let bg_g = ((bg & 0x0000FF00) >> 8) as u16;
let bg_b = ((bg & 0x000000FF) >> 0) as u16;
let fg_r = color.r() as u16;
let fg_g = color.g() as u16;
let fg_b = color.b() as u16;
let fg_mul = alpha as u16;
let bg_mul = (255 - alpha) as u16;
let r = ((fg_r * fg_mul + bg_r * bg_mul) / 255) as u32;
let g = ((fg_g * fg_mul + bg_g * bg_mul) / 255) as u32;
let b = ((fg_b * fg_mul + bg_b * bg_mul) / 255) as u32;
row[pt.x as usize] = (0xFF << 24) | (r << 16) | (g << 8) | b;
}
}
}
fn blend_bitmap(&mut self, r: Rect, src: BitmapView) {

@ -25,14 +25,14 @@ where
let cache = DrawingCache::new(bump, bump);
let fb = unsafe {
core::slice::from_raw_parts_mut(
display::get_frame_addr() as *mut u8,
width as usize * height as usize,
)
};
let mut canvas = unwrap!(Mono8Canvas::new(Offset::new(width, height), None, fb));
let (fb, fb_stride) = display::get_frame_buffer();
let mut canvas = unwrap!(Mono8Canvas::new(
Offset::new(width, height),
Some(fb_stride),
None,
fb
));
if let Some(clip) = clip {
canvas.set_viewport(Viewport::new(clip));

@ -32,14 +32,14 @@ where
let cache = DrawingCache::new(bump_a, bump_b);
let fb = unsafe {
core::slice::from_raw_parts_mut(
display::get_frame_addr() as *mut u8,
width as usize * height as usize * core::mem::size_of::<u16>(),
)
};
let mut canvas = unwrap!(Rgb565Canvas::new(Offset::new(width, height), None, fb));
let (fb, fb_stride) = display::get_frame_buffer();
let mut canvas = unwrap!(Rgb565Canvas::new(
Offset::new(width, height),
Some(fb_stride),
None,
fb
));
if let Some(clip) = clip {
canvas.set_viewport(Viewport::new(clip));

@ -32,14 +32,14 @@ where
let cache = DrawingCache::new(bump_a, bump_b);
let fb = unsafe {
core::slice::from_raw_parts_mut(
display::get_frame_addr() as *mut u8,
width as usize * height as usize * core::mem::size_of::<u32>(),
)
};
let mut canvas = unwrap!(Rgba8888Canvas::new(Offset::new(width, height), None, fb));
let (fb, fb_stride) = display::get_frame_buffer();
let mut canvas = unwrap!(Rgba8888Canvas::new(
Offset::new(width, height),
Some(fb_stride),
None,
fb
));
if let Some(clip) = clip {
canvas.set_viewport(Viewport::new(clip));

@ -177,6 +177,7 @@ where
let mut slice = unwrap!(
Rgb565Canvas::new(
Offset::new(canvas_clip.width(), lines as i16),
None,
Some(1),
&mut buff[..],
),

@ -11,8 +11,9 @@
//#define USE_DISP_I8080_8BIT_DW 1
#define USE_HASH_PROCESSOR 1
#define DISPLAY_RESX 480
#define DISPLAY_RESY 480
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888
#define DISPLAY_LEGACY_HEADER "displays/dsi.h"

@ -50,6 +50,12 @@ bool dma2d_rgb565_copy_mono4(const dma2d_params_t* dp);
bool dma2d_rgb565_copy_rgb565(const dma2d_params_t* dp);
bool dma2d_rgb565_blend_mono4(const dma2d_params_t* dp);
bool dma2d_rgba8888_fill(const dma2d_params_t* dp);
bool dma2d_rgba8888_copy_mono4(const dma2d_params_t* dp);
bool dma2d_rgba8888_copy_rgb565(const dma2d_params_t* dp);
bool dma2d_rgba8888_copy_rgba8888(const dma2d_params_t* dp);
bool dma2d_rgba8888_blend_mono4(const dma2d_params_t* dp);
bool dma2d_accessible(const void* ptr);
#endif // TREZORHAL_DMA2D_H

@ -136,12 +136,21 @@ static void switch_fb_in_backround(void) {
}
#endif
void *display_get_frame_addr(void) {
display_fb_info_t display_get_frame_buffer(void) {
void *addr;
if (current_frame_buffer == 0) {
return (void *)physical_frame_buffer_1;
addr = (void *)physical_frame_buffer_1;
} else {
return (void *)physical_frame_buffer_0;
addr = (void *)physical_frame_buffer_0;
}
display_fb_info_t fb = {
.ptr = addr,
.stride = DISPLAY_RESX * sizeof(uint16_t),
};
return fb;
}
void display_refresh(void) {

@ -96,10 +96,15 @@ int display_get_orientation(void) {
return drv->orientation_angle;
}
void *display_get_frame_addr(void) {
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
return (void *)drv->framebuf;
display_fb_info_t fb = {
.ptr = (void *)drv->framebuf,
.stride = DISPLAY_RESX * sizeof(uint16_t),
};
return fb;
}
void display_refresh(void) {
@ -113,7 +118,7 @@ void display_fill(const dma2d_params_t *dp) {
dma2d_params_t dp_new = *dp;
dp_new.dst_row = drv->framebuf + (DISPLAY_RESX * dp_new.dst_y);
dp_new.dst_stride = DISPLAY_RESX * 2;
dp_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
rgb565_fill(&dp_new);
}
@ -123,7 +128,7 @@ void display_copy_rgb565(const dma2d_params_t *dp) {
dma2d_params_t dp_new = *dp;
dp_new.dst_row = drv->framebuf + (DISPLAY_RESX * dp_new.dst_y);
dp_new.dst_stride = DISPLAY_RESX * 2;
dp_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
rgb565_copy_rgb565(&dp_new);
}
@ -133,7 +138,7 @@ void display_copy_mono4(const dma2d_params_t *dp) {
dma2d_params_t dp_new = *dp;
dp_new.dst_row = drv->framebuf + (DISPLAY_RESX * dp_new.dst_y);
dp_new.dst_stride = DISPLAY_RESX * 2;
dp_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
rgb565_copy_mono4(&dp_new);
}

@ -362,10 +362,15 @@ int display_get_orientation(void) {
return drv->orientation_angle;
}
void *display_get_frame_addr(void) {
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
return &drv->framebuf[0];
display_fb_info_t fb = {
.ptr = &drv->framebuf[0],
.stride = DISPLAY_RESX,
};
return fb;
}
void display_refresh(void) { display_sync_with_fb(); }

@ -311,10 +311,15 @@ int display_get_orientation(void) {
return drv->orientation_angle;
}
void *display_get_frame_addr(void) {
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
return &drv->framebuf[0];
display_fb_info_t fb = {
.ptr = &drv->framebuf[0],
.stride = DISPLAY_RESX,
};
return fb;
}
void display_refresh(void) {

@ -29,10 +29,13 @@ static DMA2D_HandleTypeDef dma2d_handle = {
};
bool dma2d_accessible(const void* ptr) {
// TODO:: valid only for STM32F42x
#ifdef STM32F4
const void* ccm_start = (const void*)0x10000000;
const void* ccm_end = (const void*)0x1000FFFF;
return !(ptr >= ccm_start && ptr <= ccm_end);
#else
return true;
#endif
}
void dma2d_wait(void) {
@ -67,16 +70,44 @@ bool dma2d_rgb565_fill(const dma2d_params_t* dp) {
((dma2d_handle).Instance->CR |= DMA2D_CR_START);
*/
} else {
#ifdef STM32U5
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND_FG;
dma2d_handle.Init.OutputOffset =
dp->dst_stride / sizeof(uint16_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[1].InputOffset = 0;
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
dma2d_handle.LayerCfg[1].InputAlpha = dp->src_alpha;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[0].InputOffset =
dp->dst_stride / sizeof(uint16_t) - dp->width;
dma2d_handle.LayerCfg[0].AlphaMode = 0;
dma2d_handle.LayerCfg[0].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
HAL_DMA2D_BlendingStart(
&dma2d_handle, gl_color_to_color32(dp->src_fg),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint16_t),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint16_t), dp->width,
dp->height);
#else
// STM32F4 can not accelerate blending with the fixed color
uint16_t* dst_ptr = (uint16_t*)dp->dst_row + dp->dst_x;
uint16_t height = dp->height;
uint8_t alpha = dp->src_alpha;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
dst_ptr[x] = gl_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha);
dst_ptr[x] = gl_color16_blend_a8(
dp->src_fg, gl_color16_to_color(dst_ptr[x]), alpha);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
}
#endif
}
return true;
@ -335,3 +366,269 @@ bool dma2d_rgb565_blend_mono4(const dma2d_params_t* params) {
return true;
}
bool dma2d_rgba8888_fill(const dma2d_params_t* dp) {
dma2d_wait();
if (dp->src_alpha == 255) {
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_R2M;
dma2d_handle.Init.OutputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
HAL_DMA2D_Start(&dma2d_handle, gl_color_to_color32(dp->src_fg),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t),
dp->width, dp->height);
} else {
#ifdef STM32U5
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND_FG;
dma2d_handle.Init.OutputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[1].InputOffset = 0;
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
dma2d_handle.LayerCfg[1].InputAlpha = dp->src_alpha;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[0].InputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
dma2d_handle.LayerCfg[0].AlphaMode = 0;
dma2d_handle.LayerCfg[0].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
HAL_DMA2D_BlendingStart(
&dma2d_handle, gl_color_to_color32(dp->src_fg),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t), dp->width,
dp->height);
#else
// STM32F4 can not accelerate blending with the fixed color
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint16_t height = dp->height;
uint8_t alpha = dp->src_alpha;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
dst_ptr[x] = gl_color32_blend_a8(
dp->src_fg, gl_color32_to_color(dst_ptr[x]), alpha);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
}
#endif
}
return true;
}
static void dma2d_rgba8888_copy_mono4_first_col(dma2d_params_t* dp,
const gl_color32_t* gradient) {
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint8_t* src_ptr = (uint8_t*)dp->src_row + dp->src_x / 2;
int height = dp->height;
while (height-- > 0) {
uint8_t fg_lum = src_ptr[0] >> 4;
dst_ptr[0] = gradient[fg_lum];
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
}
static void dma2d_rgba8888_copy_mono4_last_col(dma2d_params_t* dp,
const gl_color32_t* gradient) {
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + (dp->dst_x + dp->width - 1);
uint8_t* src_ptr = (uint8_t*)dp->src_row + (dp->src_x + dp->width - 1) / 2;
int height = dp->height;
while (height-- > 0) {
uint8_t fg_lum = src_ptr[0] & 0x0F;
dst_ptr[0] = gradient[fg_lum];
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
}
bool dma2d_rgba8888_copy_mono4(const dma2d_params_t* params) {
const gl_color32_t* src_gradient = NULL;
dma2d_params_t dp_copy = *params;
dma2d_params_t* dp = &dp_copy;
dma2d_wait();
if (dp->src_x & 1) {
// First column of mono4 bitmap is odd
// Use the CPU to draw the first column
src_gradient = gl_color32_gradient_a4(dp->src_fg, dp->src_bg);
dma2d_rgba8888_copy_mono4_first_col(dp, src_gradient);
dp->dst_x += 1;
dp->src_x += 1;
dp->width -= 1;
}
if (dp->width > 0 && dp->width & 1) {
// The width is odd
// Use the CPU to draw the last column
if (src_gradient == NULL) {
src_gradient = gl_color32_gradient_a4(dp->src_fg, dp->src_bg);
}
dma2d_rgba8888_copy_mono4_last_col(dp, src_gradient);
dp->width -= 1;
}
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4;
dma2d_handle.LayerCfg[1].InputOffset = dp->src_stride * 2 - dp->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_config_clut(1, dp->src_fg, dp->src_bg);
HAL_DMA2D_Start(&dma2d_handle, (uint32_t)dp->src_row + dp->src_x / 2,
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t),
dp->width, dp->height);
return true;
}
bool dma2d_rgba8888_copy_rgb565(const dma2d_params_t* dp) {
dma2d_wait();
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[1].InputOffset =
dp->src_stride / sizeof(uint16_t) - dp->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
HAL_DMA2D_Start(&dma2d_handle,
(uint32_t)dp->src_row + dp->src_x * sizeof(uint16_t),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t),
dp->width, dp->height);
return true;
}
static void dma2d_rgba8888_blend_mono4_first_col(const dma2d_params_t* dp) {
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + dp->dst_x;
uint8_t* src_ptr = (uint8_t*)dp->src_row + dp->src_x / 2;
int height = dp->height;
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] >> 4;
dst_ptr[0] = gl_color32_blend_a4(dp->src_fg,
gl_color32_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
}
static void dma2d_rgba8888_blend_mono4_last_col(const dma2d_params_t* dp) {
uint32_t* dst_ptr = (uint32_t*)dp->dst_row + (dp->dst_x + dp->width - 1);
uint8_t* src_ptr = (uint8_t*)dp->src_row + (dp->src_x + dp->width - 1) / 2;
int height = dp->height;
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] & 0x0F;
dst_ptr[0] = gl_color32_blend_a4(dp->src_fg,
gl_color32_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
}
bool dma2d_rgba8888_blend_mono4(const dma2d_params_t* params) {
dma2d_wait();
dma2d_params_t dp_copy = *params;
dma2d_params_t* dp = &dp_copy;
if (dp->src_x & 1) {
// First column of mono4 bitmap is odd
// Use the CPU to draw the first column
dma2d_rgba8888_blend_mono4_first_col(dp);
dp->dst_x += 1;
dp->src_x += 1;
dp->width -= 1;
}
if (dp->width > 0 && dp->width & 1) {
// The width is odd
// Use the CPU to draw the last column
dma2d_rgba8888_blend_mono4_last_col(dp);
dp->width -= 1;
}
if (dp->width > 0) {
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND;
dma2d_handle.Init.OutputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
dma2d_handle.LayerCfg[1].InputOffset = dp->src_stride * 2 - dp->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = gl_color_to_color32(dp->src_fg);
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[0].InputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
dma2d_handle.LayerCfg[0].AlphaMode = 0;
dma2d_handle.LayerCfg[0].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
HAL_DMA2D_BlendingStart(
&dma2d_handle, (uint32_t)dp->src_row + dp->src_x / 2,
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t), dp->width,
dp->height);
}
return true;
}
bool dma2d_rgba8888_copy_rgba8888(const dma2d_params_t* dp) {
dma2d_wait();
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
dp->dst_stride / sizeof(uint32_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[1].InputOffset =
dp->src_stride / sizeof(uint32_t) - dp->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
HAL_DMA2D_Start(&dma2d_handle,
(uint32_t)dp->src_row + dp->src_x * sizeof(uint32_t),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint32_t),
dp->width, dp->height);
return true;
}

@ -26,7 +26,7 @@
#include "display_internal.h"
#include "xdisplay.h"
#if (DISPLAY_RESX != 480) || (DISPLAY_RESY != 480)
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240)
#error "Incompatible display resolution"
#endif
@ -71,9 +71,9 @@ void display_init(void) {
void display_reinit(void) {
BSP_LCD_Reinit(0);
if (current_frame_buffer == 0) {
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
} else {
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
} else {
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
}
}
@ -82,7 +82,7 @@ void display_finish_actions(void) {
}
int display_set_backlight(int level) {
display_driver_t* drv = &g_display_driver;
display_driver_t *drv = &g_display_driver;
// Just emulation, not doing anything
drv->backlight_level = level;
@ -90,13 +90,13 @@ int display_set_backlight(int level) {
}
int display_get_backlight(void) {
display_driver_t* drv = &g_display_driver;
display_driver_t *drv = &g_display_driver;
return drv->orientation_angle;
}
int display_set_orientation(int angle) {
display_driver_t* drv = &g_display_driver;
display_driver_t *drv = &g_display_driver;
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
// Just emulation, not doing anything
@ -107,22 +107,39 @@ int display_set_orientation(int angle) {
}
int display_get_orientation(void) {
display_driver_t* drv = &g_display_driver;
display_driver_t *drv = &g_display_driver;
return drv->orientation_angle;
}
void display_set_compatible_settings() {}
/*void display_fill(dma2d_params_t *dp) {
void display_fill(const dma2d_params_t *dp) {
display_fb_info_t fb = display_get_frame_buffer();
dma2d_params_t dp_new = *dp;
dp_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * dp_new.dst_y);
dp_new.dst_stride = fb.stride;
rgba8888_fill(&dp_new);
}
void display_copy_rgb565(dma2d_params_t *dp) {
void display_copy_rgb565(const dma2d_params_t *dp) {
display_fb_info_t fb = display_get_frame_buffer();
dma2d_params_t dp_new = *dp;
dp_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * dp_new.dst_y);
dp_new.dst_stride = fb.stride;
rgba8888_copy_rgb565(&dp_new);
}
void display_copy_mono4(dma2d_params_t *dp) {
void display_copy_mono4(const dma2d_params_t *dp) {
display_fb_info_t fb = display_get_frame_buffer();
dma2d_params_t dp_new = *dp;
dp_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * dp_new.dst_y);
dp_new.dst_stride = fb.stride;
rgba8888_copy_mono4(&dp_new);
}
*/

@ -23,6 +23,7 @@
#include TREZOR_BOARD
#include STM32_HAL_H
#include <xdisplay.h>
#include "display_internal.h"
// Physical frame buffers in internal SRAM memory
@ -37,24 +38,40 @@ ALIGN_32BYTES(uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
0;
void* display_get_frame_addr(void) {
display_fb_info_t display_get_frame_buffer(void) {
uintptr_t addr;
if (current_frame_buffer == 0) {
return (void*)GFXMMU_VIRTUAL_BUFFER0_BASE_S;
addr = GFXMMU_VIRTUAL_BUFFER1_BASE_S;
} else {
return (void*)GFXMMU_VIRTUAL_BUFFER1_BASE_S;
addr = GFXMMU_VIRTUAL_BUFFER0_BASE_S;
}
uint32_t fb_stride = FRAME_BUFFER_PIXELS_PER_LINE * sizeof(uint32_t);
// We do not utilize whole area of the display
// (discovery kit display is 480x480 and we need just 240x240)
addr += (480 - DISPLAY_RESY) / 2 * sizeof(uint32_t);
addr += (480 - DISPLAY_RESX) / 2 * fb_stride;
display_fb_info_t fb = {
.ptr = (void *)addr,
.stride = fb_stride,
};
return fb;
}
void display_refresh(void) {
current_frame_buffer = current_frame_buffer ? 0 : 1;
if (current_frame_buffer == 0) {
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
PHYSICAL_FRAME_BUFFER_SIZE);
} else {
current_frame_buffer = 1;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
PHYSICAL_FRAME_BUFFER_SIZE);
sizeof(physical_frame_buffer_0));
} else {
current_frame_buffer = 0;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
sizeof(physical_frame_buffer_1));
}
}

@ -24,10 +24,13 @@
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual framebuffer
// It's smaller than size of the virtual frame buffer
// due to used GFXMMU settings
#define PHYSICAL_FRAME_BUFFER_SIZE 184320
// Pitch (in pixels) of the virtual frame buffer
#define FRAME_BUFFER_PIXELS_PER_LINE 768
// Physical frame buffers in internal SRAM memory
//
// Both frame buffers layes in the fixed addresses that

@ -130,7 +130,6 @@
#define HACT 480
#define LCD_WIDTH 480
#define LCD_HEIGHT 480
#define PIXEL_PER_LINE 768U
#include "display_gfxmmu_lut.h"
@ -518,11 +517,11 @@ __weak HAL_StatusTypeDef MX_LTDC_Init(LTDC_HandleTypeDef *hltdc) {
// LayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default
// value */ LayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; /* Not
// Used: default value */ LayerCfg.FBStartAdress =
// GFXMMU_VIRTUAL_BUFFER0_BASE; LayerCfg.ImageWidth = PIXEL_PER_LINE; /*
// Number of pixels per line in virtual frame buffer */ LayerCfg.ImageHeight =
// LCD_HEIGHT; LayerCfg.Backcolor.Red = 0; /* Not Used: default value */
// LayerCfg.Backcolor.Green = 0; /* Not Used: default value */
// LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */
// GFXMMU_VIRTUAL_BUFFER0_BASE; LayerCfg.ImageWidth =
// FRAME_BUFFER_PIXELS_PER_LINE; /* Number of pixels per line in virtual frame
// buffer */ LayerCfg.ImageHeight = LCD_HEIGHT; LayerCfg.Backcolor.Red = 0;
// /* Not Used: default value */ LayerCfg.Backcolor.Green = 0; /* Not Used:
// default value */ LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */
// LayerCfg.Bac
// return HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LayerIndex);kcolor.Reserved =
// 0xFF;
@ -553,7 +552,8 @@ __weak HAL_StatusTypeDef MX_LTDC_ConfigLayer(LTDC_HandleTypeDef *hltdc,
LTDC_BLENDING_FACTOR2_PAxCA; /* Not Used: default value */
LayerCfg.FBStartAdress = fb_addr;
LayerCfg.ImageWidth =
PIXEL_PER_LINE; /* Number of pixels per line in virtual frame buffer */
FRAME_BUFFER_PIXELS_PER_LINE; /* Number of pixels per line in virtual
frame buffer */
LayerCfg.ImageHeight = LCD_HEIGHT;
LayerCfg.Backcolor.Red = 0; /* Not Used: default value */
LayerCfg.Backcolor.Green = 0; /* Not Used: default value */

@ -265,15 +265,22 @@ int display_get_orientation(void) {
}
#ifdef XFRAMEBUFFER
void *display_get_frame_addr(void) {
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
#ifdef DISPLAY_MONO
return drv->mono_framebuf;
display_fb_info_t fb = {
.ptr = drv->mono_framebuf,
.stride = DISPLAY_RESX,
};
#else
// !@# pitch???
return drv->buffer->pixels;
display_fb_info_t fb = {
.ptr = drv->buffer->pixels,
.stride = DISPLAY_RESX * sizeof(uint16_t),
};
#endif
return fb;
}
#else // XFRAMEBUFFER

@ -20,6 +20,7 @@
#ifndef TREZORHAL_XDISPLAY_H
#define TREZORHAL_XDISPLAY_H
#include <stddef.h>
#include <stdint.h>
#include "gl_dma2d.h"
@ -87,11 +88,20 @@ int display_set_orientation(int angle);
int display_get_orientation(void);
#ifdef XFRAMEBUFFER
typedef struct {
// Pointer to the top-left pixel
void *ptr;
// Stride in bytes
size_t stride;
} display_fb_info_t;
// Provides pointer to the inactive (writeable) framebuffer.
//
// If framebuffer is not available yet due to display refreshing etc.,
// the function may block until the buffer is ready to write.
void *display_get_frame_addr(void);
display_fb_info_t display_get_frame_buffer(void);
#else // XFRAMEBUFFER

@ -33,7 +33,8 @@ void display_pixeldata(uint16_t c) {}
uint32_t *display_get_fb_addr(void) {
#ifdef XFRAMEBUFFER
return (uint32_t *)display_get_frame_addr();
display_fb_info_t fb = display_get_frame_buffer();
return (uint32_t *)fb.ptr;
#else
return (uint32_t *)0;
#endif

@ -101,6 +101,7 @@ def configure(
features_available.append("framebuffer32bit")
if "new_rendering" in features_wanted:
defines += ["XFRAMEBUFFER"]
features_available.append("xframebuffer")
features_available.append("display_rgba8888")

Loading…
Cancel
Save