<NME> drawing.rs
<BEF> #![allow(clippy::too_many_arguments)]

use smithay::{
    backend::renderer::{
        element::{
            surface::WaylandSurfaceRenderElement,
            texture::{TextureBuffer, TextureRenderElement},
            AsRenderElements,
        },
        ImportAll, Renderer, Texture,
    },
    input::pointer::CursorImageStatus,
    render_elements,
    utils::{Physical, Point, Scale},
};
#[cfg(feature = "debug")]
use smithay::{
    backend::renderer::{
        element::{Id, RenderElement},
        utils::CommitCounter,
        Frame,
    },
    utils::{Buffer, Logical, Rectangle, Size, Transform},
};

pub static CLEAR_COLOR: [f32; 4] = [0.8, 0.8, 0.9, 1.0];
pub struct PointerElement<T: Texture> {
    texture: Option<TextureBuffer<T>>,
    status: CursorImageStatus,
}

impl<T: Texture> Default for PointerElement<T> {
    fn default() -> Self {
        Self {
            texture: Default::default(),
            status: CursorImageStatus::Default,
        }
    }
}

impl<T: Texture> PointerElement<T> {
    pub fn set_status(&mut self, status: CursorImageStatus) {
        self.status = status;
    }

    pub fn set_texture(&mut self, texture: TextureBuffer<T>) {
        self.texture = Some(texture);
    }
}

render_elements! {
    pub PointerRenderElement<R> where
        R: ImportAll;
    Surface=WaylandSurfaceRenderElement,
    Texture=TextureRenderElement<<R as Renderer>::TextureId>,
}

impl<T: Texture + Clone + 'static, R> AsRenderElements<R> for PointerElement<T>
where
    R: Renderer<TextureId = T> + ImportAll,
{
    type RenderElement = PointerRenderElement<R>;
    fn render_elements<E>(&self, location: Point<i32, Physical>, scale: Scale<f64>) -> Vec<E>
    where
        E: From<PointerRenderElement<R>>,
    {
        match &self.status {
            CursorImageStatus::Hidden => vec![],
            CursorImageStatus::Default => {
                if let Some(texture) = self.texture.as_ref() {
                    vec![
                        PointerRenderElement::<R>::from(TextureRenderElement::from_texture_buffer(
                            location.to_f64(),
                            texture,
                            None,
                            None,
                        ))
                        .into(),
                    ]
                } else {
                    vec![]
                }
            }
            CursorImageStatus::Surface(surface) => {
                let elements: Vec<PointerRenderElement<R>> =
                    smithay::backend::renderer::element::surface::render_elements_from_surface_tree(
                        surface, location, scale,
                    );
                elements.into_iter().map(E::from).collect()
            }
        }
    }
}

#[cfg(feature = "debug")]
pub static FPS_NUMBERS_PNG: &[u8] = include_bytes!("../resources/numbers.png");

#[cfg(feature = "debug")]
#[derive(Clone)]
pub struct FpsElement<T: Texture> {
    id: Id,
    value: u32,
    texture: T,
    commit_counter: CommitCounter,
}

#[cfg(feature = "debug")]
impl<T: Texture> FpsElement<T> {
    pub fn new(texture: T) -> Self {
        FpsElement {
            id: Id::new(),
            texture,
            value: 0,
            commit_counter: CommitCounter::default(),
        }
    }

