chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0)
1//! Utility module for helpers around drawing [`WlSurface`](wayland_server::protocol::wl_surface::WlSurface)s
2//! and [`RenderElement`](super::element::RenderElement)s with [`Renderer`](super::Renderer)s.
3
4use crate::utils::{Buffer as BufferCoord, Coordinate, Logical, Physical, Point, Rectangle, Size};
5use std::{collections::VecDeque, fmt, sync::Arc};
6
7#[cfg(feature = "wayland_frontend")]
8mod wayland;
9#[cfg(feature = "wayland_frontend")]
10pub use self::wayland::*;
11
12/// A simple wrapper for counting commits
13///
14/// The purpose of the counter is to keep track
15/// on the number of times something has changed.
16/// It provides an easy way to obtain the distance
17/// between two instances of a [`CommitCounter`].
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
19pub struct CommitCounter(usize);
20
21impl CommitCounter {
22 /// Increment the commit counter
23 pub fn increment(&mut self) {
24 self.0 = self.0.wrapping_add(1)
25 }
26
27 /// Get the distance between two [`CommitCounter`]s
28 ///
29 /// If the [`CommitCounter`] is incremented on each recorded
30 /// damage this returns the count of damage that happened
31 /// between the [`CommitCounter`]s
32 ///
33 /// Returns `None` in case the distance could not be calculated.
34 /// If uses as part of damage tracking the tracked element
35 /// should be considered as fully damaged.
36 pub fn distance(&self, previous_commit: Option<CommitCounter>) -> Option<usize> {
37 // if commit > commit_count we have overflown, in that case the following map might result
38 // in a false-positive, if commit is still very large. So we force false in those cases.
39 // That will result in a potentially sub-optimal full damage every usize::MAX frames,
40 // which is acceptable.
41 previous_commit
42 .filter(|commit| commit <= self)
43 .map(|commit| self.0.wrapping_sub(commit.0))
44 }
45}
46
47impl From<usize> for CommitCounter {
48 #[inline]
49 fn from(counter: usize) -> Self {
50 CommitCounter(counter)
51 }
52}
53
54/// A tracker for holding damage
55///
56/// It keeps track of the submitted damage
57/// and automatically caps the damage
58/// with the specified limit.
59///
60/// See [`DamageSnapshot`] for more
61/// information.
62pub struct DamageBag<N, Kind> {
63 limit: usize,
64 state: DamageSnapshot<N, Kind>,
65}
66
67/// A snapshot of the current state of a [`DamageBag`]
68///
69/// The snapshot can be used to get an immutable view
70/// into the current state of a [`DamageBag`].
71/// It provides an easy way to get the damage between two
72/// [`CommitCounter`]s.
73pub struct DamageSnapshot<N, Kind> {
74 limit: usize,
75 commit_counter: CommitCounter,
76 damage: Arc<VecDeque<smallvec::SmallVec<[Rectangle<N, Kind>; MAX_DAMAGE_RECTS]>>>,
77}
78
79impl<N, Kind> Clone for DamageSnapshot<N, Kind> {
80 #[inline]
81 fn clone(&self) -> Self {
82 Self {
83 limit: self.limit,
84 commit_counter: self.commit_counter,
85 damage: self.damage.clone(),
86 }
87 }
88}
89
90impl<N: fmt::Debug> fmt::Debug for DamageBag<N, BufferCoord> {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 f.debug_struct("DamageBag")
93 .field("limit", &self.limit)
94 .field("state", &self.state)
95 .finish()
96 }
97}
98
99impl<N: fmt::Debug> fmt::Debug for DamageBag<N, Physical> {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.debug_struct("DamageBag")
102 .field("limit", &self.limit)
103 .field("state", &self.state)
104 .finish()
105 }
106}
107
108impl<N: fmt::Debug> fmt::Debug for DamageBag<N, Logical> {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 f.debug_struct("DamageBag")
111 .field("limit", &self.limit)
112 .field("state", &self.state)
113 .finish()
114 }
115}
116
117impl<N: fmt::Debug> fmt::Debug for DamageSnapshot<N, BufferCoord> {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.debug_struct("DamageSnapshot")
120 .field("commit_counter", &self.commit_counter)
121 .field("damage", &self.damage)
122 .finish()
123 }
124}
125
126impl<N: fmt::Debug> fmt::Debug for DamageSnapshot<N, Physical> {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.debug_struct("DamageSnapshot")
129 .field("commit_counter", &self.commit_counter)
130 .field("damage", &self.damage)
131 .finish()
132 }
133}
134
135impl<N: fmt::Debug> fmt::Debug for DamageSnapshot<N, Logical> {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("DamageSnapshot")
138 .field("commit_counter", &self.commit_counter)
139 .field("damage", &self.damage)
140 .finish()
141 }
142}
143
144const MAX_DAMAGE_AGE: usize = 4;
145const MAX_DAMAGE_RECTS: usize = 16;
146const MAX_DAMAGE_SET: usize = MAX_DAMAGE_RECTS * 2;
147
148impl<N: Clone, Kind> Default for DamageBag<N, Kind> {
149 #[inline]
150 fn default() -> Self {
151 DamageBag::new(MAX_DAMAGE_AGE)
152 }
153}
154
155impl<N: Clone, Kind> DamageSnapshot<N, Kind> {
156 fn new(limit: usize) -> Self {
157 DamageSnapshot {
158 limit,
159 commit_counter: CommitCounter::default(),
160 damage: Arc::new(VecDeque::with_capacity(limit)),
161 }
162 }
163
164 /// Create an empty damage snapshot
165 pub fn empty() -> Self {
166 DamageSnapshot {
167 limit: 0,
168 commit_counter: CommitCounter::default(),
169 damage: Default::default(),
170 }
171 }
172
173 /// Gets the current [`CommitCounter`] of this snapshot
174 ///
175 /// The returned [`CommitCounter`] should be stored after
176 /// calling [`damage_since`](DamageSnapshot::damage_since)
177 /// and provided to the next call of [`damage_since`](DamageSnapshot::damage_since)
178 /// to query the damage between these two [`CommitCounter`]s.
179 #[inline]
180 pub fn current_commit(&self) -> CommitCounter {
181 self.commit_counter
182 }
183
184 /// Provides raw access to the stored damage
185 pub fn raw(&self) -> impl Iterator<Item = impl Iterator<Item = &Rectangle<N, Kind>>> {
186 self.damage.iter().map(|d| d.iter())
187 }
188
189 fn reset(&mut self) {
190 Arc::make_mut(&mut self.damage).clear();
191 self.commit_counter.increment();
192 }
193}
194
195impl<N: Coordinate, Kind> DamageSnapshot<N, Kind> {
196 /// Get the damage since the last commit
197 ///
198 /// Returns `None` in case the [`CommitCounter`] is too old
199 /// or the damage has been reset. In that case the whole
200 /// element geometry should be considered as damaged
201 ///
202 /// If the commit is recent enough and no damage has occurred
203 /// an empty `Vec` will be returned
204 pub fn damage_since(&self, commit: Option<CommitCounter>) -> Option<DamageSet<N, Kind>> {
205 let distance = self.commit_counter.distance(commit);
206
207 if distance
208 .map(|distance| distance <= self.damage.len())
209 .unwrap_or(false)
210 {
211 let mut damage_set = DamageSet::default();
212 for damage in self.damage.iter().take(distance.unwrap()) {
213 damage_set.damage.extend_from_slice(damage);
214 }
215 Some(damage_set)
216 } else {
217 None
218 }
219 }
220
221 fn add(&mut self, damage: impl IntoIterator<Item = Rectangle<N, Kind>>) {
222 // FIXME: Get rid of this allocation here
223 let mut damage = damage.into_iter().filter(|d| !d.is_empty()).collect::<Vec<_>>();
224
225 if damage.is_empty() {
226 // do not track empty damage
227 return;
228 }
229
230 damage.dedup();
231
232 let inner_damage = Arc::make_mut(&mut self.damage);
233 inner_damage.push_front(smallvec::SmallVec::from_vec(damage));
234 inner_damage.truncate(self.limit);
235
236 self.commit_counter.increment();
237 }
238}
239
240impl<N: Clone, Kind> DamageBag<N, Kind> {
241 /// Initialize a a new [`DamageBag`] with the specified limit
242 pub fn new(limit: usize) -> Self {
243 DamageBag {
244 limit,
245 state: DamageSnapshot::new(limit),
246 }
247 }
248
249 /// Gets the current [`CommitCounter`] of this tracker
250 #[inline]
251 pub fn current_commit(&self) -> CommitCounter {
252 self.state.current_commit()
253 }
254
255 /// Provides raw access to the stored damage
256 pub fn raw(&self) -> impl Iterator<Item = impl Iterator<Item = &Rectangle<N, Kind>>> {
257 self.state.raw()
258 }
259
260 /// Reset the damage
261 ///
262 /// This should be called when the
263 /// tracked item has been resized
264 pub fn reset(&mut self) {
265 self.state.reset()
266 }
267}
268
269impl<N, Kind> DamageBag<N, Kind> {
270 /// Get a snapshot of the current damage
271 pub fn snapshot(&self) -> DamageSnapshot<N, Kind> {
272 self.state.clone()
273 }
274}
275
276impl<N: Coordinate, Kind> DamageBag<N, Kind> {
277 /// Add some damage to the tracker
278 pub fn add(&mut self, damage: impl IntoIterator<Item = Rectangle<N, Kind>>) {
279 self.state.add(damage)
280 }
281
282 /// Get the damage since the last commit
283 ///
284 /// Returns `None` in case the [`CommitCounter`] is too old
285 /// or the damage has been reset. In that case the whole
286 /// element geometry should be considered as damaged
287 ///
288 /// If the commit is recent enough and no damage has occurred
289 /// an empty `Vec` will be returned
290 pub fn damage_since(&self, commit: Option<CommitCounter>) -> Option<DamageSet<N, Kind>> {
291 self.state.damage_since(commit)
292 }
293}
294
295/// A set of damage returned from [`DamageBag::damage_since`] of [`DamageSnapshot::damage_since`]
296pub struct DamageSet<N, Kind> {
297 damage: smallvec::SmallVec<[Rectangle<N, Kind>; MAX_DAMAGE_SET]>,
298}
299
300impl<N, Kind> Default for DamageSet<N, Kind> {
301 fn default() -> Self {
302 Self {
303 damage: Default::default(),
304 }
305 }
306}
307
308impl<N: Copy, Kind> DamageSet<N, Kind> {
309 /// Copy the damage from a slice into a new `DamageSet`.
310 #[inline]
311 pub fn from_slice(slice: &[Rectangle<N, Kind>]) -> Self {
312 Self {
313 damage: smallvec::SmallVec::from_slice(slice),
314 }
315 }
316}
317
318impl<N, Kind> std::ops::Deref for DamageSet<N, Kind> {
319 type Target = [Rectangle<N, Kind>];
320
321 #[inline]
322 fn deref(&self) -> &Self::Target {
323 &self.damage
324 }
325}
326
327impl<N, Kind> IntoIterator for DamageSet<N, Kind> {
328 type Item = Rectangle<N, Kind>;
329
330 type IntoIter = DamageSetIter<N, Kind>;
331
332 #[inline]
333 fn into_iter(self) -> Self::IntoIter {
334 DamageSetIter {
335 inner: self.damage.into_iter(),
336 }
337 }
338}
339
340impl<N, Kind> FromIterator<Rectangle<N, Kind>> for DamageSet<N, Kind> {
341 #[inline]
342 fn from_iter<T: IntoIterator<Item = Rectangle<N, Kind>>>(iter: T) -> Self {
343 Self {
344 damage: smallvec::SmallVec::from_iter(iter),
345 }
346 }
347}
348
349/// Iterator for [`DamageSet::into_iter`]
350pub struct DamageSetIter<N, Kind> {
351 inner: smallvec::IntoIter<[Rectangle<N, Kind>; MAX_DAMAGE_SET]>,
352}
353
354impl<N: fmt::Debug> fmt::Debug for DamageSetIter<N, BufferCoord> {
355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356 f.debug_struct("DamageSetIter")
357 .field("inner", &self.inner)
358 .finish()
359 }
360}
361
362impl<N: fmt::Debug> fmt::Debug for DamageSetIter<N, Physical> {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 f.debug_struct("DamageSetIter")
365 .field("inner", &self.inner)
366 .finish()
367 }
368}
369
370impl<N: fmt::Debug> fmt::Debug for DamageSetIter<N, Logical> {
371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 f.debug_struct("DamageSetIter")
373 .field("inner", &self.inner)
374 .finish()
375 }
376}
377
378impl<N, Kind> Iterator for DamageSetIter<N, Kind> {
379 type Item = Rectangle<N, Kind>;
380
381 #[inline]
382 fn next(&mut self) -> Option<Self::Item> {
383 self.inner.next()
384 }
385
386 #[inline]
387 fn size_hint(&self) -> (usize, Option<usize>) {
388 self.inner.size_hint()
389 }
390}
391
392impl<N: fmt::Debug> fmt::Debug for DamageSet<N, BufferCoord> {
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 f.debug_struct("DamageSet").field("damage", &self.damage).finish()
395 }
396}
397
398impl<N: fmt::Debug> fmt::Debug for DamageSet<N, Physical> {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 f.debug_struct("DamageSet").field("damage", &self.damage).finish()
401 }
402}
403
404impl<N: fmt::Debug> fmt::Debug for DamageSet<N, Logical> {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 f.debug_struct("DamageSet").field("damage", &self.damage).finish()
407 }
408}
409
410const MAX_OPAQUE_REGIONS: usize = 16;
411
412/// Wrapper for a set of opaque regions
413pub struct OpaqueRegions<N, Kind> {
414 regions: smallvec::SmallVec<[Rectangle<N, Kind>; MAX_OPAQUE_REGIONS]>,
415}
416
417impl<N, Kind> Default for OpaqueRegions<N, Kind>
418where
419 N: Default,
420{
421 #[inline]
422 fn default() -> Self {
423 Self {
424 regions: Default::default(),
425 }
426 }
427}
428
429impl<N: Copy, Kind> OpaqueRegions<N, Kind> {
430 /// Copy the opaque regions from a slice into a new `OpaqueRegions`.
431 #[inline]
432 pub fn from_slice(slice: &[Rectangle<N, Kind>]) -> Self {
433 Self {
434 regions: smallvec::SmallVec::from_slice(slice),
435 }
436 }
437}
438
439impl<N, Kind> std::ops::Deref for OpaqueRegions<N, Kind> {
440 type Target = [Rectangle<N, Kind>];
441
442 #[inline]
443 fn deref(&self) -> &Self::Target {
444 &self.regions
445 }
446}
447
448impl<N, Kind> IntoIterator for OpaqueRegions<N, Kind> {
449 type Item = Rectangle<N, Kind>;
450
451 type IntoIter = OpaqueRegionsIter<N, Kind>;
452
453 #[inline]
454 fn into_iter(self) -> Self::IntoIter {
455 OpaqueRegionsIter {
456 inner: self.regions.into_iter(),
457 }
458 }
459}
460
461impl<N, Kind> FromIterator<Rectangle<N, Kind>> for OpaqueRegions<N, Kind> {
462 #[inline]
463 fn from_iter<T: IntoIterator<Item = Rectangle<N, Kind>>>(iter: T) -> Self {
464 Self {
465 regions: smallvec::SmallVec::from_iter(iter),
466 }
467 }
468}
469
470/// Iterator for [`OpaqueRegions::into_iter`]
471pub struct OpaqueRegionsIter<N, Kind> {
472 inner: smallvec::IntoIter<[Rectangle<N, Kind>; MAX_OPAQUE_REGIONS]>,
473}
474
475impl<N: fmt::Debug> fmt::Debug for OpaqueRegionsIter<N, BufferCoord> {
476 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477 f.debug_struct("OpaqueRegionsIter")
478 .field("inner", &self.inner)
479 .finish()
480 }
481}
482
483impl<N: fmt::Debug> fmt::Debug for OpaqueRegionsIter<N, Physical> {
484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485 f.debug_struct("OpaqueRegionsIter")
486 .field("inner", &self.inner)
487 .finish()
488 }
489}
490
491impl<N: fmt::Debug> fmt::Debug for OpaqueRegionsIter<N, Logical> {
492 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493 f.debug_struct("OpaqueRegionsIter")
494 .field("inner", &self.inner)
495 .finish()
496 }
497}
498
499impl<N, Kind> Iterator for OpaqueRegionsIter<N, Kind> {
500 type Item = Rectangle<N, Kind>;
501
502 #[inline]
503 fn next(&mut self) -> Option<Self::Item> {
504 self.inner.next()
505 }
506
507 #[inline]
508 fn size_hint(&self) -> (usize, Option<usize>) {
509 self.inner.size_hint()
510 }
511}
512
513impl<N: fmt::Debug> fmt::Debug for OpaqueRegions<N, BufferCoord> {
514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
515 f.debug_struct("OpaqueRegions")
516 .field("regions", &self.regions)
517 .finish()
518 }
519}
520
521impl<N: fmt::Debug> fmt::Debug for OpaqueRegions<N, Physical> {
522 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523 f.debug_struct("OpaqueRegions")
524 .field("regions", &self.regions)
525 .finish()
526 }
527}
528
529impl<N: fmt::Debug> fmt::Debug for OpaqueRegions<N, Logical> {
530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531 f.debug_struct("OpaqueRegions")
532 .field("regions", &self.regions)
533 .finish()
534 }
535}
536
537/// Defines a view into the surface
538#[derive(Debug, Default, PartialEq, Clone, Copy)]
539pub struct SurfaceView {
540 /// The logical source used for cropping
541 pub src: Rectangle<f64, Logical>,
542 /// The logical destination size used for scaling
543 pub dst: Size<i32, Logical>,
544 /// The logical offset for a sub-surface
545 pub offset: Point<i32, Logical>,
546}