mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-18 05:28:40 +00:00
refactor(core): improve safety of buffer handling
[no changelog]
This commit is contained in:
parent
640685a41f
commit
69be9b1edf
@ -22,82 +22,61 @@
|
||||
#include "fonts/fonts.h"
|
||||
#include "memzero.h"
|
||||
|
||||
#define BUFFERS_16BPP 3
|
||||
#define BUFFERS_4BPP 3
|
||||
#define BUFFERS_TEXT 1
|
||||
#define BUFFERS_JPEG 1
|
||||
#define BUFFERS_JPEG_WORK 1
|
||||
#define BUFFERS_BLURRING 1
|
||||
|
||||
const int32_t text_buffer_height = FONT_MAX_HEIGHT;
|
||||
const int32_t buffer_width = DISPLAY_RESX;
|
||||
|
||||
BUFFER_SECTION line_buffer_16bpp_t line_buffers_16bpp[BUFFERS_16BPP];
|
||||
BUFFER_SECTION line_buffer_4bpp_t line_buffers_4bpp[BUFFERS_4BPP];
|
||||
BUFFER_SECTION buffer_text_t text_buffers[BUFFERS_TEXT];
|
||||
NODMA_BUFFER_SECTION buffer_jpeg_t jpeg_buffers[BUFFERS_JPEG];
|
||||
NODMA_BUFFER_SECTION buffer_jpeg_work_t jpeg_work_buffers[BUFFERS_JPEG_WORK];
|
||||
NODMA_BUFFER_SECTION buffer_blurring_t blurring_buffers[BUFFERS_BLURRING];
|
||||
#define CONCAT_(a, b) a##b
|
||||
#define CONCAT(a, b) CONCAT_(a, b)
|
||||
|
||||
line_buffer_16bpp_t* buffers_get_line_buffer_16bpp(uint16_t idx, bool clear) {
|
||||
if (idx >= BUFFERS_16BPP) {
|
||||
return NULL;
|
||||
}
|
||||
if (clear) {
|
||||
memzero(&line_buffers_16bpp[idx], sizeof(line_buffers_16bpp[idx]));
|
||||
}
|
||||
return &line_buffers_16bpp[idx];
|
||||
}
|
||||
#define CONCAT3_(a, b, c) a##b##c
|
||||
#define CONCAT3(a, b, c) CONCAT3_(a, b, c)
|
||||
|
||||
line_buffer_4bpp_t* buffers_get_line_buffer_4bpp(uint16_t idx, bool clear) {
|
||||
if (idx >= BUFFERS_4BPP) {
|
||||
return NULL;
|
||||
}
|
||||
if (clear) {
|
||||
memzero(&line_buffers_4bpp[idx], sizeof(line_buffers_4bpp[idx]));
|
||||
}
|
||||
return &line_buffers_4bpp[idx];
|
||||
}
|
||||
#define STRUCT(name) CONCAT3(buffers_, name, _t)
|
||||
#define TYPE(name) CONCAT3(buffer_, name, _t)
|
||||
#define FUNCTION(name) CONCAT(buffers_get_, name)
|
||||
#define FUNCTION_FREE(name) CONCAT(buffers_free_, name)
|
||||
#define VARNAME(name) CONCAT(buffers_, name)
|
||||
|
||||
buffer_text_t* buffers_get_text_buffer(uint16_t idx, bool clear) {
|
||||
if (idx >= BUFFERS_TEXT) {
|
||||
return NULL;
|
||||
}
|
||||
if (clear) {
|
||||
memzero(&text_buffers[idx], sizeof(text_buffers[idx]));
|
||||
}
|
||||
return &text_buffers[idx];
|
||||
}
|
||||
|
||||
buffer_jpeg_t* buffers_get_jpeg_buffer(uint16_t idx, bool clear) {
|
||||
if (idx >= BUFFERS_JPEG) {
|
||||
return NULL;
|
||||
#define BUFFER(section, name, count) \
|
||||
typedef struct { \
|
||||
TYPE(name) buffers[count]; \
|
||||
uint8_t allocated[count]; \
|
||||
} STRUCT(name); \
|
||||
section STRUCT(name) VARNAME(name); \
|
||||
\
|
||||
TYPE(name) * FUNCTION(name)(bool clear) { \
|
||||
int idx = -1; \
|
||||
for (int i = 0; i < (count); i++) { \
|
||||
if (VARNAME(name).allocated[i] == 0) { \
|
||||
idx = i; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (idx < 0) { \
|
||||
return NULL; \
|
||||
} \
|
||||
if (clear) { \
|
||||
memzero(&VARNAME(name).buffers[idx], \
|
||||
sizeof(VARNAME(name).buffers[idx])); \
|
||||
} \
|
||||
VARNAME(name).allocated[idx] = 1; \
|
||||
return &VARNAME(name).buffers[idx]; \
|
||||
} \
|
||||
void FUNCTION_FREE(name)(TYPE(name) * buffer) { \
|
||||
if (buffer == NULL) { \
|
||||
return; \
|
||||
} \
|
||||
for (uint16_t i = 0; i < (count); i++) { \
|
||||
if (buffer == &VARNAME(name).buffers[i]) { \
|
||||
VARNAME(name).allocated[i] = 0; \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
memzero(&jpeg_buffers[idx], sizeof(jpeg_buffers[idx]));
|
||||
}
|
||||
return &jpeg_buffers[idx];
|
||||
}
|
||||
|
||||
buffer_jpeg_work_t* buffers_get_jpeg_work_buffer(uint16_t idx, bool clear) {
|
||||
if (idx >= BUFFERS_JPEG_WORK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
memzero(&jpeg_work_buffers[idx], sizeof(jpeg_work_buffers[idx]));
|
||||
}
|
||||
return &jpeg_work_buffers[idx];
|
||||
}
|
||||
|
||||
buffer_blurring_t* buffers_get_blurring_buffer(uint16_t idx, bool clear) {
|
||||
if (idx >= BUFFERS_BLURRING) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
memzero(&blurring_buffers[idx], sizeof(blurring_buffers[idx]));
|
||||
}
|
||||
return &blurring_buffers[idx];
|
||||
}
|
||||
BUFFER(BUFFER_SECTION, line_16bpp, 3);
|
||||
BUFFER(BUFFER_SECTION, line_4bpp, 3);
|
||||
BUFFER(BUFFER_SECTION, text, 1);
|
||||
BUFFER(NODMA_BUFFER_SECTION, jpeg, 1);
|
||||
BUFFER(NODMA_BUFFER_SECTION, jpeg_work, 1);
|
||||
BUFFER(NODMA_BUFFER_SECTION, blurring, 1);
|
||||
|
@ -59,11 +59,11 @@
|
||||
|
||||
typedef __attribute__((aligned(4))) struct {
|
||||
uint8_t buffer[LINE_BUFFER_16BPP_SIZE];
|
||||
} line_buffer_16bpp_t;
|
||||
} buffer_line_16bpp_t;
|
||||
|
||||
typedef __attribute__((aligned(4))) struct {
|
||||
uint8_t buffer[LINE_BUFFER_4BPP_SIZE];
|
||||
} line_buffer_4bpp_t;
|
||||
} buffer_line_4bpp_t;
|
||||
|
||||
typedef __attribute__((aligned(4))) struct {
|
||||
uint8_t buffer[TEXT_BUFFER_SIZE];
|
||||
@ -84,11 +84,22 @@ typedef __attribute__((aligned(4))) struct {
|
||||
extern const int32_t text_buffer_height;
|
||||
extern const int32_t buffer_width;
|
||||
|
||||
line_buffer_16bpp_t* buffers_get_line_buffer_16bpp(uint16_t idx, bool clear);
|
||||
line_buffer_4bpp_t* buffers_get_line_buffer_4bpp(uint16_t idx, bool clear);
|
||||
buffer_text_t* buffers_get_text_buffer(uint16_t idx, bool clear);
|
||||
buffer_jpeg_t* buffers_get_jpeg_buffer(uint16_t idx, bool clear);
|
||||
buffer_jpeg_work_t* buffers_get_jpeg_work_buffer(uint16_t idx, bool clear);
|
||||
buffer_blurring_t* buffers_get_blurring_buffer(uint16_t idx, bool clear);
|
||||
buffer_line_16bpp_t* buffers_get_line_16bpp(bool clear);
|
||||
void buffers_free_line_16bpp(buffer_line_16bpp_t* buffer);
|
||||
|
||||
buffer_line_4bpp_t* buffers_get_line_4bpp(bool clear);
|
||||
void buffers_free_line_4bpp(buffer_line_4bpp_t* buffer);
|
||||
|
||||
buffer_text_t* buffers_get_text(bool clear);
|
||||
void buffers_free_text(buffer_text_t* buffer);
|
||||
|
||||
buffer_jpeg_t* buffers_get_jpeg(bool clear);
|
||||
void buffers_free_jpeg(buffer_jpeg_t* buffer);
|
||||
|
||||
buffer_jpeg_work_t* buffers_get_jpeg_work(bool clear);
|
||||
void buffers_free_jpeg_work(buffer_jpeg_work_t* buffer);
|
||||
|
||||
buffer_blurring_t* buffers_get_blurring(bool clear);
|
||||
void buffers_free_blurring(buffer_blurring_t* buffer);
|
||||
|
||||
#endif // _BUFFERS_H
|
||||
|
@ -312,8 +312,13 @@ void display_image(int x, int y, int w, int h, const void *data,
|
||||
struct uzlib_uncomp decomp = {0};
|
||||
uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {0};
|
||||
|
||||
line_buffer_16bpp_t *b1 = buffers_get_line_buffer_16bpp(0, false);
|
||||
line_buffer_16bpp_t *b2 = buffers_get_line_buffer_16bpp(1, false);
|
||||
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);
|
||||
|
||||
@ -321,7 +326,7 @@ void display_image(int x, int y, int w, int h, const void *data,
|
||||
|
||||
for (int32_t pos = 0; pos < h; pos++) {
|
||||
int32_t pixels = w;
|
||||
line_buffer_16bpp_t *next_buf = (pos % 2 == 1) ? b1 : b2;
|
||||
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);
|
||||
@ -330,6 +335,8 @@ void display_image(int x, int y, int w, int h, const void *data,
|
||||
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
|
||||
|
||||
@ -391,8 +398,13 @@ void display_icon(int x, int y, int w, int h, const void *data,
|
||||
}
|
||||
|
||||
uint8_t b[DISPLAY_RESX / 2];
|
||||
line_buffer_4bpp_t *b1 = buffers_get_line_buffer_4bpp(0, false);
|
||||
line_buffer_4bpp_t *b2 = buffers_get_line_buffer_4bpp(1, false);
|
||||
buffer_line_4bpp_t *b1 = buffers_get_line_4bpp(false);
|
||||
if (b1 == NULL) return;
|
||||
buffer_line_4bpp_t *b2 = buffers_get_line_4bpp(false);
|
||||
if (b2 == NULL) {
|
||||
buffers_free_line_4bpp(b1);
|
||||
return;
|
||||
}
|
||||
|
||||
struct uzlib_uncomp decomp = {0};
|
||||
uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {0};
|
||||
@ -404,7 +416,7 @@ void display_icon(int x, int y, int w, int h, const void *data,
|
||||
int off_x = x < 0 ? -x : 0;
|
||||
|
||||
for (uint32_t pos = 0; pos < h; pos++) {
|
||||
line_buffer_4bpp_t *next_buf = (pos % 2 == 0) ? b1 : b2;
|
||||
buffer_line_4bpp_t *next_buf = (pos % 2 == 0) ? b1 : b2;
|
||||
decomp.dest = b;
|
||||
decomp.dest_limit = b + w / 2;
|
||||
int st = uzlib_uncompress(&decomp);
|
||||
@ -416,6 +428,8 @@ void display_icon(int x, int y, int w, int h, const void *data,
|
||||
}
|
||||
}
|
||||
dma2d_wait_for_transfer();
|
||||
buffers_free_line_4bpp(b1);
|
||||
buffers_free_line_4bpp(b2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -328,12 +328,24 @@ fn generate_trezorhal_bindings() {
|
||||
.allowlist_function("dma2d_start_blend")
|
||||
.allowlist_function("dma2d_wait_for_transfer")
|
||||
//buffers
|
||||
.allowlist_function("buffers_get_line_buffer_16bpp")
|
||||
.allowlist_function("buffers_get_line_buffer_4bpp")
|
||||
.allowlist_function("buffers_get_text_buffer")
|
||||
.allowlist_function("buffers_get_jpeg_buffer")
|
||||
.allowlist_function("buffers_get_jpeg_work_buffer")
|
||||
.allowlist_function("buffers_get_blurring_buffer")
|
||||
.allowlist_function("buffers_get_line_16bpp")
|
||||
.allowlist_function("buffers_free_line_16bpp")
|
||||
.allowlist_function("buffers_get_line_4bpp")
|
||||
.allowlist_function("buffers_free_line_4bpp")
|
||||
.allowlist_function("buffers_get_text")
|
||||
.allowlist_function("buffers_free_text")
|
||||
.allowlist_function("buffers_get_jpeg")
|
||||
.allowlist_function("buffers_free_jpeg")
|
||||
.allowlist_function("buffers_get_jpeg_work")
|
||||
.allowlist_function("buffers_free_jpeg_work")
|
||||
.allowlist_function("buffers_get_blurring")
|
||||
.allowlist_function("buffers_free_blurring")
|
||||
.no_copy("buffer_line_16bpp_t")
|
||||
.no_copy("buffer_line_4bpp_t")
|
||||
.no_copy("buffer_text_t")
|
||||
.no_copy("buffer_jpeg_t")
|
||||
.no_copy("buffer_jpeg_work_t")
|
||||
.no_copy("buffer_blurring_t")
|
||||
.allowlist_var("text_buffer_height")
|
||||
.allowlist_var("buffer_width")
|
||||
//usb
|
||||
|
@ -1,88 +1,93 @@
|
||||
use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
ptr,
|
||||
};
|
||||
|
||||
use super::ffi;
|
||||
|
||||
pub use ffi::{
|
||||
buffer_blurring_t as BlurringBuffer, buffer_text_t as BufferText,
|
||||
line_buffer_16bpp_t as LineBuffer16Bpp, line_buffer_4bpp_t as LineBuffer4Bpp,
|
||||
};
|
||||
macro_rules! buffer_wrapper {
|
||||
($rust_name: ident, $type: ident, $get: ident, $free: ident) => {
|
||||
pub struct $rust_name(ptr::NonNull<ffi::$type>);
|
||||
|
||||
impl $rust_name {
|
||||
pub fn get() -> Self {
|
||||
unsafe {
|
||||
let ptr = ffi::$get(false);
|
||||
Self(unwrap!(ptr::NonNull::new(ptr)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cleared() -> Self {
|
||||
unsafe {
|
||||
let ptr = ffi::$get(true);
|
||||
Self(unwrap!(ptr::NonNull::new(ptr)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for $rust_name {
|
||||
type Target = ffi::$type;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// SAFETY: The lifetime of the pointer is 'static and the C API
|
||||
// promises that we are the sole owner.
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for $rust_name {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
// SAFETY: The lifetime of the pointer is 'static and the C API
|
||||
// promises that we are the sole owner, and we have borrowed mutably.
|
||||
unsafe { self.0.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $rust_name {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::$free(self.0.as_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
buffer_wrapper!(
|
||||
BufferLine16bpp,
|
||||
buffer_line_16bpp_t,
|
||||
buffers_get_line_16bpp,
|
||||
buffers_free_line_16bpp
|
||||
);
|
||||
buffer_wrapper!(
|
||||
BufferLine4bpp,
|
||||
buffer_line_4bpp_t,
|
||||
buffers_get_line_4bpp,
|
||||
buffers_free_line_4bpp
|
||||
);
|
||||
buffer_wrapper!(
|
||||
BufferText,
|
||||
buffer_text_t,
|
||||
buffers_get_text,
|
||||
buffers_free_text
|
||||
);
|
||||
buffer_wrapper!(
|
||||
BufferBlurring,
|
||||
buffer_blurring_t,
|
||||
buffers_get_blurring,
|
||||
buffers_free_blurring
|
||||
);
|
||||
#[cfg(feature = "jpeg")]
|
||||
pub use ffi::{buffer_jpeg_t as BufferJpeg, buffer_jpeg_work_t as BufferJpegWork};
|
||||
|
||||
/// Returns a buffer for one line of 16bpp data
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee
|
||||
/// that he doesn't use buffer on same index multiple times
|
||||
pub unsafe fn get_buffer_16bpp(idx: u16, clear: bool) -> &'static mut LineBuffer16Bpp {
|
||||
unsafe {
|
||||
let ptr = ffi::buffers_get_line_buffer_16bpp(idx, clear);
|
||||
unwrap!(ptr.as_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a buffer for one line of 4bpp data
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee
|
||||
/// that he doesn't use buffer on same index multiple times
|
||||
pub unsafe fn get_buffer_4bpp(idx: u16, clear: bool) -> &'static mut LineBuffer4Bpp {
|
||||
unsafe {
|
||||
let ptr = ffi::buffers_get_line_buffer_4bpp(idx, clear);
|
||||
unwrap!(ptr.as_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a buffer for one line of text
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee
|
||||
/// that he doesn't use buffer on same index multiple times
|
||||
pub unsafe fn get_text_buffer(idx: u16, clear: bool) -> &'static mut BufferText {
|
||||
unsafe {
|
||||
let ptr = ffi::buffers_get_text_buffer(idx, clear);
|
||||
unwrap!(ptr.as_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a buffer for jpeg data
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee
|
||||
/// that he doesn't use buffer on same index multiple times
|
||||
buffer_wrapper!(
|
||||
BufferJpeg,
|
||||
buffer_jpeg_t,
|
||||
buffers_get_jpeg,
|
||||
buffers_free_jpeg
|
||||
);
|
||||
#[cfg(feature = "jpeg")]
|
||||
pub unsafe fn get_jpeg_buffer(idx: u16, clear: bool) -> &'static mut BufferJpeg {
|
||||
unsafe {
|
||||
let ptr = ffi::buffers_get_jpeg_buffer(idx, clear);
|
||||
unwrap!(ptr.as_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a jpeg work buffer
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee
|
||||
/// that he doesn't use buffer on same index multiple times
|
||||
#[cfg(feature = "jpeg")]
|
||||
pub unsafe fn get_jpeg_work_buffer(idx: u16, clear: bool) -> &'static mut BufferJpegWork {
|
||||
unsafe {
|
||||
let ptr = ffi::buffers_get_jpeg_work_buffer(idx, clear);
|
||||
unwrap!(ptr.as_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a buffer for blurring data
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee
|
||||
/// that he doesn't use buffer on same index multiple times
|
||||
pub unsafe fn get_blurring_buffer(idx: u16, clear: bool) -> &'static mut BlurringBuffer {
|
||||
unsafe {
|
||||
let ptr = ffi::buffers_get_blurring_buffer(idx, clear);
|
||||
unwrap!(ptr.as_mut())
|
||||
}
|
||||
}
|
||||
buffer_wrapper!(
|
||||
BufferJpegWork,
|
||||
buffer_jpeg_work_t,
|
||||
buffers_get_jpeg_work,
|
||||
buffers_free_jpeg_work
|
||||
);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::ffi;
|
||||
use core::ptr;
|
||||
use core::{ops::DerefMut, ptr};
|
||||
use cty::c_int;
|
||||
|
||||
use crate::trezorhal::buffers::BufferText;
|
||||
@ -36,7 +36,7 @@ pub fn text_into_buffer(text: &str, font: i32, buffer: &mut BufferText, x_offset
|
||||
text.as_ptr() as _,
|
||||
text.len() as _,
|
||||
font,
|
||||
buffer as _,
|
||||
buffer.deref_mut(),
|
||||
x_offset.into(),
|
||||
)
|
||||
}
|
||||
@ -92,7 +92,14 @@ pub fn bar_radius(x: i16, y: i16, w: i16, h: i16, fgcolor: u16, bgcolor: u16, ra
|
||||
|
||||
pub fn bar_radius_buffer(x: i16, y: i16, w: i16, h: i16, radius: u8, buffer: &mut BufferText) {
|
||||
unsafe {
|
||||
ffi::display_bar_radius_buffer(x.into(), y.into(), w.into(), h.into(), radius, buffer as _)
|
||||
ffi::display_bar_radius_buffer(
|
||||
x.into(),
|
||||
y.into(),
|
||||
w.into(),
|
||||
h.into(),
|
||||
radius,
|
||||
buffer.deref_mut(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,16 @@ pub fn dma2d_setup_4bpp_over_16bpp(overlay_color: u16) {
|
||||
unsafe { ffi::dma2d_setup_4bpp_over_16bpp(overlay_color) }
|
||||
}
|
||||
|
||||
pub fn dma2d_start(buffer: &[u8], pixels: i16) {
|
||||
/// Starts dma2d transfer
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee that he:
|
||||
/// 1) doesn't mutate the buffers until the transfer is finished, which is
|
||||
/// guaranteed by calling `dma2d_wait_for_transfer`
|
||||
/// 2) the buffer doesn't get dropped until the transfer is finished
|
||||
/// 3) doesn't call this function while another transfer is running
|
||||
pub unsafe fn dma2d_start(buffer: &[u8], pixels: i16) {
|
||||
unsafe {
|
||||
ffi::dma2d_start(
|
||||
buffer.as_ptr() as _,
|
||||
@ -22,7 +31,16 @@ pub fn dma2d_start(buffer: &[u8], pixels: i16) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dma2d_start_blend(overlay_buffer: &[u8], bg_buffer: &[u8], pixels: i16) {
|
||||
/// Starts blending
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because the caller has to guarantee that he:
|
||||
/// 1) doesn't mutate the buffers until the transfer is finished, which is
|
||||
/// guaranteed by calling `dma2d_wait_for_transfer`
|
||||
/// 2) the buffer doesn't get dropped until the transfer is finished
|
||||
/// 3) doesn't call this function while another transfer is running
|
||||
pub unsafe fn dma2d_start_blend(overlay_buffer: &[u8], bg_buffer: &[u8], pixels: i16) {
|
||||
unsafe {
|
||||
ffi::dma2d_start_blend(
|
||||
overlay_buffer.as_ptr() as _,
|
||||
|
@ -8,7 +8,7 @@ use crate::ui::{
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
use crate::trezorhal::{
|
||||
buffers::{get_buffer_16bpp, get_buffer_4bpp},
|
||||
buffers,
|
||||
dma2d::{dma2d_setup_4bpp_over_4bpp, dma2d_start_blend, dma2d_wait_for_transfer},
|
||||
};
|
||||
|
||||
@ -353,11 +353,11 @@ pub fn loader_rust(
|
||||
|
||||
let n_start = Point::new(-start_vector.y, start_vector.x);
|
||||
|
||||
let b1 = unsafe { get_buffer_16bpp(0, false) };
|
||||
let b2 = unsafe { get_buffer_16bpp(1, false) };
|
||||
let ib1 = unsafe { get_buffer_4bpp(0, true) };
|
||||
let ib2 = unsafe { get_buffer_4bpp(1, true) };
|
||||
let empty_line = unsafe { get_buffer_4bpp(2, true) };
|
||||
let mut b1 = buffers::BufferLine16bpp::get();
|
||||
let mut b2 = buffers::BufferLine16bpp::get();
|
||||
let mut ib1 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut ib2 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut empty_line = buffers::BufferLine4bpp::get_cleared();
|
||||
|
||||
dma2d_setup_4bpp_over_4bpp(fg_color.into(), bg_color.into(), icon_color.into());
|
||||
|
||||
@ -420,7 +420,9 @@ pub fn loader_rust(
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
dma2d_start_blend(&icon_buffer.buffer, &loader_buffer.buffer, clamped.width());
|
||||
unsafe {
|
||||
dma2d_start_blend(&icon_buffer.buffer, &loader_buffer.buffer, clamped.width());
|
||||
}
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
|
@ -9,7 +9,6 @@ use super::{
|
||||
};
|
||||
#[cfg(feature = "dma2d")]
|
||||
use crate::trezorhal::{
|
||||
buffers::{get_buffer_16bpp, get_buffer_4bpp},
|
||||
dma2d::{
|
||||
dma2d_setup_4bpp_over_16bpp, dma2d_setup_4bpp_over_4bpp, dma2d_start_blend,
|
||||
dma2d_wait_for_transfer,
|
||||
@ -21,7 +20,7 @@ use crate::ui::geometry::TOP_LEFT;
|
||||
|
||||
use crate::{
|
||||
time::Duration,
|
||||
trezorhal::{buffers::get_text_buffer, display, time, uzlib::UzlibContext},
|
||||
trezorhal::{buffers, display, time, uzlib::UzlibContext},
|
||||
ui::lerp::Lerp,
|
||||
};
|
||||
use core::slice;
|
||||
@ -448,13 +447,13 @@ pub fn text_over_image(
|
||||
offset_text: Offset,
|
||||
text_color: Color,
|
||||
) {
|
||||
let text_buffer = unsafe { get_text_buffer(0, true) };
|
||||
let img1 = unsafe { get_buffer_16bpp(0, true) };
|
||||
let img2 = unsafe { get_buffer_16bpp(1, true) };
|
||||
let empty_img = unsafe { get_buffer_16bpp(2, true) };
|
||||
let t1 = unsafe { get_buffer_4bpp(0, true) };
|
||||
let t2 = unsafe { get_buffer_4bpp(1, true) };
|
||||
let empty_t = unsafe { get_buffer_4bpp(2, true) };
|
||||
let mut text_buffer = buffers::BufferText::get();
|
||||
let mut img1 = buffers::BufferLine16bpp::get_cleared();
|
||||
let mut img2 = buffers::BufferLine16bpp::get_cleared();
|
||||
let mut empty_img = buffers::BufferLine16bpp::get_cleared();
|
||||
let mut t1 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut t2 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut empty_t = buffers::BufferLine4bpp::get_cleared();
|
||||
|
||||
let r_img;
|
||||
let area;
|
||||
@ -495,7 +494,7 @@ pub fn text_over_image(
|
||||
Point::new(text_right, text_bottom),
|
||||
);
|
||||
|
||||
display::text_into_buffer(text, font.into(), text_buffer, 0);
|
||||
display::text_into_buffer(text, font.into(), &mut text_buffer, 0);
|
||||
|
||||
set_window(clamped);
|
||||
|
||||
@ -548,7 +547,7 @@ pub fn text_over_image(
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
dma2d_start_blend(&t_buffer.buffer, &img_buffer.buffer, clamped.width());
|
||||
unsafe { dma2d_start_blend(&t_buffer.buffer, &img_buffer.buffer, clamped.width()) };
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
@ -572,12 +571,12 @@ pub fn icon_over_icon(
|
||||
fg: (Icon, Offset, Color),
|
||||
bg_color: Color,
|
||||
) {
|
||||
let bg1 = unsafe { get_buffer_16bpp(0, true) };
|
||||
let bg2 = unsafe { get_buffer_16bpp(1, true) };
|
||||
let empty1 = unsafe { get_buffer_16bpp(2, true) };
|
||||
let fg1 = unsafe { get_buffer_4bpp(0, true) };
|
||||
let fg2 = unsafe { get_buffer_4bpp(1, true) };
|
||||
let empty2 = unsafe { get_buffer_4bpp(2, true) };
|
||||
let mut bg1 = buffers::BufferLine16bpp::get_cleared();
|
||||
let mut bg2 = buffers::BufferLine16bpp::get_cleared();
|
||||
let mut empty1 = buffers::BufferLine16bpp::get_cleared();
|
||||
let mut fg1 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut fg2 = buffers::BufferLine4bpp::get_cleared();
|
||||
let mut empty2 = buffers::BufferLine4bpp::get_cleared();
|
||||
|
||||
let (icon_bg, offset_bg, color_icon_bg) = bg;
|
||||
let (icon_fg, offset_fg, color_icon_fg) = fg;
|
||||
@ -662,7 +661,7 @@ pub fn icon_over_icon(
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
dma2d_start_blend(&fg_buffer.buffer, &bg_buffer.buffer, clamped.width());
|
||||
unsafe { dma2d_start_blend(&fg_buffer.buffer, &bg_buffer.buffer, clamped.width()) };
|
||||
}
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
@ -768,13 +767,13 @@ pub fn bar_with_text_and_fill(
|
||||
}
|
||||
|
||||
pub fn marquee(area: Rect, text: &str, offset: i16, font: Font, fg: Color, bg: Color) {
|
||||
let buffer = unsafe { get_text_buffer(0, true) };
|
||||
let mut buffer = buffers::BufferText::get_cleared();
|
||||
|
||||
let area = area.translate(get_offset());
|
||||
let clamped = area.clamp(constant::screen());
|
||||
set_window(clamped);
|
||||
|
||||
display::text_into_buffer(text, font.into(), buffer, offset);
|
||||
display::text_into_buffer(text, font.into(), &mut buffer, offset);
|
||||
let tbl = get_color_table(fg, bg);
|
||||
|
||||
for y in 0..clamped.height() {
|
||||
|
@ -35,7 +35,7 @@ Trezor modifications:
|
||||
|
||||
use crate::{
|
||||
trezorhal::{
|
||||
buffers::{get_jpeg_work_buffer, BufferJpeg},
|
||||
buffers::{BufferJpeg, BufferJpegWork},
|
||||
display::pixeldata,
|
||||
},
|
||||
ui::{
|
||||
@ -1399,7 +1399,8 @@ impl<'i, 'p> JDEC<'i, 'p> {
|
||||
}
|
||||
|
||||
pub fn jpeg(data: &[u8], pos: Point, scale: u8) {
|
||||
let pool = unsafe { get_jpeg_work_buffer(0, true).buffer.as_mut_slice() };
|
||||
let mut buffer = BufferJpegWork::get_cleared();
|
||||
let pool = buffer.buffer.as_mut_slice();
|
||||
let mut out = PixelDataOutput(pos);
|
||||
let mut inp = BufferInput(data);
|
||||
if let Ok(mut jd) = JDEC::new(&mut inp, pool) {
|
||||
@ -1409,9 +1410,10 @@ pub fn jpeg(data: &[u8], pos: Point, scale: u8) {
|
||||
}
|
||||
|
||||
pub fn jpeg_info(data: &[u8]) -> Option<(Offset, i16)> {
|
||||
let pool = unsafe { get_jpeg_work_buffer(0, true).buffer.as_mut_slice() };
|
||||
let mut buffer = BufferJpegWork::get_cleared();
|
||||
let pool = buffer.buffer.as_mut_slice();
|
||||
let mut inp = BufferInput(data);
|
||||
if let Ok(jd) = JDEC::new(&mut inp, pool) {
|
||||
let result = if let Ok(jd) = JDEC::new(&mut inp, pool) {
|
||||
let mcu_height = jd.mcu_height();
|
||||
if mcu_height > 16 {
|
||||
return None;
|
||||
@ -1419,13 +1421,15 @@ pub fn jpeg_info(data: &[u8]) -> Option<(Offset, i16)> {
|
||||
Some((Offset::new(jd.width(), jd.height()), mcu_height))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
pub fn jpeg_test(data: &[u8]) -> bool {
|
||||
let pool = unsafe { get_jpeg_work_buffer(0, true).buffer.as_mut_slice() };
|
||||
let mut buffer = BufferJpegWork::get_cleared();
|
||||
let pool = buffer.buffer.as_mut_slice();
|
||||
let mut inp = BufferInput(data);
|
||||
if let Ok(mut jd) = JDEC::new(&mut inp, pool) {
|
||||
let result = if let Ok(mut jd) = JDEC::new(&mut inp, pool) {
|
||||
if jd.mcu_height() > 16 {
|
||||
return false;
|
||||
}
|
||||
@ -1438,7 +1442,8 @@ pub fn jpeg_test(data: &[u8]) -> bool {
|
||||
res.is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
result
|
||||
}
|
||||
|
||||
pub trait JpegInput {
|
||||
@ -1464,18 +1469,18 @@ pub trait JpegOutput {
|
||||
fn write(&mut self, jd: &JDEC, rect: Rect, pixels: &[u16]) -> bool;
|
||||
}
|
||||
|
||||
pub struct BufferOutput<'o> {
|
||||
buffer: &'o mut BufferJpeg,
|
||||
pub struct BufferOutput {
|
||||
buffer: BufferJpeg,
|
||||
buffer_width: i16,
|
||||
buffer_height: i16,
|
||||
current_line: i16,
|
||||
current_line_pix: i16,
|
||||
}
|
||||
|
||||
impl<'o> BufferOutput<'o> {
|
||||
pub fn new(buffer: &'o mut BufferJpeg, buffer_width: i16, buffer_height: i16) -> Self {
|
||||
impl BufferOutput {
|
||||
pub fn new(buffer_width: i16, buffer_height: i16) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
buffer: BufferJpeg::get_cleared(),
|
||||
buffer_width,
|
||||
buffer_height,
|
||||
current_line: 0,
|
||||
@ -1484,11 +1489,11 @@ impl<'o> BufferOutput<'o> {
|
||||
}
|
||||
|
||||
pub fn buffer(&mut self) -> &mut BufferJpeg {
|
||||
self.buffer
|
||||
&mut self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl<'o> JpegOutput for BufferOutput<'o> {
|
||||
impl JpegOutput for BufferOutput {
|
||||
fn write(&mut self, jd: &JDEC, rect: Rect, bitmap: &[u16]) -> bool {
|
||||
let w = rect.width();
|
||||
let h = rect.height();
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
trezorhal::{display::ToifFormat, uzlib::UZLIB_WINDOW_SIZE},
|
||||
trezorhal::{buffers::BufferJpegWork, display::ToifFormat, uzlib::UZLIB_WINDOW_SIZE},
|
||||
ui::{
|
||||
constant::HEIGHT,
|
||||
display::{tjpgd::BufferInput, toif::Toif},
|
||||
@ -211,7 +211,8 @@ where
|
||||
if let Ok(data) = res {
|
||||
if is_image_jpeg(data.as_ref()) {
|
||||
let mut input = BufferInput(data.as_ref());
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input);
|
||||
let mut pool = BufferJpegWork::get_cleared();
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input, pool.buffer.as_mut_slice());
|
||||
homescreen(
|
||||
&mut hs_img,
|
||||
&[text],
|
||||
@ -236,7 +237,8 @@ where
|
||||
|
||||
if show_default {
|
||||
let mut input = BufferInput(IMAGE_HOMESCREEN);
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input);
|
||||
let mut pool = BufferJpegWork::get_cleared();
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input, pool.buffer.as_mut_slice());
|
||||
homescreen(
|
||||
&mut hs_img,
|
||||
&[text],
|
||||
@ -328,7 +330,8 @@ where
|
||||
if let Ok(data) = res {
|
||||
if is_image_jpeg(data.as_ref()) {
|
||||
let mut input = BufferInput(data.as_ref());
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input);
|
||||
let mut pool = BufferJpegWork::get_cleared();
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input, pool.buffer.as_mut_slice());
|
||||
homescreen_blurred(&mut hs_img, &texts);
|
||||
show_default = false;
|
||||
} else if is_image_toif(data.as_ref()) {
|
||||
@ -343,7 +346,8 @@ where
|
||||
|
||||
if show_default {
|
||||
let mut input = BufferInput(IMAGE_HOMESCREEN);
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input);
|
||||
let mut pool = BufferJpegWork::get_cleared();
|
||||
let mut hs_img = HomescreenJpeg::new(&mut input, pool.buffer.as_mut_slice());
|
||||
homescreen_blurred(&mut hs_img, &texts);
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,25 @@
|
||||
#[cfg(feature = "dma2d")]
|
||||
use crate::trezorhal::{
|
||||
buffers::{get_buffer_16bpp, get_buffer_4bpp, get_text_buffer, BufferText, LineBuffer4Bpp},
|
||||
dma2d::{dma2d_setup_4bpp_over_16bpp, dma2d_start_blend, dma2d_wait_for_transfer},
|
||||
};
|
||||
use crate::{
|
||||
trezorhal::{
|
||||
buffers::{get_blurring_buffer, get_jpeg_buffer, get_jpeg_work_buffer, BufferJpeg},
|
||||
buffers::{BufferBlurring, BufferJpeg, BufferLine16bpp, BufferLine4bpp, BufferText},
|
||||
display,
|
||||
display::bar_radius_buffer,
|
||||
dma2d::{dma2d_setup_4bpp_over_16bpp, dma2d_start_blend, dma2d_wait_for_transfer},
|
||||
uzlib::UzlibContext,
|
||||
},
|
||||
ui::{
|
||||
constant::screen,
|
||||
display::{position_buffer, set_window, Color},
|
||||
component::text::TextStyle,
|
||||
constant::{screen, HEIGHT, WIDTH},
|
||||
display::{
|
||||
position_buffer, set_window,
|
||||
tjpgd::{BufferInput, BufferOutput, JDEC},
|
||||
Color, Icon,
|
||||
},
|
||||
geometry::{Offset, Point, Rect},
|
||||
model_tt::theme,
|
||||
util::icon_text_center,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::ui::{
|
||||
component::text::TextStyle,
|
||||
constant::{HEIGHT, WIDTH},
|
||||
display::{
|
||||
tjpgd::{BufferInput, BufferOutput, JDEC},
|
||||
Icon,
|
||||
},
|
||||
model_tt::theme,
|
||||
util::icon_text_center,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct HomescreenText<'a> {
|
||||
pub text: &'a str,
|
||||
@ -91,18 +83,15 @@ pub trait HomescreenDecompressor {
|
||||
}
|
||||
|
||||
pub struct HomescreenJpeg<'i> {
|
||||
pub output: BufferOutput<'i>,
|
||||
pub output: BufferOutput,
|
||||
pub jdec: Option<JDEC<'i, 'i>>,
|
||||
}
|
||||
|
||||
impl<'i> HomescreenJpeg<'i> {
|
||||
pub fn new(input: &'i mut BufferInput<'i>) -> Self {
|
||||
pub fn new(input: &'i mut BufferInput<'i>, pool: &'i mut [u8]) -> Self {
|
||||
Self {
|
||||
output: BufferOutput::new(unsafe { get_jpeg_buffer(0, true) }, WIDTH, 16),
|
||||
jdec: JDEC::new(input, unsafe {
|
||||
get_jpeg_work_buffer(0, true).buffer.as_mut_slice()
|
||||
})
|
||||
.ok(),
|
||||
output: BufferOutput::new(WIDTH, 16),
|
||||
jdec: JDEC::new(input, pool).ok(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,7 +114,7 @@ impl<'i> HomescreenDecompressor for HomescreenJpeg<'i> {
|
||||
}
|
||||
|
||||
pub struct HomescreenToif<'i> {
|
||||
pub output: BufferOutput<'i>,
|
||||
pub output: BufferOutput,
|
||||
pub decomp_context: UzlibContext<'i>,
|
||||
line: i16,
|
||||
}
|
||||
@ -133,7 +122,7 @@ pub struct HomescreenToif<'i> {
|
||||
impl<'i> HomescreenToif<'i> {
|
||||
pub fn new(context: UzlibContext<'i>) -> Self {
|
||||
Self {
|
||||
output: BufferOutput::new(unsafe { get_jpeg_buffer(0, true) }, WIDTH, 16),
|
||||
output: BufferOutput::new(WIDTH, 16),
|
||||
decomp_context: context,
|
||||
line: 0,
|
||||
}
|
||||
@ -184,7 +173,7 @@ fn homescreen_get_fg_text(
|
||||
y_tmp: i16,
|
||||
text_info: HomescreenTextInfo,
|
||||
text_buffer: &BufferText,
|
||||
fg_buffer: &mut LineBuffer4Bpp,
|
||||
fg_buffer: &mut BufferLine4bpp,
|
||||
) -> bool {
|
||||
if y_tmp >= text_info.text_area.y0 && y_tmp < text_info.text_area.y1 {
|
||||
let y_pos = y_tmp - text_info.text_area.y0;
|
||||
@ -204,7 +193,7 @@ fn homescreen_get_fg_icon(
|
||||
y_tmp: i16,
|
||||
text_info: HomescreenTextInfo,
|
||||
icon_data: &[u8],
|
||||
fg_buffer: &mut LineBuffer4Bpp,
|
||||
fg_buffer: &mut BufferLine4bpp,
|
||||
) {
|
||||
if let Some(icon_area) = text_info.icon_area {
|
||||
let icon_size = icon_area.size();
|
||||
@ -291,13 +280,13 @@ fn homescreen_dim_area(x: i16, y: i16) -> bool {
|
||||
fn homescreen_line_blurred(
|
||||
icon_data: &[u8],
|
||||
text_buffer: &mut BufferText,
|
||||
fg_buffer: &mut BufferLine4bpp,
|
||||
img_buffer: &mut BufferLine16bpp,
|
||||
text_info: HomescreenTextInfo,
|
||||
blurring: &BlurringContext,
|
||||
y: i16,
|
||||
) -> bool {
|
||||
let t_buffer = unsafe { get_buffer_4bpp((y & 0x1) as u16, true) };
|
||||
let mut img_buffer = unsafe { get_buffer_16bpp((y & 0x1) as u16, false) };
|
||||
|
||||
fg_buffer.buffer.fill(0);
|
||||
for x in 0..HOMESCREEN_IMAGE_WIDTH {
|
||||
let c = if LOCKSCREEN_DIM_ALL {
|
||||
let x = x as usize;
|
||||
@ -327,28 +316,31 @@ fn homescreen_line_blurred(
|
||||
img_buffer.buffer[j] = (c & 0xFF) as u8;
|
||||
}
|
||||
|
||||
let done = homescreen_get_fg_text(y, text_info, text_buffer, t_buffer);
|
||||
homescreen_get_fg_icon(y, text_info, icon_data, t_buffer);
|
||||
let done = homescreen_get_fg_text(y, text_info, text_buffer, fg_buffer);
|
||||
homescreen_get_fg_icon(y, text_info, icon_data, fg_buffer);
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
dma2d_setup_4bpp_over_16bpp(text_info.text_color.into());
|
||||
dma2d_start_blend(&t_buffer.buffer, &img_buffer.buffer, WIDTH);
|
||||
unsafe {
|
||||
dma2d_start_blend(&fg_buffer.buffer, &img_buffer.buffer, WIDTH);
|
||||
}
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn homescreen_line(
|
||||
icon_data: &[u8],
|
||||
text_buffer: &mut BufferText,
|
||||
text_info: HomescreenTextInfo,
|
||||
data_buffer: &mut BufferJpeg,
|
||||
fg_buffer: &mut BufferLine4bpp,
|
||||
img_buffer: &mut BufferLine16bpp,
|
||||
mcu_height: i16,
|
||||
y: i16,
|
||||
) -> bool {
|
||||
let t_buffer = unsafe { get_buffer_4bpp((y & 0x1) as u16, true) };
|
||||
let mut img_buffer = unsafe { get_buffer_16bpp((y & 0x1) as u16, false) };
|
||||
|
||||
let image_data = get_data(data_buffer, y, mcu_height);
|
||||
fg_buffer.buffer.fill(0);
|
||||
|
||||
for x in 0..HOMESCREEN_IMAGE_WIDTH {
|
||||
let d = image_data[x as usize];
|
||||
@ -373,12 +365,14 @@ fn homescreen_line(
|
||||
img_buffer.buffer[j] = (c & 0xFF) as u8;
|
||||
}
|
||||
|
||||
let done = homescreen_get_fg_text(y, text_info, text_buffer, t_buffer);
|
||||
homescreen_get_fg_icon(y, text_info, icon_data, t_buffer);
|
||||
let done = homescreen_get_fg_text(y, text_info, text_buffer, fg_buffer);
|
||||
homescreen_get_fg_icon(y, text_info, icon_data, fg_buffer);
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
dma2d_setup_4bpp_over_16bpp(text_info.text_color.into());
|
||||
dma2d_start_blend(&t_buffer.buffer, &img_buffer.buffer, WIDTH);
|
||||
unsafe {
|
||||
dma2d_start_blend(&fg_buffer.buffer, &img_buffer.buffer, WIDTH);
|
||||
}
|
||||
|
||||
done
|
||||
}
|
||||
@ -427,7 +421,7 @@ fn update_accs_sub(data: &[u16], idx: usize, acc_r: &mut u16, acc_g: &mut u16, a
|
||||
}
|
||||
|
||||
struct BlurringContext {
|
||||
pub lines: &'static mut [[[u16; 240usize]; 3usize]],
|
||||
mem: BufferBlurring,
|
||||
pub totals: [[u16; HOMESCREEN_IMAGE_WIDTH as usize]; COLORS],
|
||||
line_num: i16,
|
||||
add_idx: usize,
|
||||
@ -436,9 +430,8 @@ struct BlurringContext {
|
||||
|
||||
impl BlurringContext {
|
||||
pub fn new() -> Self {
|
||||
let mem = unsafe { get_blurring_buffer(0, true) };
|
||||
Self {
|
||||
lines: &mut mem.buffer[0..DECOMP_LINES],
|
||||
mem: BufferBlurring::get_cleared(),
|
||||
totals: [[0; HOMESCREEN_IMAGE_WIDTH as usize]; COLORS],
|
||||
line_num: 0,
|
||||
add_idx: 0,
|
||||
@ -447,8 +440,9 @@ impl BlurringContext {
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
let lines = &mut self.mem.buffer[0..DECOMP_LINES];
|
||||
for (i, total) in self.totals.iter_mut().enumerate() {
|
||||
for line in self.lines.iter_mut() {
|
||||
for line in lines.iter_mut() {
|
||||
line[i].fill(0);
|
||||
}
|
||||
total.fill(0);
|
||||
@ -457,6 +451,7 @@ impl BlurringContext {
|
||||
|
||||
// computes color averages for one line of image data
|
||||
fn compute_line_avgs(&mut self, buffer: &mut BufferJpeg, mcu_height: i16) {
|
||||
let lines = &mut self.mem.buffer[0..DECOMP_LINES];
|
||||
let mut acc_r = 0;
|
||||
let mut acc_g = 0;
|
||||
let mut acc_b = 0;
|
||||
@ -468,9 +463,9 @@ impl BlurringContext {
|
||||
}
|
||||
|
||||
for i in 0..HOMESCREEN_IMAGE_WIDTH {
|
||||
self.lines[self.add_idx][RED_IDX][i as usize] = acc_r;
|
||||
self.lines[self.add_idx][GREEN_IDX][i as usize] = acc_g;
|
||||
self.lines[self.add_idx][BLUE_IDX][i as usize] = acc_b;
|
||||
lines[self.add_idx][RED_IDX][i as usize] = acc_r;
|
||||
lines[self.add_idx][GREEN_IDX][i as usize] = acc_g;
|
||||
lines[self.add_idx][BLUE_IDX][i as usize] = acc_b;
|
||||
|
||||
// clamping handles left and right edges
|
||||
let ic = (i - BLUR_RADIUS).clamp(0, HOMESCREEN_IMAGE_WIDTH - 1) as usize;
|
||||
@ -484,22 +479,24 @@ impl BlurringContext {
|
||||
|
||||
// adds one line of averages to sliding total averages
|
||||
fn vertical_avg_add(&mut self) {
|
||||
let lines = &mut self.mem.buffer[0..DECOMP_LINES];
|
||||
for i in 0..HOMESCREEN_IMAGE_WIDTH as usize {
|
||||
self.totals[RED_IDX][i] += self.lines[self.add_idx][RED_IDX][i];
|
||||
self.totals[GREEN_IDX][i] += self.lines[self.add_idx][GREEN_IDX][i];
|
||||
self.totals[BLUE_IDX][i] += self.lines[self.add_idx][BLUE_IDX][i];
|
||||
self.totals[RED_IDX][i] += lines[self.add_idx][RED_IDX][i];
|
||||
self.totals[GREEN_IDX][i] += lines[self.add_idx][GREEN_IDX][i];
|
||||
self.totals[BLUE_IDX][i] += lines[self.add_idx][BLUE_IDX][i];
|
||||
}
|
||||
}
|
||||
|
||||
// adds one line and removes one line of averages to/from sliding total averages
|
||||
fn vertical_avg(&mut self) {
|
||||
let lines = &mut self.mem.buffer[0..DECOMP_LINES];
|
||||
for i in 0..HOMESCREEN_IMAGE_WIDTH as usize {
|
||||
self.totals[RED_IDX][i] +=
|
||||
self.lines[self.add_idx][RED_IDX][i] - self.lines[self.rem_idx][RED_IDX][i];
|
||||
lines[self.add_idx][RED_IDX][i] - lines[self.rem_idx][RED_IDX][i];
|
||||
self.totals[GREEN_IDX][i] +=
|
||||
self.lines[self.add_idx][GREEN_IDX][i] - self.lines[self.rem_idx][GREEN_IDX][i];
|
||||
lines[self.add_idx][GREEN_IDX][i] - lines[self.rem_idx][GREEN_IDX][i];
|
||||
self.totals[BLUE_IDX][i] +=
|
||||
self.lines[self.add_idx][BLUE_IDX][i] - self.lines[self.rem_idx][BLUE_IDX][i];
|
||||
lines[self.add_idx][BLUE_IDX][i] - lines[self.rem_idx][BLUE_IDX][i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,11 +529,15 @@ fn get_data(buffer: &mut BufferJpeg, line_num: i16, mcu_height: i16) -> &mut [u1
|
||||
pub fn homescreen_blurred(data: &mut dyn HomescreenDecompressor, texts: &[HomescreenText]) {
|
||||
let mut icon_data = [0_u8; (HOMESCREEN_MAX_ICON_SIZE * HOMESCREEN_MAX_ICON_SIZE / 2) as usize];
|
||||
|
||||
let text_buffer = unsafe { get_text_buffer(0, true) };
|
||||
let mut text_buffer = BufferText::get_cleared();
|
||||
let mut fg_buffer_0 = BufferLine4bpp::get_cleared();
|
||||
let mut img_buffer_0 = BufferLine16bpp::get_cleared();
|
||||
let mut fg_buffer_1 = BufferLine4bpp::get_cleared();
|
||||
let mut img_buffer_1 = BufferLine16bpp::get_cleared();
|
||||
|
||||
let mut next_text_idx = 1;
|
||||
let mut text_info =
|
||||
homescreen_position_text(unwrap!(texts.get(0)), text_buffer, &mut icon_data);
|
||||
homescreen_position_text(unwrap!(texts.get(0)), &mut text_buffer, &mut icon_data);
|
||||
|
||||
let mcu_height = data.get_height();
|
||||
data.decompress();
|
||||
@ -571,11 +572,36 @@ pub fn homescreen_blurred(data: &mut dyn HomescreenDecompressor, texts: &[Homesc
|
||||
blurring.compute_line_avgs(data.get_data(), mcu_height);
|
||||
}
|
||||
|
||||
let done = homescreen_line_blurred(&icon_data, text_buffer, text_info, &blurring, y);
|
||||
let done = if y % 2 == 0 {
|
||||
homescreen_line_blurred(
|
||||
&icon_data,
|
||||
&mut text_buffer,
|
||||
&mut fg_buffer_0,
|
||||
&mut img_buffer_0,
|
||||
text_info,
|
||||
&blurring,
|
||||
y,
|
||||
)
|
||||
} else {
|
||||
homescreen_line_blurred(
|
||||
&icon_data,
|
||||
&mut text_buffer,
|
||||
&mut fg_buffer_1,
|
||||
&mut img_buffer_1,
|
||||
text_info,
|
||||
&blurring,
|
||||
y,
|
||||
)
|
||||
};
|
||||
|
||||
if done {
|
||||
(text_info, next_text_idx) =
|
||||
homescreen_next_text(texts, text_buffer, &mut icon_data, text_info, next_text_idx);
|
||||
(text_info, next_text_idx) = homescreen_next_text(
|
||||
texts,
|
||||
&mut text_buffer,
|
||||
&mut icon_data,
|
||||
text_info,
|
||||
next_text_idx,
|
||||
);
|
||||
}
|
||||
|
||||
blurring.vertical_avg();
|
||||
@ -613,7 +639,11 @@ pub fn homescreen(
|
||||
) {
|
||||
let mut icon_data = [0_u8; (HOMESCREEN_MAX_ICON_SIZE * HOMESCREEN_MAX_ICON_SIZE / 2) as usize];
|
||||
|
||||
let text_buffer = unsafe { get_text_buffer(0, true) };
|
||||
let mut text_buffer = BufferText::get_cleared();
|
||||
let mut fg_buffer_0 = BufferLine4bpp::get_cleared();
|
||||
let mut img_buffer_0 = BufferLine16bpp::get_cleared();
|
||||
let mut fg_buffer_1 = BufferLine4bpp::get_cleared();
|
||||
let mut img_buffer_1 = BufferLine16bpp::get_cleared();
|
||||
|
||||
let mut next_text_idx = 0;
|
||||
let mut text_info = if let Some(notification) = notification {
|
||||
@ -623,7 +653,7 @@ pub fn homescreen(
|
||||
WIDTH - NOTIFICATION_BORDER * 2,
|
||||
NOTIFICATION_HEIGHT,
|
||||
2,
|
||||
text_buffer,
|
||||
&mut text_buffer,
|
||||
);
|
||||
let area = Rect::new(
|
||||
Point::new(0, NOTIFICATION_BORDER),
|
||||
@ -637,7 +667,7 @@ pub fn homescreen(
|
||||
}
|
||||
} else {
|
||||
next_text_idx += 1;
|
||||
homescreen_position_text(unwrap!(texts.get(0)), text_buffer, &mut icon_data)
|
||||
homescreen_position_text(unwrap!(texts.get(0)), &mut text_buffer, &mut icon_data)
|
||||
};
|
||||
|
||||
set_window(screen());
|
||||
@ -649,14 +679,29 @@ pub fn homescreen(
|
||||
data.decompress();
|
||||
}
|
||||
|
||||
let done = homescreen_line(
|
||||
&icon_data,
|
||||
text_buffer,
|
||||
text_info,
|
||||
data.get_data(),
|
||||
mcu_height,
|
||||
y,
|
||||
);
|
||||
let done = if y % 2 == 0 {
|
||||
homescreen_line(
|
||||
&icon_data,
|
||||
&mut text_buffer,
|
||||
text_info,
|
||||
data.get_data(),
|
||||
&mut fg_buffer_0,
|
||||
&mut img_buffer_0,
|
||||
mcu_height,
|
||||
y,
|
||||
)
|
||||
} else {
|
||||
homescreen_line(
|
||||
&icon_data,
|
||||
&mut text_buffer,
|
||||
text_info,
|
||||
data.get_data(),
|
||||
&mut fg_buffer_1,
|
||||
&mut img_buffer_1,
|
||||
mcu_height,
|
||||
y,
|
||||
)
|
||||
};
|
||||
|
||||
if done {
|
||||
if notification.is_some() && next_text_idx == 0 {
|
||||
@ -670,6 +715,9 @@ pub fn homescreen(
|
||||
|
||||
dma2d_wait_for_transfer();
|
||||
|
||||
drop(fg_buffer_0);
|
||||
drop(fg_buffer_1);
|
||||
|
||||
icon_text_center(
|
||||
text_info.text_area.center(),
|
||||
notification.icon,
|
||||
@ -678,6 +726,10 @@ pub fn homescreen(
|
||||
style,
|
||||
Offset::new(1, -2),
|
||||
);
|
||||
|
||||
fg_buffer_0 = BufferLine4bpp::get_cleared();
|
||||
fg_buffer_1 = BufferLine4bpp::get_cleared();
|
||||
|
||||
set_window(
|
||||
screen()
|
||||
.split_top(NOTIFICATION_HEIGHT + NOTIFICATION_BORDER)
|
||||
@ -690,8 +742,13 @@ pub fn homescreen(
|
||||
return;
|
||||
}
|
||||
|
||||
(text_info, next_text_idx) =
|
||||
homescreen_next_text(texts, text_buffer, &mut icon_data, text_info, next_text_idx);
|
||||
(text_info, next_text_idx) = homescreen_next_text(
|
||||
texts,
|
||||
&mut text_buffer,
|
||||
&mut icon_data,
|
||||
text_info,
|
||||
next_text_idx,
|
||||
);
|
||||
}
|
||||
}
|
||||
dma2d_wait_for_transfer();
|
||||
|
Loading…
Reference in New Issue
Block a user