    pub fn update_fps(&mut self, fps: u32) {
        if self.value != fps {
            self.value = fps;
            self.commit_counter.increment();
        }
                                    })
                                    .collect::<Vec<_>>();
                                let result = renderer.import_shm_buffer(&buffer, Some(&attributes), &damage);
                                if result.is_ok() {
                                    buffer.release();
                                }
                                Some(result)
                            },
                            #[cfg(feature = "egl")]
                            Some(BufferType::Egl) => Some(renderer.import_egl_buffer(&buffer, egl_buffer_reader.unwrap())),
                            Some(BufferType::Dma) => Some(renderer.import_dma_buffer(&buffer)),
                            _ => {
                                error!(log, "Unknown buffer format for: {:?}", buffer);
                                None
                            }
                        };
                        match texture {
                            Some(Ok(m)) => {
                                data.texture = Some(Box::new(BufferTextures { buffer: Some(buffer), texture: m })
                                    as Box<dyn std::any::Any + 'static>)
                            }
                            // there was an error reading the buffer, release it.
                            Some(Err(err)) => {
                                warn!(log, "Error loading buffer: {:?}", err);
                                buffer.release();
                            },
                            None => buffer.release(),
                        };
                    }
                }
            2
        } else {
            3
        };
        Rectangle::from_loc_and_size((0, 0), (24 * digits, 35)).to_physical_precise_round(scale)
    }

    fn current_commit(&self) -> CommitCounter {
        self.commit_counter
    }

    fn draw(
        &self,
        _renderer: &mut R,
        frame: &mut <R as Renderer>::Frame,
        location: Point<i32, Physical>,
        scale: Scale<f64>,
        damage: &[Rectangle<i32, Physical>],
        _log: &slog::Logger,
    ) -> Result<(), R::Error> {
        let value_str = std::cmp::min(self.value, 999).to_string();
        let mut offset: Point<f64, Physical> = Point::from((0.0, 0.0));
        for digit in value_str.chars().map(|d| d.to_digit(10).unwrap()) {
            let digit_location = location.to_f64() + offset;
            let digit_size = Size::<i32, Logical>::from((22, 35)).to_f64().to_physical(scale);
            let dst = Rectangle::from_loc_and_size(
                digit_location.to_i32_round(),
                ((digit_size.to_point() + digit_location).to_i32_round() - digit_location.to_i32_round())
                    .to_size(),
            );
            let damage = damage
                .iter()
                .cloned()
                .flat_map(|x| x.intersection(dst))
                .map(|mut x| {
                    x.loc -= dst.loc;
                    x
                })
                .collect::<Vec<_>>();
            let src: Rectangle<i32, Buffer> = match digit {
                9 => Rectangle::from_loc_and_size((0, 0), (22, 35)),
                6 => Rectangle::from_loc_and_size((22, 0), (22, 35)),
                3 => Rectangle::from_loc_and_size((44, 0), (22, 35)),
                1 => Rectangle::from_loc_and_size((66, 0), (22, 35)),
                8 => Rectangle::from_loc_and_size((0, 35), (22, 35)),
                0 => Rectangle::from_loc_and_size((22, 35), (22, 35)),
                2 => Rectangle::from_loc_and_size((44, 35), (22, 35)),
                7 => Rectangle::from_loc_and_size((0, 70), (22, 35)),
                4 => Rectangle::from_loc_and_size((22, 70), (22, 35)),
                5 => Rectangle::from_loc_and_size((44, 70), (22, 35)),
                _ => unreachable!(),
            };
            frame.render_texture_from_to(
                &self.texture,
                src.to_f64(),
                dst,
                &damage,
                Transform::Normal,
                1.0,
            )?;
            offset += Point::from((24.0, 0.0)).to_physical(scale);
        }

        Ok(())
    }
}

<MSG> anvil: don't release SHM buffers twice

<DFF> @@ -123,30 +123,32 @@ where
                                     })
                                     .collect::<Vec<_>>();
                                 let result = renderer.import_shm_buffer(&buffer, Some(&attributes), &damage);
-                                if result.is_ok() {
-                                    buffer.release();
-                                }
-                                Some(result)
+                                buffer.release();
+                                // don't return the buffer as it is already released
+                                Some((result, None))
                             },
                             #[cfg(feature = "egl")]
-                            Some(BufferType::Egl) => Some(renderer.import_egl_buffer(&buffer, egl_buffer_reader.unwrap())),
-                            Some(BufferType::Dma) => Some(renderer.import_dma_buffer(&buffer)),
+                            Some(BufferType::Egl) => Some((renderer.import_egl_buffer(&buffer, egl_buffer_reader.unwrap()), Some(buffer))),
+                            Some(BufferType::Dma) => Some((renderer.import_dma_buffer(&buffer), Some(buffer))),
                             _ => {
                                 error!(log, "Unknown buffer format for: {:?}", buffer);
+                                buffer.release();
                                 None
                             }
                         };
                         match texture {
-                            Some(Ok(m)) => {
-                                data.texture = Some(Box::new(BufferTextures { buffer: Some(buffer), texture: m })
+                            Some((Ok(m), buffer)) => {
+                                data.texture = Some(Box::new(BufferTextures { buffer, texture: m })
                                     as Box<dyn std::any::Any + 'static>)
                             }
                             // there was an error reading the buffer, release it.
-                            Some(Err(err)) => {
+                            Some((Err(err), buffer)) => {
                                 warn!(log, "Error loading buffer: {:?}", err);
-                                buffer.release();
+                                if let Some(buffer) = buffer {
+                                    buffer.release();
+                                }
                             },
-                            None => buffer.release(),
+                            None => {},
                         };
                     }
                 }

anvil: don't release SHM buffers twice