refactor(core): rewrite display_image into rust

[no changelog]
pull/2983/head
tychovrahe 1 year ago committed by TychoVrahe
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…
Cancel
Save