Skip to content

Commit a144b75

Browse files
committed
Merge branch 'master' into vello_cpu
2 parents 3c2deb0 + dffc676 commit a144b75

8 files changed

Lines changed: 217 additions & 50 deletions

File tree

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,18 @@ image.optional = true
120120
[dev-dependencies]
121121
criterion = "0.5"
122122
iced_wgpu.workspace = true
123+
iced_renderer.workspace = true
123124

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

130+
[[bench]]
131+
name = "cpu"
132+
harness = false
133+
required-features = ["canvas"]
134+
129135
[profile.release-opt]
130136
inherits = "release"
131137
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>(

examples/loupe/src/main.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ impl Loupe {
4747

4848
mod loupe {
4949
use iced::advanced::Renderer as _;
50+
use iced::advanced::Shell;
5051
use iced::advanced::layout::{self, Layout};
5152
use iced::advanced::renderer;
5253
use iced::advanced::widget::{self, Widget};
5354
use iced::mouse;
54-
use iced::{Color, Element, Length, Rectangle, Renderer, Size, Theme, Transformation};
55+
use iced::{Color, Element, Event, Length, Rectangle, Renderer, Size, Theme, Transformation};
5556

5657
pub fn loupe<'a, Message>(
5758
zoom: f32,
@@ -101,6 +102,21 @@ mod loupe {
101102
self.content.as_widget_mut().layout(tree, renderer, limits)
102103
}
103104

105+
fn update(
106+
&mut self,
107+
_tree: &mut widget::Tree,
108+
_event: &Event,
109+
layout: Layout<'_>,
110+
cursor: mouse::Cursor,
111+
_renderer: &Renderer,
112+
shell: &mut Shell<'_, Message>,
113+
_viewport: &Rectangle,
114+
) {
115+
if cursor.is_over(layout.bounds().expand(10)) {
116+
shell.request_redraw();
117+
}
118+
}
119+
104120
fn draw(
105121
&self,
106122
tree: &widget::Tree,

graphics/src/layer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,14 @@ impl<T: Layer> Stack<T> {
156156

157157
// We scan downwards for a contiguous block of mergeable layer candidates
158158
while current > 0 {
159-
let candidate = &self.layers[current - 1];
159+
current -= 1;
160+
161+
let candidate = &self.layers[current];
160162
let start = candidate.start();
161163
let end = candidate.end();
162164

163165
// We skip empty layers
164166
if end == 0 {
165-
current -= 1;
166167
continue;
167168
}
168169

@@ -176,7 +177,6 @@ impl<T: Layer> Stack<T> {
176177
target = candidate;
177178
target_start = start;
178179
target_index = current;
179-
current -= 1;
180180
}
181181

182182
// We merge all the layers scanned into the target

graphics/src/text.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ pub fn align(
260260

261261
needs_relayout = true;
262262
} else if let Some(line) = buffer.lines.first_mut() {
263-
needs_relayout = line.set_align(None);
263+
needs_relayout |= line.set_align(None);
264264
}
265265
}
266266

widget/src/pane_grid.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -719,13 +719,9 @@ where
719719
let node = self.internal.layout();
720720
let resize_leeway = self.on_resize.as_ref().map(|(leeway, _)| *leeway);
721721

722-
let picked_pane = action.picked_pane().filter(|(_, origin)| {
723-
cursor
724-
.position()
725-
.map(|position| position.distance(*origin))
726-
.unwrap_or_default()
727-
> DRAG_DEADBAND_DISTANCE
728-
});
722+
let picked_pane = action.picked_pane();
723+
let dragged_pane = picked_pane
724+
.filter(|(_, origin)| is_dragging(*origin, cursor.position().unwrap_or_default()));
729725

730726
let picked_split = action
731727
.picked_split()
@@ -800,11 +796,10 @@ where
800796
viewport,
801797
);
802798

803-
if picked_pane.is_some()
799+
if let Some(cursor_position) = cursor.position()
800+
&& dragged_pane.is_some()
804801
&& pane_in_edge.is_none()
805-
&& let Some(region) = cursor
806-
.position()
807-
.and_then(|cursor_position| layout_region(pane_layout, cursor_position))
802+
&& let Some(region) = layout_region(pane_layout, cursor_position)
808803
{
809804
let bounds = layout_region_bounds(pane_layout, region);
810805

@@ -832,7 +827,9 @@ where
832827
}
833828
}
834829

835-
if let Some(edge) = pane_in_edge {
830+
if dragged_pane.is_some()
831+
&& let Some(edge) = pane_in_edge
832+
{
836833
let bounds = edge_bounds(layout, edge);
837834

838835
renderer.fill_quad(
@@ -845,7 +842,7 @@ where
845842
);
846843
}
847844

848-
if picked_pane.is_none()
845+
if dragged_pane.is_none()
849846
&& let Some((axis, split_region, is_picked)) = picked_split
850847
{
851848
let highlight = if is_picked {
@@ -955,8 +952,13 @@ where
955952
_layout: Layout<'_>,
956953
cursor: mouse::Cursor,
957954
) {
958-
let translation =
959-
cursor.position().unwrap_or_default() - Point::new(self.origin.x, self.origin.y);
955+
let cursor_position = cursor.position().unwrap_or_default();
956+
957+
let translation = if is_dragging(self.origin, cursor_position) {
958+
cursor_position - self.origin
959+
} else {
960+
Vector::ZERO
961+
};
960962

961963
renderer.with_translation(translation, |renderer| {
962964
self.content.draw(
@@ -972,6 +974,10 @@ where
972974
}
973975
}
974976

977+
fn is_dragging(origin: Point, cursor: Point) -> bool {
978+
cursor.distance(origin) > DRAG_DEADBAND_DISTANCE
979+
}
980+
975981
impl<'a, Message, Theme, Renderer> From<PaneGrid<'a, Message, Theme, Renderer>>
976982
for Element<'a, Message, Theme, Renderer>
977983
where

widget/src/pane_grid/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ pub enum Action {
424424
}
425425

426426
impl Action {
427-
/// Returns the current [`Pane`] that is being dragged, if any.
427+
/// Returns the current [`Pane`] that is being picked, if any.
428428
pub fn picked_pane(&self) -> Option<(Pane, Point)> {
429429
match *self {
430430
Action::Dragging { pane, origin, .. } => Some((pane, origin)),

0 commit comments

Comments
 (0)