Skip to content

Commit dffc676

Browse files
committed
Add a couple of basic cpu rendering benchmarks
1 parent 6d5eb86 commit dffc676

4 files changed

Lines changed: 176 additions & 30 deletions

File tree

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,18 @@ image.optional = true
118118
[dev-dependencies]
119119
criterion = "0.5"
120120
iced_wgpu.workspace = true
121+
iced_renderer.workspace = true
121122

122123
[[bench]]
123124
name = "wgpu"
124125
harness = false
125126
required-features = ["canvas"]
126127

128+
[[bench]]
129+
name = "cpu"
130+
harness = false
131+
required-features = ["canvas"]
132+
127133
[profile.release-opt]
128134
inherits = "release"
129135
codegen-units = 1

benches/cpu.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#![allow(missing_docs)]
2+
use criterion::{Bencher, Criterion, criterion_group, criterion_main};
3+
4+
use iced::border;
5+
use iced::mouse;
6+
use iced::widget::{canvas, center_y, column, container, row, scrollable, space, text};
7+
use iced::{Center, Color, Element, Fill, Length, Never, Point, Rectangle, Size, Theme};
8+
use iced_renderer::Renderer;
9+
use iced_renderer::core::renderer::{self, Headless as _};
10+
use iced_runtime::UserInterface;
11+
use iced_runtime::user_interface;
12+
13+
use iced_futures::futures::executor;
14+
15+
criterion_main!(benches);
16+
criterion_group!(benches, benchmark);
17+
18+
const VIEWPORT: Size<f32> = Size::new(512.0, 512.0);
19+
const SCALE: f32 = 2.0;
20+
21+
pub fn benchmark(c: &mut Criterion) {
22+
let mut renderer = executor::block_on(Renderer::new(
23+
renderer::Settings::default(),
24+
Some("software"),
25+
))
26+
.expect("software renderer must be available");
27+
28+
let _ = c
29+
.bench_function("cpu — ipsum", |b| {
30+
draw(b, &mut renderer, ipsum());
31+
})
32+
.bench_function("cpu — application", |b| {
33+
draw(b, &mut renderer, application());
34+
});
35+
}
36+
37+
fn draw(bencher: &mut Bencher<'_>, renderer: &mut Renderer, view: Element<'static, Never>) {
38+
let mut ui = UserInterface::build(view, VIEWPORT, user_interface::Cache::new(), renderer);
39+
40+
bencher.iter(|| {
41+
ui.draw(
42+
renderer,
43+
&Theme::Dark,
44+
&renderer::Style::default(),
45+
mouse::Cursor::Unavailable,
46+
);
47+
48+
let _ = renderer.screenshot(
49+
Size::new(
50+
(VIEWPORT.width * SCALE) as u32,
51+
(VIEWPORT.height * SCALE) as u32,
52+
),
53+
SCALE,
54+
Color::WHITE,
55+
);
56+
});
57+
}
58+
59+
fn ipsum() -> Element<'static, Never> {
60+
text(include_str!("ipsum.txt"))
61+
.ellipsis(text::Ellipsis::End)
62+
.into()
63+
}
64+
65+
fn application() -> Element<'static, Never> {
66+
fn square<'a>(size: impl Into<Length> + Copy) -> Element<'a, Never> {
67+
struct Square;
68+
69+
impl canvas::Program<Never> for Square {
70+
type State = ();
71+
72+
fn draw(
73+
&self,
74+
_state: &Self::State,
75+
renderer: &Renderer,
76+
theme: &Theme,
77+
bounds: Rectangle,
78+
_cursor: mouse::Cursor,
79+
) -> Vec<canvas::Geometry> {
80+
let mut frame = canvas::Frame::new(renderer, bounds.size());
81+
82+
let palette = theme.palette();
83+
84+
frame.fill_rectangle(
85+
Point::ORIGIN,
86+
bounds.size(),
87+
palette.background.strong.color,
88+
);
89+
90+
vec![frame.into_geometry()]
91+
}
92+
}
93+
94+
canvas(Square).width(size).height(size).into()
95+
}
96+
97+
let header = container(
98+
row![
99+
square(40),
100+
space::horizontal(),
101+
"Header!",
102+
space::horizontal(),
103+
square(40),
104+
]
105+
.padding(10)
106+
.align_y(Center),
107+
)
108+
.style(|theme| {
109+
let palette = theme.palette();
110+
111+
container::Style::default().border(border::color(palette.background.strong.color).width(1))
112+
});
113+
114+
let sidebar = center_y(
115+
column!["Sidebar!", square(50), square(50)]
116+
.spacing(40)
117+
.padding(10)
118+
.width(200)
119+
.align_x(Center),
120+
)
121+
.style(container::rounded_box);
122+
123+
let content = container(
124+
scrollable(
125+
column![
126+
"Content!",
127+
row((1..10).map(|i| square(if i % 2 == 0 { 80 } else { 160 })))
128+
.spacing(20)
129+
.align_y(Center)
130+
.wrap(),
131+
"The end"
132+
]
133+
.spacing(40)
134+
.align_x(Center)
135+
.width(Fill),
136+
)
137+
.height(Fill),
138+
)
139+
.padding(10);
140+
141+
column![header, row![sidebar, content]].into()
142+
}

