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:
parent
001acc770c
commit
89ae44ebfa
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
83
core/embed/rust/src/ui/shape/utils/imagebuf.rs
Normal file
83
core/embed/rust/src/ui/shape/utils/imagebuf.rs
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user