<NME> mod.rs
<BEF> use crate::{
    backend::renderer::{buffer_dimensions, Frame, ImportAll, Renderer, Texture},
    utils::{Logical, Physical, Point, Size},
    wayland::compositor::{
        is_sync_subsurface, with_surface_tree_upward, BufferAssignment, Damage, SubsurfaceCachedState,
        SurfaceAttributes, TraversalAction,
#[cfg(feature = "wayland_frontend")]
mod wayland;
#[cfg(feature = "wayland_frontend")]
pub use self::wayland::*;

/// A simple wrapper for counting commits
///
/// The purpose of the counter is to keep track
/// on the number of times something has changed.
/// It provides an easy way to obtain the distance
/// between two instances of a [`CommitCounter`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
pub struct CommitCounter(usize);

impl CommitCounter {
    /// Increment the commit counter
    pub fn increment(&mut self) {
        self.0 = self.0.wrapping_add(1)
    }

    /// Get the distance between two [`CommitCounter`]s
    ///
    /// If the [`CommitCounter`] is incremented on each recorded
    /// damage this returns the count of damage that happened
    /// between the [`CommitCounter`]s
    ///
    /// Returns `None` in case the distance could not be calculated.
    /// If uses as part of damage tracking the tracked element
    /// should be considered as fully damaged.
    pub fn distance(&self, previous_commit: Option<CommitCounter>) -> Option<usize> {
        // if commit > commit_count we have overflown, in that case the following map might result
        // in a false-positive, if commit is still very large. So we force false in those cases.
        // That will result in a potentially sub-optimal full damage every usize::MAX frames,
        // which is acceptable.
        previous_commit
            .filter(|commit| commit <= self)
            .map(|commit| self.0.wrapping_sub(commit.0))
    }
}

impl From<usize> for CommitCounter {
    fn from(counter: usize) -> Self {
        CommitCounter(counter)
    }
}

/// A tracker for holding damage
///
/// It keeps track of the submitted damage
/// and automatically caps the damage
/// with the specified limit.
///
/// See [`DamageTrackerSnapshot`] for more
/// information.
pub struct DamageTracker<N, Kind> {
    limit: usize,
    state: DamageTrackerSnapshot<N, Kind>,
}

    }
}

pub fn draw_surface_tree<R, E, F, T>(
    renderer: &mut R,
    frame: &mut F,
    surface: &WlSurface,
    scale: f64,
    location: Point<i32, Logical>,
    log: &slog::Logger,
) -> Result<(), R::Error>
where
        Self {
            limit: self.limit,
            commit_counter: self.commit_counter,
    T: Texture + 'static,
{
    let mut result = Ok(());
    with_surface_tree_upward(
        surface,
        location,
            .finish()
    }
}

impl<N: fmt::Debug> fmt::Debug for DamageTracker<N, Physical> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DamageTracker")
            .field("limit", &self.limit)
            .field("state", &self.state)
            .finish()
    }
}

impl<N: fmt::Debug> fmt::Debug for DamageTracker<N, Logical> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DamageTracker")
            .field("limit", &self.limit)
            .field("state", &self.state)
            .finish()
    }
}

impl<N: fmt::Debug> fmt::Debug for DamageTrackerSnapshot<N, BufferCoord> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DamageTrackerSnapshot")
            .field("commit_counter", &self.commit_counter)
            .field("damage", &self.damage)
            .finish()
    }
}

impl<N: fmt::Debug> fmt::Debug for DamageTrackerSnapshot<N, Physical> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DamageTrackerSnapshot")
            .field("commit_counter", &self.commit_counter)
            .field("damage", &self.damage)
            .finish()
    }
}

impl<N: fmt::Debug> fmt::Debug for DamageTrackerSnapshot<N, Logical> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DamageTrackerSnapshot")
            .field("commit_counter", &self.commit_counter)
            .field("damage", &self.damage)
            .finish()
    }
}