benches/wgpu.rs

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use iced_wgpu::wgpu;
1111
criterion_main!(benches);
1212
criterion_group!(benches, wgpu_benchmark);
1313

14-
#[allow(unused_results)]
1514
pub fn wgpu_benchmark(c: &mut Criterion) {
1615
use iced_futures::futures::executor;
1716
use iced_wgpu::wgpu;
@@ -38,35 +37,33 @@ pub fn wgpu_benchmark(c: &mut Criterion) {
3837
}))
3938
.expect("request device");
4039

41-
c.bench_function("wgpu — canvas (light)", |b| {
42-
benchmark(b, &adapter, &device, &queue, |_| scene(10));
43-
});
44-
c.bench_function("wgpu — canvas (heavy)", |b| {
45-
benchmark(b, &adapter, &device, &queue, |_| scene(1_000));
46-
});
47-
48-
c.bench_function("wgpu - layered text (light)", |b| {
49-
benchmark(b, &adapter, &device, &queue, |_| layered_text(10));
50-
});
51-
c.bench_function("wgpu - layered text (heavy)", |b| {
52-
benchmark(b, &adapter, &device, &queue, |_| layered_text(1_000));
53-
});
54-
55-
c.bench_function("wgpu - dynamic text (light)", |b| {
56-
benchmark(b, &adapter, &device, &queue, |i| dynamic_text(1_000, i));
57-
});
58-
c.bench_function("wgpu - dynamic text (heavy)", |b| {
59-
benchmark(b, &adapter, &device, &queue, |i| dynamic_text(100_000, i));
60-
});
61-
62-
c.bench_function("wgpu - advanced shaping (light)", |b| {
63-
benchmark(b, &adapter, &device, &queue, |i| advanced_shaping(1_000, i));
64-
});
65-
c.bench_function("wgpu - advanced shaping (heavy)", |b| {
66-
benchmark(b, &adapter, &device, &queue, |i| {
67-
advanced_shaping(100_000, i)
40+
let _ = c
41+
.bench_function("wgpu — canvas (light)", |b| {
42+
benchmark(b, &adapter, &device, &queue, |_| scene(10));
43+
})
44+
.bench_function("wgpu — canvas (heavy)", |b| {
45+
benchmark(b, &adapter, &device, &queue, |_| scene(1_000));
46+
})
47+
.bench_function("wgpu - layered text (light)", |b| {
48+
benchmark(b, &adapter, &device, &queue, |_| layered_text(10));
49+
})
50+
.bench_function("wgpu - layered text (heavy)", |b| {
51+
benchmark(b, &adapter, &device, &queue, |_| layered_text(1_000));
52+
})
53+
.bench_function("wgpu - dynamic text (light)", |b| {
54+
benchmark(b, &adapter, &device, &queue, |i| dynamic_text(1_000, i));
55+
})
56+
.bench_function("wgpu - dynamic text (heavy)", |b| {
57+
benchmark(b, &adapter, &device, &queue, |i| dynamic_text(100_000, i));
58+
})
59+
.bench_function("wgpu - advanced shaping (light)", |b| {
60+
benchmark(b, &adapter, &device, &queue, |i| advanced_shaping(1_000, i));
61+
})
62+
.bench_function("wgpu - advanced shaping (heavy)", |b| {
63+
benchmark(b, &adapter, &device, &queue, |i| {
64+
advanced_shaping(100_000, i)
65+
});
6866
});
69-
});
7067
}
7168

7269
fn benchmark<'a>(

tiny_skia/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ impl compositor::Default for Renderer {
389389

390390
impl renderer::Headless for Renderer {
391391
async fn new(settings: renderer::Settings, backend: Option<&str>) -> Option<Self> {
392-
if backend.is_some_and(|backend| !["tiny-skia", "tiny_skia"].contains(&backend)) {
392+
if backend.is_some_and(|backend| !["tiny-skia", "tiny_skia", "software"].contains(&backend))
393+
{
393394
return None;
394395
}
395396

0 commit comments

Comments
 (0)