1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 23:48:12 +00:00

feat(core/rust): introduce ImageBuffer for advanced drawing

[no changelog]
This commit is contained in:
cepetr 2024-05-16 15:59:21 +02:00 committed by cepetr
parent 001acc770c
commit 89ae44ebfa
8 changed files with 140 additions and 7 deletions

View File

@ -5,7 +5,7 @@ use crate::ui::{
use super::super::{ use super::super::{
utils::{circle_points, line_points, sin_f32}, utils::{circle_points, line_points, sin_f32},
BitmapView, Viewport, Bitmap, BitmapFormat, BitmapView, Viewport,
}; };
#[cfg(feature = "ui_blurring")] #[cfg(feature = "ui_blurring")]
@ -71,6 +71,16 @@ pub trait BasicCanvas {
fn draw_bitmap(&mut self, r: Rect, bitmap: BitmapView); fn draw_bitmap(&mut self, r: Rect, bitmap: BitmapView);
} }
pub trait CanvasBuilder<'a> {
/// Returns a format of the underlying bitmap.
fn format() -> BitmapFormat;
/// Creates a new canvas from the specified bitmap.
///
/// The bitmap must be mutable and have the same format as the canvas.
fn from_bitmap(bitmap: Bitmap<'a>) -> Self;
}
pub trait Canvas: BasicCanvas { pub trait Canvas: BasicCanvas {
/// Returns a non-mutable view of the underlying bitmap. /// Returns a non-mutable view of the underlying bitmap.
fn view(&self) -> BitmapView; fn view(&self) -> BitmapView;

View File

@ -4,7 +4,7 @@ mod rgb565;
mod rgba8888; mod rgba8888;
mod viewport; mod viewport;
pub use common::{BasicCanvas, Canvas}; pub use common::{BasicCanvas, Canvas, CanvasBuilder};
pub use mono8::Mono8Canvas; pub use mono8::Mono8Canvas;
pub use rgb565::Rgb565Canvas; pub use rgb565::Rgb565Canvas;
pub use rgba8888::Rgba8888Canvas; pub use rgba8888::Rgba8888Canvas;

View File

@ -8,7 +8,7 @@ use crate::{
use super::{ use super::{
super::{Bitmap, BitmapFormat, BitmapView}, super::{Bitmap, BitmapFormat, BitmapView},
BasicCanvas, Canvas, Viewport, BasicCanvas, Canvas, CanvasBuilder, Viewport,
}; };
#[cfg(feature = "ui_blurring")] #[cfg(feature = "ui_blurring")]
@ -74,6 +74,18 @@ impl<'a> BasicCanvas for Mono8Canvas<'a> {
} }
} }
impl<'a> CanvasBuilder<'a> for Mono8Canvas<'a> {
fn format() -> BitmapFormat {
BitmapFormat::MONO8
}
fn from_bitmap(bitmap: Bitmap<'a>) -> Self {
assert!(bitmap.format() == Self::format());
let viewport = Viewport::from_size(bitmap.size());
Self { bitmap, viewport }
}
}
impl<'a> Canvas for Mono8Canvas<'a> { impl<'a> Canvas for Mono8Canvas<'a> {
fn view(&self) -> BitmapView { fn view(&self) -> BitmapView {
BitmapView::new(&self.bitmap) BitmapView::new(&self.bitmap)

View File

@ -8,7 +8,7 @@ use crate::{
use super::{ use super::{
super::{Bitmap, BitmapFormat, BitmapView}, super::{Bitmap, BitmapFormat, BitmapView},
BasicCanvas, Canvas, Viewport, BasicCanvas, Canvas, CanvasBuilder, Viewport,
}; };
#[cfg(feature = "ui_blurring")] #[cfg(feature = "ui_blurring")]
@ -74,6 +74,18 @@ impl<'a> BasicCanvas for Rgb565Canvas<'a> {
} }
} }
impl<'a> CanvasBuilder<'a> for Rgb565Canvas<'a> {
fn format() -> BitmapFormat {
BitmapFormat::RGB565
}
fn from_bitmap(bitmap: Bitmap<'a>) -> Self {
assert!(bitmap.format() == Self::format());
let viewport = Viewport::from_size(bitmap.size());
Self { bitmap, viewport }
}
}
impl<'a> Canvas for Rgb565Canvas<'a> { impl<'a> Canvas for Rgb565Canvas<'a> {
fn view(&self) -> BitmapView { fn view(&self) -> BitmapView {
BitmapView::new(&self.bitmap) BitmapView::new(&self.bitmap)

View File

@ -8,7 +8,7 @@ use crate::{
use super::{ use super::{
super::{Bitmap, BitmapFormat, BitmapView}, super::{Bitmap, BitmapFormat, BitmapView},
BasicCanvas, Canvas, Viewport, BasicCanvas, Canvas, CanvasBuilder, Viewport,
}; };
#[cfg(feature = "ui_blurring")] #[cfg(feature = "ui_blurring")]
@ -74,6 +74,18 @@ impl<'a> BasicCanvas for Rgba8888Canvas<'a> {
} }
} }
impl<'a> CanvasBuilder<'a> for Rgba8888Canvas<'a> {
fn format() -> BitmapFormat {
BitmapFormat::RGBA8888
}
fn from_bitmap(bitmap: Bitmap<'a>) -> Self {
assert!(bitmap.format() == Self::format());
let viewport = Viewport::from_size(bitmap.size());
Self { bitmap, viewport }
}
}
impl<'a> Canvas for Rgba8888Canvas<'a> { impl<'a> Canvas for Rgba8888Canvas<'a> {
fn view(&self) -> BitmapView { fn view(&self) -> BitmapView {
BitmapView::new(&self.bitmap) BitmapView::new(&self.bitmap)

View File

@ -21,7 +21,9 @@ pub use bitmap::{Bitmap, BitmapFormat, BitmapView};
#[cfg(feature = "ui_blurring")] #[cfg(feature = "ui_blurring")]
pub use blur::Blurring; pub use blur::Blurring;
pub use cache::drawing_cache::DrawingCache; pub use cache::drawing_cache::DrawingCache;
pub use canvas::{BasicCanvas, Canvas, Mono8Canvas, Rgb565Canvas, Rgba8888Canvas, Viewport}; pub use canvas::{
BasicCanvas, Canvas, CanvasBuilder, Mono8Canvas, Rgb565Canvas, Rgba8888Canvas, Viewport,
};
pub use circle::Circle; pub use circle::Circle;
pub use display::render_on_display; pub use display::render_on_display;
#[cfg(feature = "ui_jpeg_decoder")] #[cfg(feature = "ui_jpeg_decoder")]
@ -30,4 +32,4 @@ pub use qrcode::QrImage;
pub use render::{DirectRenderer, ProgressiveRenderer, Renderer}; pub use render::{DirectRenderer, ProgressiveRenderer, Renderer};
pub use text::Text; pub use text::Text;
pub use toif::ToifImage; pub use toif::ToifImage;
pub use utils::PI4; pub use utils::ImageBuffer;

View File

@ -0,0 +1,83 @@
use crate::ui::{
geometry::Offset,
shape::{Bitmap, BitmapView, Canvas, CanvasBuilder},
};
/// Size of image buffer in bytes
const IMAGE_BUFFER_SIZE: usize = 64 * 1024;
#[repr(align(16))]
struct AlignedBuffer {
bytes: [u8; IMAGE_BUFFER_SIZE],
}
/// Raw image buffer used by `ImageBuffer` instances.
static mut IMAGE_BUFFER: AlignedBuffer = AlignedBuffer {
bytes: [0; IMAGE_BUFFER_SIZE],
};
/// Set to `true` if the `IMAGE_BUFFER` is locked
/// (in use by some instance of `ImageBuffer`)
static mut IMAGE_BUFFER_LOCKED: bool = false;
/// A struct representing an image buffer - generic buffer for mutable images.
pub struct ImageBuffer<T: Canvas + CanvasBuilder<'static>> {
canvas: T,
}
impl<T> Drop for ImageBuffer<T>
where
T: Canvas + CanvasBuilder<'static>,
{
fn drop(&mut self) {
// It's safe to modify static variable as whole app
// is single-threaded.
unsafe {
IMAGE_BUFFER_LOCKED = false;
}
}
}
impl<T> ImageBuffer<T>
where
T: Canvas + CanvasBuilder<'static>,
{
/// Creates a new image buffer with the specified format and size.
///
/// Returns `None` if the buffer is already in use or the
/// buffer is not big enough to hold the image.
pub fn new(size: Offset) -> Option<Self> {
// SAFETY:
// It's safe to read/modify mutable static variable as
// whole app is single-threaded.
//
// We can be sure that `IMAGE_BUFFER` is not shared between
// multiple instances of `ImageBuffer` as we have `IMAGE_BUFFER_LOCKED`
// to prevent that.
unsafe {
if IMAGE_BUFFER_LOCKED {
return None;
}
let bitmap =
Bitmap::new_mut(T::format(), None, size, None, &mut IMAGE_BUFFER.bytes[..])?;
IMAGE_BUFFER_LOCKED = true;
Some(Self {
canvas: T::from_bitmap(bitmap),
})
}
}
/// Returns the canvas for the bitmap in the image buffer.
pub fn canvas(&mut self) -> &mut T {
&mut self.canvas
}
/// Returns the immutable view of the bitmap in the image buffer.
pub fn view(&self) -> BitmapView {
self.canvas.view()
}
}

View File

@ -1,9 +1,11 @@
mod blur; mod blur;
mod circle; mod circle;
mod imagebuf;
mod line; mod line;
mod trigo; mod trigo;
pub use blur::{BlurAlgorithm, BlurBuff}; pub use blur::{BlurAlgorithm, BlurBuff};
pub use circle::circle_points; pub use circle::circle_points;
pub use imagebuf::ImageBuffer;
pub use line::line_points; pub use line::line_points;
pub use trigo::sin_f32; pub use trigo::sin_f32;