const MAX_DAMAGE: usize = 4;
            if let Some(data) = states.data_map.get::<RefCell<SurfaceState>>() {
                let mut data = data.borrow_mut();
                let buffer_scale = data.buffer_scale;
                let attributes = states.cached_state.current::<SurfaceAttributes>();
                if let Some(texture) = data.texture.as_mut().and_then(|x| x.downcast_mut::<T>()) {
                    // we need to re-extract the subsurface offset, as the previous closure
                    // only passes it to our children
                    if states.role == Some("subsurface") {
                        let current = states.cached_state.current::<SubsurfaceCachedState>();
                        location += current.location;
                    }

                    // TODO: Take wp_viewporter into account
                    if let Err(err) = frame.render_texture_at(
                        texture,
    }
                        buffer_scale,
                        scale,
                        attributes.buffer_transform.into(),
                        1.0,
                    ) {
                        result = Err(err);
        self.damage.clear();
        self.commit_counter.increment();
    }
}

impl<N: Coordinate, Kind> DamageTrackerSnapshot<N, Kind> {
    /// Get the damage since the last commit
    ///
    /// Returns `None` in case the [`CommitCounter`] is too old
    /// or the damage has been reset. In that case the whole
    /// element geometry should be considered as damaged
    ///
    /// If the commit is recent enough and no damage has occurred
    /// an empty `Vec` will be returned
    pub fn damage_since(&self, commit: Option<CommitCounter>) -> Option<Vec<Rectangle<N, Kind>>> {
        let distance = self.commit_counter.distance(commit);

        if distance
            .map(|distance| distance <= self.damage.len())
            .unwrap_or(false)
        {
            Some(
                self.damage
                    .iter()
                    .take(distance.unwrap())
                    .fold(Vec::new(), |mut acc, elem| {
                        acc.extend(elem);
                        acc
                    }),
            )
        } else {
            None
        }
    }

    fn add(&mut self, damage: &[Rectangle<N, Kind>]) {
        if damage.is_empty() || damage.iter().all(|d| d.is_empty()) {
            // do not track empty damage
            return;
        }

        let mut damage = damage
            .iter()
            .copied()
            .filter(|d| !d.is_empty())
            .collect::<Vec<_>>();
        damage.dedup();

        self.damage.push_front(damage);
        self.damage.truncate(self.limit);

        self.commit_counter.increment();
    }
}

impl<N, Kind> DamageTracker<N, Kind> {
    /// Initialize a a new [`DamageTracker`]
    pub fn new(limit: usize) -> Self {
        DamageTracker {
            limit,
            state: DamageTrackerSnapshot::new(limit),
        }
    }

    /// Gets the current [`CommitCounter`] of this tracker
    pub fn current_commit(&self) -> CommitCounter {
        self.state.current_commit()
    }

    /// Provides raw access to the stored damage
    pub fn damage(&self) -> impl Iterator<Item = &Vec<Rectangle<N, Kind>>> {
        self.state.damage()
    }

    /// Reset the damage
    ///
    /// This should be called when the
    /// tracked item has been resized
    pub fn reset(&mut self) {
        self.state.reset()
    }
}

impl<N: Clone, Kind> DamageTracker<N, Kind> {
    /// Get a snapshot of the current damage
    pub fn snapshot(&self) -> DamageTrackerSnapshot<N, Kind> {
        self.state.clone()
    }
}

impl<N: Coordinate, Kind> DamageTracker<N, Kind> {
    /// Add some damage to the tracker
    pub fn add(&mut self, damage: &[Rectangle<N, Kind>]) {
        self.state.add(damage)
    }

    /// Get the damage since the last commit
    ///
    /// Returns `None` in case the [`CommitCounter`] is too old
    /// or the damage has been reset. In that case the whole
    /// element geometry should be considered as damaged
    ///
    /// If the commit is recent enough and no damage has occurred
    /// an empty `Vec` will be returned
    pub fn damage_since(&self, commit: Option<CommitCounter>) -> Option<Vec<Rectangle<N, Kind>>> {
        self.state.damage_since(commit)
    }
}

