feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
@@ -0,0 +1,34 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{
|
||||
pixelcolor::{Gray8, Rgb555, Rgb565, Rgb888},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
fn impl_bench<CFrom, CTo>(c: &mut Criterion, name: &str)
|
||||
where
|
||||
CFrom: PixelColor + Default + Into<CTo>,
|
||||
CTo: PixelColor + Default,
|
||||
{
|
||||
c.bench_function(name, |b| {
|
||||
let input = &[CFrom::default(); 320 * 240];
|
||||
let mut output = [CTo::default(); 320 * 240];
|
||||
|
||||
b.iter(|| {
|
||||
for (i, o) in black_box(input).iter().copied().zip(output.iter_mut()) {
|
||||
*o = i.into();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn color_conversions(c: &mut Criterion) {
|
||||
impl_bench::<Rgb555, Rgb565>(c, "Rgb555 to Rgb565");
|
||||
impl_bench::<Rgb565, Rgb555>(c, "Rgb565 to Rgb555");
|
||||
impl_bench::<Rgb565, Rgb888>(c, "Rgb565 to Rgb888");
|
||||
impl_bench::<Rgb888, Rgb565>(c, "Rgb888 to Rgb565");
|
||||
impl_bench::<Gray8, Rgb888>(c, "Gray8 to Rgb888");
|
||||
impl_bench::<Rgb888, Gray8>(c, "Rgb888 to Gray8");
|
||||
}
|
||||
|
||||
criterion_group!(benches, color_conversions);
|
||||
criterion_main!(benches);
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
use embedded_graphics::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
const SIZE: usize = 256;
|
||||
|
||||
pub struct Framebuffer<C> {
|
||||
pixels: [[C; SIZE]; SIZE],
|
||||
}
|
||||
|
||||
impl<C> Framebuffer<C>
|
||||
where
|
||||
C: PixelColor + Default,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pixels: [[C::default(); 256]; 256],
|
||||
}
|
||||
}
|
||||
|
||||
fn set_pixel(&mut self, position: Point, color: C) {
|
||||
if let (Ok(x), Ok(y)) = (usize::try_from(position.x), usize::try_from(position.y)) {
|
||||
self.pixels
|
||||
.get_mut(y)
|
||||
.and_then(|row| row.get_mut(x))
|
||||
.map(|pixel| *pixel = color);
|
||||
} else {
|
||||
panic!(
|
||||
"tried to set pixel outside the framebuffer at {:?}",
|
||||
position
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> DrawTarget for Framebuffer<C>
|
||||
where
|
||||
C: PixelColor + Default,
|
||||
{
|
||||
type Color = C;
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||
{
|
||||
for Pixel(position, color) in pixels {
|
||||
self.set_pixel(position, color);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> OriginDimensions for Framebuffer<C> {
|
||||
fn size(&self) -> Size {
|
||||
Size::new_equal(SIZE as u32)
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{prelude::*, primitives::*};
|
||||
|
||||
fn triangle_contains_inside(c: &mut Criterion) {
|
||||
c.bench_function("triangle contains point (inside)", |b| {
|
||||
let object = Triangle::new(Point::new(5, 10), Point::new(15, 20), Point::new(5, 20));
|
||||
let midpoint = object.bounding_box().center();
|
||||
|
||||
b.iter(|| object.contains(midpoint))
|
||||
});
|
||||
}
|
||||
|
||||
// Point outside triangle but still within bounding box. If point is outside bounding box, this
|
||||
// benchmark doesn't exercise the expensive point-in-triangle code.
|
||||
fn triangle_contains_outside(c: &mut Criterion) {
|
||||
c.bench_function("triangle contains point (outside)", |b| {
|
||||
let object = Triangle::new(Point::new(5, 10), Point::new(55, 20), Point::new(30, 40));
|
||||
|
||||
b.iter(|| object.contains(Point::new(50, 13)))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
contains,
|
||||
triangle_contains_inside,
|
||||
triangle_contains_outside
|
||||
);
|
||||
criterion_main!(contains);
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{
|
||||
geometry::Point,
|
||||
mono_font::{
|
||||
ascii::{FONT_10X20, FONT_6X9},
|
||||
MonoTextStyle, MonoTextStyleBuilder,
|
||||
},
|
||||
pixelcolor::Gray8,
|
||||
prelude::*,
|
||||
text::Text,
|
||||
};
|
||||
|
||||
mod common;
|
||||
|
||||
use common::Framebuffer;
|
||||
|
||||
fn one_line<S>(style: S) -> Text<'static, S> {
|
||||
Text::new("Hello world!", Point::new_equal(20), style)
|
||||
}
|
||||
|
||||
fn three_lines<S>(style: S) -> Text<'static, S> {
|
||||
Text::new("line 1\nl2\nThis is line 3", Point::new_equal(20), style)
|
||||
}
|
||||
|
||||
fn font_6x9(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("font 6x9");
|
||||
|
||||
let style = MonoTextStyle::new(&FONT_6X9, Gray8::WHITE);
|
||||
let style_with_bg = MonoTextStyleBuilder::new()
|
||||
.font(&FONT_6X9)
|
||||
.text_color(Gray8::WHITE)
|
||||
.background_color(Gray8::BLACK)
|
||||
.build();
|
||||
|
||||
group.bench_function("one line", |b| {
|
||||
let object = one_line(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("one line with background", |b| {
|
||||
let object = one_line(style_with_bg);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("three lines", |b| {
|
||||
let object = three_lines(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("three lines with background)", |b| {
|
||||
let object = three_lines(style_with_bg);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn font_10x20(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("font 10x20");
|
||||
|
||||
let style = MonoTextStyle::new(&FONT_10X20, Gray8::WHITE);
|
||||
let style_with_bg = MonoTextStyleBuilder::new()
|
||||
.font(&FONT_10X20)
|
||||
.text_color(Gray8::WHITE)
|
||||
.background_color(Gray8::BLACK)
|
||||
.build();
|
||||
|
||||
group.bench_function("one line", |b| {
|
||||
let object = one_line(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("one line with background", |b| {
|
||||
let object = one_line(style_with_bg);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("three lines", |b| {
|
||||
let object = three_lines(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("three lines with background)", |b| {
|
||||
let object = three_lines(style_with_bg);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(fonts, font_6x9, font_10x20);
|
||||
criterion_main!(fonts);
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{
|
||||
framebuffer::{buffer_size, Framebuffer},
|
||||
geometry::Point,
|
||||
image::GetPixel,
|
||||
pixelcolor::{raw::LittleEndian, BinaryColor, Rgb565},
|
||||
prelude::{DrawTarget, Size, WebColors},
|
||||
primitives::{Primitive, PrimitiveStyle, Rectangle},
|
||||
};
|
||||
|
||||
fn framebuffer_set_1bpp(c: &mut Criterion) {
|
||||
c.bench_function("framebuffer set pixel 1bpp", |b| {
|
||||
let mut fb = Framebuffer::<
|
||||
BinaryColor,
|
||||
_,
|
||||
LittleEndian,
|
||||
320,
|
||||
240,
|
||||
{ buffer_size::<BinaryColor>(320, 240) },
|
||||
>::new();
|
||||
|
||||
b.iter(|| {
|
||||
fb.set_pixel(Point::new(1, 1), BinaryColor::On);
|
||||
fb.set_pixel(Point::new(300, 200), BinaryColor::On);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn framebuffer_get_1bpp(c: &mut Criterion) {
|
||||
c.bench_function("framebuffer get pixel 1bpp", |b| {
|
||||
let fb = Framebuffer::<
|
||||
BinaryColor,
|
||||
_,
|
||||
LittleEndian,
|
||||
320,
|
||||
240,
|
||||
{ buffer_size::<BinaryColor>(320, 240) },
|
||||
>::new();
|
||||
|
||||
b.iter(|| {
|
||||
fb.pixel(Point::new(1, 1));
|
||||
fb.pixel(Point::new(300, 200));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn framebuffer_1bpp_draw_iter(c: &mut Criterion) {
|
||||
c.bench_function("framebuffer 1bpp draw iter", |b| {
|
||||
let mut fb = Framebuffer::<
|
||||
BinaryColor,
|
||||
_,
|
||||
LittleEndian,
|
||||
320,
|
||||
240,
|
||||
{ buffer_size::<BinaryColor>(320, 240) },
|
||||
>::new();
|
||||
|
||||
b.iter(|| {
|
||||
let rect = Rectangle::new(Point::new(20, 30), Size::new(40, 50))
|
||||
.into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
|
||||
.pixels();
|
||||
|
||||
fb.draw_iter(rect).unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn framebuffer_set_rgb565(c: &mut Criterion) {
|
||||
c.bench_function("framebuffer set pixel rgb565", |b| {
|
||||
let mut fb = Framebuffer::<
|
||||
Rgb565,
|
||||
_,
|
||||
LittleEndian,
|
||||
320,
|
||||
240,
|
||||
{ buffer_size::<Rgb565>(320, 240) },
|
||||
>::new();
|
||||
|
||||
b.iter(|| {
|
||||
fb.set_pixel(Point::new(1, 1), Rgb565::CSS_DARK_SALMON);
|
||||
fb.set_pixel(Point::new(300, 200), Rgb565::CSS_TEAL);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn framebuffer_get_rgb565(c: &mut Criterion) {
|
||||
c.bench_function("framebuffer get pixel rgb565", |b| {
|
||||
let fb = Framebuffer::<
|
||||
Rgb565,
|
||||
_,
|
||||
LittleEndian,
|
||||
320,
|
||||
240,
|
||||
{ buffer_size::<Rgb565>(320, 240) },
|
||||
>::new();
|
||||
|
||||
b.iter(|| {
|
||||
fb.pixel(Point::new(1, 1));
|
||||
fb.pixel(Point::new(300, 200));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
framebuffer,
|
||||
framebuffer_set_1bpp,
|
||||
framebuffer_get_1bpp,
|
||||
framebuffer_set_rgb565,
|
||||
framebuffer_get_rgb565,
|
||||
framebuffer_1bpp_draw_iter
|
||||
);
|
||||
criterion_main!(framebuffer);
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{
|
||||
image::{Image, ImageRaw},
|
||||
pixelcolor::BinaryColor,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
mod common;
|
||||
|
||||
use common::Framebuffer;
|
||||
|
||||
fn image_1bpp(c: &mut Criterion) {
|
||||
c.bench_function("image 4x4px", |b| {
|
||||
let bytes = include_bytes!("../assets/patch_1bpp.raw");
|
||||
|
||||
let image: ImageRaw<BinaryColor> = ImageRaw::new(bytes, 4);
|
||||
let object = Image::new(&image, Point::zero());
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(images, image_1bpp);
|
||||
criterion_main!(images);
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{geometry::AnchorPoint, pixelcolor::Gray8, prelude::*, primitives::*};
|
||||
|
||||
mod common;
|
||||
|
||||
use common::Framebuffer;
|
||||
|
||||
const BOUNDING_BOX: Rectangle = Rectangle::new(Point::new_equal(32), Size::new_equal(192));
|
||||
|
||||
fn rectangle(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "rectangle", || BOUNDING_BOX);
|
||||
}
|
||||
|
||||
fn rounded_rectangle(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "rounded rectangle", || {
|
||||
RoundedRectangle::new(BOUNDING_BOX, CornerRadii::new(Size::new(10, 12)))
|
||||
});
|
||||
}
|
||||
|
||||
fn rounded_rectangle_corners(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "rounded rectangle corners", || {
|
||||
RoundedRectangle::new(
|
||||
BOUNDING_BOX,
|
||||
CornerRadii {
|
||||
top_left: Size::new(10, 12),
|
||||
top_right: Size::new(14, 16),
|
||||
bottom_right: Size::new(18, 20),
|
||||
bottom_left: Size::new(22, 24),
|
||||
},
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn triangle(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "triangle", || {
|
||||
Triangle::new(
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::BottomLeft),
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::TopCenter),
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::BottomRight),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn circle(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "circle", || {
|
||||
Circle::new(BOUNDING_BOX.top_left, BOUNDING_BOX.size.width)
|
||||
});
|
||||
}
|
||||
|
||||
fn ellipse(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "ellipse", || {
|
||||
Ellipse::with_center(BOUNDING_BOX.center(), BOUNDING_BOX.size - Size::new(0, 20))
|
||||
});
|
||||
}
|
||||
|
||||
fn sector_150(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "sector 150°", || {
|
||||
Sector::with_center(
|
||||
BOUNDING_BOX.center(),
|
||||
BOUNDING_BOX.size.width,
|
||||
-30.0.deg(),
|
||||
150.0.deg(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn sector_360(c: &mut Criterion) {
|
||||
closed_shape_benches(c, "sector 360°", || {
|
||||
Sector::with_center(
|
||||
BOUNDING_BOX.center(),
|
||||
BOUNDING_BOX.size.width,
|
||||
-30.0.deg(),
|
||||
150.0.deg(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn line(c: &mut Criterion) {
|
||||
open_shape_benches(c, "line", || {
|
||||
Line::new(
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::TopLeft),
|
||||
// move point up a bit, because non 45° lines might be slower
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::BottomRight) - Point::new(0, 20),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn polyline(c: &mut Criterion) {
|
||||
let points = [
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::BottomLeft),
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::TopCenter) - Point::new(20, 0),
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::BottomCenter),
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::TopRight),
|
||||
BOUNDING_BOX.anchor_point(AnchorPoint::BottomRight),
|
||||
];
|
||||
|
||||
open_shape_benches(c, "polyline", || Polyline::new(&points));
|
||||
}
|
||||
|
||||
fn arc_150(c: &mut Criterion) {
|
||||
open_shape_benches(c, "arc 150°", || {
|
||||
Arc::with_center(
|
||||
BOUNDING_BOX.center(),
|
||||
BOUNDING_BOX.size.width,
|
||||
-30.0.deg(),
|
||||
150.0.deg(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn arc_360(c: &mut Criterion) {
|
||||
open_shape_benches(c, "arc 360°", || {
|
||||
Arc::with_center(
|
||||
BOUNDING_BOX.center(),
|
||||
BOUNDING_BOX.size.width,
|
||||
0.0.deg(),
|
||||
360.0.deg(),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
primitives,
|
||||
rectangle,
|
||||
rounded_rectangle,
|
||||
rounded_rectangle_corners,
|
||||
triangle,
|
||||
circle,
|
||||
ellipse,
|
||||
line,
|
||||
polyline,
|
||||
sector_150,
|
||||
sector_360,
|
||||
arc_150,
|
||||
arc_360,
|
||||
);
|
||||
criterion_main!(primitives);
|
||||
|
||||
fn closed_shape_benches<P>(c: &mut Criterion, name: &str, build: impl Fn() -> P)
|
||||
where
|
||||
P: Primitive,
|
||||
Styled<P, PrimitiveStyle<Gray8>>: Drawable<Color = Gray8>,
|
||||
{
|
||||
let mut group = c.benchmark_group(name);
|
||||
|
||||
group.bench_function("fill", |b| {
|
||||
let style = PrimitiveStyle::with_fill(Gray8::WHITE);
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("stroke 1px", |b| {
|
||||
let style = PrimitiveStyleBuilder::new()
|
||||
.stroke_color(Gray8::BLACK)
|
||||
.stroke_width(1)
|
||||
.stroke_alignment(StrokeAlignment::Inside)
|
||||
.build();
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("stroke 10px", |b| {
|
||||
let style = PrimitiveStyleBuilder::new()
|
||||
.stroke_color(Gray8::BLACK)
|
||||
.stroke_width(10)
|
||||
.stroke_alignment(StrokeAlignment::Inside)
|
||||
.build();
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("stroke 1px and fill", |b| {
|
||||
let style = PrimitiveStyleBuilder::new()
|
||||
.fill_color(Gray8::WHITE)
|
||||
.stroke_color(Gray8::BLACK)
|
||||
.stroke_width(1)
|
||||
.stroke_alignment(StrokeAlignment::Inside)
|
||||
.build();
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("stroke 10px and fill", |b| {
|
||||
let style = PrimitiveStyleBuilder::new()
|
||||
.fill_color(Gray8::WHITE)
|
||||
.stroke_color(Gray8::BLACK)
|
||||
.stroke_width(10)
|
||||
.stroke_alignment(StrokeAlignment::Inside)
|
||||
.build();
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.finish()
|
||||
}
|
||||
|
||||
fn open_shape_benches<P>(c: &mut Criterion, name: &str, build: impl Fn() -> P)
|
||||
where
|
||||
P: Primitive,
|
||||
Styled<P, PrimitiveStyle<Gray8>>: Drawable<Color = Gray8>,
|
||||
{
|
||||
let mut group = c.benchmark_group(name);
|
||||
|
||||
group.bench_function("stroke 1px", |b| {
|
||||
let style = PrimitiveStyle::with_stroke(Gray8::WHITE, 1);
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("stroke 10px", |b| {
|
||||
let style = PrimitiveStyle::with_stroke(Gray8::WHITE, 10);
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.bench_function("stroke 50px", |b| {
|
||||
let style = PrimitiveStyle::with_stroke(Gray8::WHITE, 50);
|
||||
let object = build().into_styled(style);
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
|
||||
group.finish()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{geometry::AngleUnit, pixelcolor::Gray8, prelude::*, primitives::*};
|
||||
|
||||
mod common;
|
||||
|
||||
use common::Framebuffer;
|
||||
|
||||
fn arc(c: &mut Criterion) {
|
||||
c.bench_function("arc", |b| {
|
||||
let object = &Arc::new(Point::new(100, 100), 100, -30.0.deg(), 150.0.deg())
|
||||
.into_styled(PrimitiveStyle::with_stroke(Gray8::new(1), 1));
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
}
|
||||
|
||||
fn sector(c: &mut Criterion) {
|
||||
c.bench_function("sector", |b| {
|
||||
let object = &Sector::new(Point::new(100, 100), 100, -30.0.deg(), 150.0.deg())
|
||||
.into_styled(PrimitiveStyle::with_stroke(Gray8::new(1), 1));
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
}
|
||||
|
||||
fn filled_sector(c: &mut Criterion) {
|
||||
c.bench_function("filled_sector", |b| {
|
||||
let object = &Sector::new(Point::new(100, 100), 100, -30.0.deg(), 150.0.deg())
|
||||
.into_styled(PrimitiveStyle::with_fill(Gray8::new(1)));
|
||||
|
||||
let mut framebuffer = Framebuffer::new();
|
||||
b.iter(|| object.draw(&mut framebuffer))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(primitives_fixed_point, arc, sector, filled_sector);
|
||||
criterion_main!(primitives_fixed_point);
|
||||
@@ -0,0 +1,42 @@
|
||||
use criterion::*;
|
||||
use embedded_graphics::{iterator::raw::RawDataSlice, pixelcolor::raw::*};
|
||||
|
||||
const TEST_DATA: &[u8] = include_bytes!("../fonts/src/10x20.bdf");
|
||||
|
||||
macro_rules! impl_bench {
|
||||
($fn:ident, $type:ident) => {
|
||||
fn $fn(c: &mut Criterion) {
|
||||
c.bench_function(stringify!($type), |b| {
|
||||
let slice = RawDataSlice::<$type, LittleEndian>::new(TEST_DATA);
|
||||
|
||||
b.iter(|| slice.into_iter().collect::<Vec<_>>())
|
||||
});
|
||||
|
||||
c.bench_function(concat!(stringify!($type), " step by 20"), |b| {
|
||||
let slice = RawDataSlice::<$type, LittleEndian>::new(TEST_DATA);
|
||||
|
||||
b.iter(|| slice.into_iter().step_by(20).collect::<Vec<_>>())
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_bench!(raw_u1, RawU1);
|
||||
impl_bench!(raw_u2, RawU2);
|
||||
impl_bench!(raw_u4, RawU4);
|
||||
impl_bench!(raw_u8, RawU8);
|
||||
impl_bench!(raw_u16, RawU16);
|
||||
impl_bench!(raw_u24, RawU24);
|
||||
impl_bench!(raw_u32, RawU32);
|
||||
|
||||
criterion_group!(
|
||||
raw_data_iter,
|
||||
raw_u1,
|
||||
raw_u2,
|
||||
raw_u4,
|
||||
raw_u8,
|
||||
raw_u16,
|
||||
raw_u24,
|
||||
raw_u32
|
||||
);
|
||||
criterion_main!(raw_data_iter);
|
||||
Reference in new issue
Block a user