mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-02 10:51:06 +00:00
refactor(core): rewrite display_image into rust
[no changelog]
This commit is contained in:
parent
e578f7f0f8
commit
0a8981d643
@ -82,8 +82,7 @@ void ui_screen_boot(const vendor_header *const vhdr,
|
||||
// check whether vendor image is 120x120
|
||||
if (memcmp(vimg, "TOIF\x78\x00\x78\x00", 4) == 0) {
|
||||
uint32_t datalen = *(uint32_t *)(vimg + 8);
|
||||
display_image((DISPLAY_RESX - 120) / 2, image_top, 120, 120, vimg + 12,
|
||||
datalen);
|
||||
display_image((DISPLAY_RESX - 120) / 2, image_top, vimg + 12, datalen);
|
||||
}
|
||||
|
||||
if (show_string) {
|
||||
|
@ -19,11 +19,9 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "uzlib.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "buffers.h"
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
|
||||
#ifdef USE_DMA2D
|
||||
#include "dma2d.h"
|
||||
@ -182,23 +180,6 @@ void display_bar_radius_buffer(int x, int y, int w, int h, uint8_t r,
|
||||
}
|
||||
}
|
||||
|
||||
#define UZLIB_WINDOW_SIZE (1 << 10)
|
||||
|
||||
static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window,
|
||||
const void *src, uint32_t srcsize, void *dest,
|
||||
uint32_t destsize) {
|
||||
memzero(decomp, sizeof(struct uzlib_uncomp));
|
||||
if (window) {
|
||||
memzero(window, UZLIB_WINDOW_SIZE);
|
||||
}
|
||||
memzero(dest, destsize);
|
||||
decomp->source = (const uint8_t *)src;
|
||||
decomp->source_limit = decomp->source + srcsize;
|
||||
decomp->dest = (uint8_t *)dest;
|
||||
decomp->dest_limit = decomp->dest + destsize;
|
||||
uzlib_uncompress_init(decomp, window, window ? UZLIB_WINDOW_SIZE : 0);
|
||||
}
|
||||
|
||||
void display_text_render_buffer(const char *text, int textlen, int font,
|
||||
buffer_text_t *buffer, int text_offset) {
|
||||
// determine text length if not provided
|
||||
@ -262,84 +243,6 @@ void display_text_render_buffer(const char *text, int textlen, int font,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_DMA2D
|
||||
void display_image(int x, int y, int w, int h, const void *data,
|
||||
uint32_t datalen) {
|
||||
#if defined TREZOR_MODEL_T
|
||||
x += DISPLAY_OFFSET.x;
|
||||
y += DISPLAY_OFFSET.y;
|
||||
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
|
||||
clamp_coords(x, y, w, h, &x0, &y0, &x1, &y1);
|
||||
display_set_window(x0, y0, x1, y1);
|
||||
x0 -= x;
|
||||
x1 -= x;
|
||||
y0 -= y;
|
||||
y1 -= y;
|
||||
|
||||
struct uzlib_uncomp decomp = {0};
|
||||
uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {0};
|
||||
uint8_t decomp_out[2] = {0};
|
||||
uzlib_prepare(&decomp, decomp_window, data, datalen, decomp_out,
|
||||
sizeof(decomp_out));
|
||||
|
||||
PIXELDATA_DIRTY();
|
||||
for (uint32_t pos = 0; pos < w * h; pos++) {
|
||||
int st = uzlib_uncompress(&decomp);
|
||||
if (st == TINF_DONE) break; // all OK
|
||||
if (st < 0) break; // error
|
||||
const int px = pos % w;
|
||||
const int py = pos / w;
|
||||
if (px >= x0 && px <= x1 && py >= y0 && py <= y1) {
|
||||
PIXELDATA((decomp_out[1] << 8) | decomp_out[0]);
|
||||
}
|
||||
decomp.dest = (uint8_t *)&decomp_out;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void display_image(int x, int y, int w, int h, const void *data,
|
||||
uint32_t datalen) {
|
||||
x += DISPLAY_OFFSET.x;
|
||||
y += DISPLAY_OFFSET.y;
|
||||
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
|
||||
clamp_coords(x, y, w, h, &x0, &y0, &x1, &y1);
|
||||
display_set_window(x0, y0, x1, y1);
|
||||
x0 -= x;
|
||||
x1 -= x;
|
||||
y0 -= y;
|
||||
y1 -= y;
|
||||
|
||||
struct uzlib_uncomp decomp = {0};
|
||||
uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {0};
|
||||
|
||||
buffer_line_16bpp_t *b1 = buffers_get_line_16bpp(false);
|
||||
if (b1 == NULL) return;
|
||||
buffer_line_16bpp_t *b2 = buffers_get_line_16bpp(false);
|
||||
if (b2 == NULL) {
|
||||
buffers_free_line_16bpp(b1);
|
||||
return;
|
||||
};
|
||||
|
||||
uzlib_prepare(&decomp, decomp_window, data, datalen, b1, w * 2);
|
||||
|
||||
dma2d_setup_16bpp();
|
||||
|
||||
for (int32_t pos = 0; pos < h; pos++) {
|
||||
int32_t pixels = w;
|
||||
buffer_line_16bpp_t *next_buf = (pos % 2 == 1) ? b1 : b2;
|
||||
decomp.dest = next_buf->buffer;
|
||||
decomp.dest_limit = next_buf->buffer + w * 2;
|
||||
int st = uzlib_uncompress(&decomp);
|
||||
if (st < 0) break; // error
|
||||
dma2d_wait_for_transfer();
|
||||
dma2d_start(next_buf->buffer, (uint8_t *)DISPLAY_DATA_ADDRESS, pixels);
|
||||
}
|
||||
dma2d_wait_for_transfer();
|
||||
buffers_free_line_16bpp(b1);
|
||||
buffers_free_line_16bpp(b2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// see docs/misc/toif.md for definition of the TOIF format
|
||||
bool display_toif_info(const uint8_t *data, uint32_t len, uint16_t *out_w,
|
||||
uint16_t *out_h, toif_format_t *out_format) {
|
||||
|
@ -57,8 +57,6 @@ void display_bar_radius_buffer(int x, int y, int w, int h, uint8_t r,
|
||||
|
||||
bool display_toif_info(const uint8_t *buf, uint32_t len, uint16_t *out_w,
|
||||
uint16_t *out_h, toif_format_t *out_format);
|
||||
void display_image(int x, int y, int w, int h, const void *data,
|
||||
uint32_t datalen);
|
||||
|
||||
#ifndef TREZOR_PRINT_DISABLE
|
||||
void display_print_color(uint16_t fgcolor, uint16_t bgcolor);
|
||||
|
@ -289,7 +289,6 @@ fn generate_trezorhal_bindings() {
|
||||
.allowlist_function("display_bar")
|
||||
.allowlist_function("display_bar_radius")
|
||||
.allowlist_function("display_bar_radius_buffer")
|
||||
.allowlist_function("display_image")
|
||||
.allowlist_function("display_pixeldata")
|
||||
.allowlist_function("display_pixeldata_dirty")
|
||||
.allowlist_function("display_set_window")
|
||||
@ -321,6 +320,7 @@ fn generate_trezorhal_bindings() {
|
||||
.allowlist_function("hal_ticks_ms")
|
||||
// dma2d
|
||||
.allowlist_function("dma2d_setup_4bpp")
|
||||
.allowlist_function("dma2d_setup_16bpp")
|
||||
.allowlist_function("dma2d_setup_4bpp_over_4bpp")
|
||||
.allowlist_function("dma2d_setup_4bpp_over_16bpp")
|
||||
.allowlist_function("dma2d_start")
|
||||
|
@ -25,3 +25,5 @@ uint32_t screen_install_fail(void);
|
||||
void screen_welcome_model(void);
|
||||
void screen_welcome(void);
|
||||
void screen_boot_empty(bool fading);
|
||||
|
||||
void display_image(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen);
|
||||
|
@ -103,19 +103,6 @@ pub fn bar_radius_buffer(x: i16, y: i16, w: i16, h: i16, radius: u8, buffer: &mu
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image(x: i16, y: i16, w: i16, h: i16, data: &[u8]) {
|
||||
unsafe {
|
||||
ffi::display_image(
|
||||
x.into(),
|
||||
y.into(),
|
||||
w.into(),
|
||||
h.into(),
|
||||
data.as_ptr() as _,
|
||||
data.len() as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(all(feature = "model_tt", target_arch = "arm"))]
|
||||
pub fn pixeldata(c: u16) {
|
||||
|
@ -4,6 +4,10 @@ pub fn dma2d_setup_4bpp(fg_color: u16, bg_color: u16) {
|
||||
unsafe { ffi::dma2d_setup_4bpp(fg_color, bg_color) }
|
||||
}
|
||||
|
||||
pub fn dma2d_setup_16bpp() {
|
||||
unsafe { ffi::dma2d_setup_16bpp() }
|
||||
}
|
||||
|
||||
pub fn dma2d_setup_4bpp_over_4bpp(fg_color: u16, bg_color: u16, overlay_color: u16) {
|
||||
unsafe { ffi::dma2d_setup_4bpp_over_4bpp(fg_color, bg_color, overlay_color) }
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
use crate::{
|
||||
trezorhal::display::{image, ToifFormat},
|
||||
trezorhal::display::ToifFormat,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
display::{toif::Toif, Color, Icon},
|
||||
display::{
|
||||
toif::{image, Toif},
|
||||
Color, Icon,
|
||||
},
|
||||
geometry::{Alignment2D, Offset, Point, Rect, CENTER},
|
||||
},
|
||||
};
|
||||
@ -28,7 +31,7 @@ impl Image {
|
||||
/// `alignment` argument.
|
||||
pub fn draw(&self, baseline: Point, alignment: Alignment2D) {
|
||||
let r = Rect::snap(baseline, self.toif.size(), alignment);
|
||||
image(r.x0, r.y0, r.width(), r.height(), self.toif.zdata());
|
||||
image(self, r.center());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,23 @@ use crate::{
|
||||
uzlib::{UzlibContext, UZLIB_WINDOW_SIZE},
|
||||
},
|
||||
ui::{
|
||||
component::image::Image,
|
||||
constant,
|
||||
display::{get_color_table, get_offset, pixeldata, pixeldata_dirty, set_window},
|
||||
geometry::{Alignment2D, Offset, Point, Rect},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::ui::geometry::TOP_LEFT;
|
||||
#[cfg(feature = "dma2d")]
|
||||
use crate::{
|
||||
trezorhal::{
|
||||
buffers::BufferLine16bpp,
|
||||
dma2d::{dma2d_setup_16bpp, dma2d_start, dma2d_wait_for_transfer},
|
||||
},
|
||||
ui::display::process_buffer,
|
||||
};
|
||||
|
||||
use super::Color;
|
||||
|
||||
const TOIF_HEADER_LENGTH: usize = 12;
|
||||
@ -49,6 +60,93 @@ pub fn icon(icon: &Icon, center: Point, fg_color: Color, bg_color: Color) {
|
||||
pixeldata_dirty();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn display_image(
|
||||
x: cty::int16_t,
|
||||
y: cty::int16_t,
|
||||
data: *const cty::uint8_t,
|
||||
data_len: cty::uint32_t,
|
||||
) {
|
||||
let data_slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) };
|
||||
let image = Image::new(data_slice);
|
||||
image.draw(Point::new(x, y), TOP_LEFT);
|
||||
}
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
pub fn image(image: &Image, center: Point) {
|
||||
let r = Rect::from_center_and_size(center, image.toif.size());
|
||||
let area = r.translate(get_offset());
|
||||
let clamped = area.clamp(constant::screen());
|
||||
|
||||
set_window(clamped);
|
||||
|
||||
let mut window = [0; UZLIB_WINDOW_SIZE];
|
||||
let mut ctx = image.toif.decompression_context(Some(&mut window));
|
||||
|
||||
let mut b1 = BufferLine16bpp::get_cleared();
|
||||
let mut b2 = BufferLine16bpp::get_cleared();
|
||||
|
||||
let mut decompressed_lines = 0;
|
||||
let clamp_x = if clamped.x0 > area.x0 {
|
||||
area.x0 - clamped.x0
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
dma2d_setup_16bpp();
|
||||
|
||||
for y in clamped.y0..clamped.y1 {
|
||||
let img_buffer_used = if y % 2 == 0 { &mut b1 } else { &mut b2 };
|
||||
|
||||
process_buffer(
|
||||
y,
|
||||
area,
|
||||
Offset::x(clamp_x),
|
||||
&mut ctx,
|
||||
&mut img_buffer_used.buffer,
|
||||
&mut decompressed_lines,
|
||||
16,
|
||||
);
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
unsafe { dma2d_start(&img_buffer_used.buffer, clamped.width()) };
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
pixeldata_dirty();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dma2d"))]
|
||||
pub fn image(image: &Image, center: Point) {
|
||||
let r = Rect::from_center_and_size(center, image.toif.size());
|
||||
let area = r.translate(get_offset());
|
||||
let clamped = area.clamp(constant::screen());
|
||||
|
||||
set_window(clamped);
|
||||
|
||||
let mut dest = [0_u8; 2];
|
||||
|
||||
let mut window = [0; UZLIB_WINDOW_SIZE];
|
||||
let mut ctx = image.toif.decompression_context(Some(&mut window));
|
||||
|
||||
for py in area.y0..area.y1 {
|
||||
for px in area.x0..area.x1 {
|
||||
let p = Point::new(px, py);
|
||||
|
||||
if clamped.contains(p) {
|
||||
unwrap!(ctx.uncompress(&mut dest), "Decompression failed");
|
||||
let c = Color::from_u16(u16::from_le_bytes(dest));
|
||||
pixeldata(c);
|
||||
} else {
|
||||
//continue unzipping but dont write to display
|
||||
unwrap!(ctx.uncompress(&mut dest), "Decompression failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pixeldata_dirty();
|
||||
}
|
||||
|
||||
/// Holding toif data and allowing it to draw itself.
|
||||
/// See https://docs.trezor.io/trezor-firmware/misc/toif.html for data format.
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
|
Loading…
Reference in New Issue
Block a user