/// Defines a view into the surface
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub struct SurfaceView {
    /// The logical source used for cropping
    pub src: Rectangle<f64, Logical>,
    /// The logical destination size used for scaling
    pub dst: Size<i32, Logical>,
    /// The logical offset for a sub-surface
    pub offset: Point<i32, Logical>,
}

<MSG> renderer: Use fine grained damage for rendering

Up until now we always redrew the whole windows, which worked
fine - except for some transparency issues - but left performance
on the table.

So now we use instancing to render only the actually damaged regions
inside the window, which also fixes our few rendering issues.

We also use a shader now for clearing the screen to use instancing as
well and lower the amount of draw calls at the begin of a frame for
clearing parts of it.

And while we are add it we remove the last rendering artifacts
by optimizing the damage vector by deduplicating and merging rectangles.

<DFF> @@ -1,6 +1,6 @@
 use crate::{
     backend::renderer::{buffer_dimensions, Frame, ImportAll, Renderer, Texture},
-    utils::{Logical, Physical, Point, Size},
+    utils::{Buffer, Logical, Physical, Point, Rectangle, Size},
     wayland::compositor::{
         is_sync_subsurface, with_surface_tree_upward, BufferAssignment, Damage, SubsurfaceCachedState,
         SurfaceAttributes, TraversalAction,
@@ -66,12 +66,14 @@ pub fn on_commit_buffer_handler(surface: &WlSurface) {
     }
 }
 
+/// TODO
 pub fn draw_surface_tree<R, E, F, T>(
     renderer: &mut R,
     frame: &mut F,
     surface: &WlSurface,
     scale: f64,
     location: Point<i32, Logical>,
+    damage: &[Rectangle<i32, Logical>],
     log: &slog::Logger,
 ) -> Result<(), R::Error>
 where
@@ -81,6 +83,10 @@ where
     T: Texture + 'static,
 {
     let mut result = Ok(());
+    let damage = damage
+        .iter()
+        .map(|geo| geo.to_f64().to_physical(scale).to_i32_round())
+        .collect::<Vec<_>>();
     with_surface_tree_upward(
         surface,
         location,
@@ -137,15 +143,33 @@ where
             if let Some(data) = states.data_map.get::<RefCell<SurfaceState>>() {
                 let mut data = data.borrow_mut();
                 let buffer_scale = data.buffer_scale;
+                let buffer_dimensions = data.buffer_dimensions;
                 let attributes = states.cached_state.current::<SurfaceAttributes>();
                 if let Some(texture) = data.texture.as_mut().and_then(|x| x.downcast_mut::<T>()) {
                     // we need to re-extract the subsurface offset, as the previous closure
                     // only passes it to our children
+                    let mut surface_offset = (0, 0).into();
                     if states.role == Some("subsurface") {
                         let current = states.cached_state.current::<SubsurfaceCachedState>();
+                        surface_offset = current.location;
                         location += current.location;
                     }
 
+                    let rect = Rectangle::<i32, Physical>::from_loc_and_size(
+                        surface_offset.to_f64().to_physical(scale).to_i32_round(),
+                        buffer_dimensions.unwrap(),
+                    );
+                    let new_damage = damage
+                        .iter()
+                        .cloned()
+                        .filter(|geo| geo.overlaps(rect))
+                        .map(|geo| geo.intersection(rect))
+                        .map(|mut geo| {
+                            geo.loc -= rect.loc;
+                            geo
+                        })
+                        .collect::<Vec<_>>();
+
                     // TODO: Take wp_viewporter into account
                     if let Err(err) = frame.render_texture_at(
                         texture,
@@ -153,6 +177,7 @@ where
                         buffer_scale,
                         scale,
                         attributes.buffer_transform.into(),
+                        &new_damage,
                         1.0,
                     ) {
                         result = Err(err);

renderer: Use fine grained damage for rendering