diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index e2739b1..30075d6 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -15,7 +15,7 @@ use smithay::{ }, utils::Rectangle, wayland::{ - compositor::{roles::Role, SubsurfaceRole, TraversalAction}, + compositor::{roles::Role, SubsurfaceRole, TraversalAction, Damage}, data_device::DnDIconRole, seat::CursorImageRole, }, @@ -90,7 +90,11 @@ where let mut data = data.borrow_mut(); if data.texture.is_none() { if let Some(buffer) = data.current_state.buffer.take() { - match renderer.import_buffer(&buffer, Some(&attributes.damage), egl_buffer_reader) { + let damage = attributes.damage.iter().map(|dmg| match dmg { + Damage::Buffer(rect) => *rect, + Damage::Surface(rect) => rect.scale(attributes.buffer_scale), + }).collect::>(); + match renderer.import_buffer(&buffer, &damage, egl_buffer_reader) { Ok(m) => { let buffer = if smithay::wayland::shm::with_buffer_contents(&buffer, |_,_| ()).is_ok() { buffer.release(); diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index 551efad..42759bd 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -28,10 +28,10 @@ use crate::backend::egl::{ ffi::egl::{self as ffi_egl, types::EGLImage}, EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError, }; -use crate::backend::SwapBuffersError; +use crate::{backend::SwapBuffersError, utils::Rectangle}; #[cfg(feature = "wayland_frontend")] -use crate::{backend::egl::display::EGLBufferReader, wayland::compositor::Damage}; +use crate::backend::egl::display::EGLBufferReader; #[cfg(feature = "wayland_frontend")] use wayland_commons::user_data::UserDataMap; #[cfg(feature = "wayland_frontend")] @@ -503,7 +503,7 @@ impl Gles2Renderer { fn import_shm( &mut self, buffer: &wl_buffer::WlBuffer, - mut damage: Option, + mut damage: &[crate::utils::Rectangle], ) -> Result { use crate::wayland::shm::with_buffer_contents; @@ -534,7 +534,7 @@ impl Gles2Renderer { let mut tex = 0; unsafe { self.gl.GenTextures(1, &mut tex) }; // different buffer, upload in full - damage = None; + damage = &[]; let texture = Gles2Texture(Rc::new(Gles2TextureInternal { texture: tex, texture_kind: shader_idx, @@ -564,7 +564,7 @@ impl Gles2Renderer { self.gl .TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32); self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize); - if let Some(region) = damage { + for region in damage { trace!(self.logger, "Uploading partial shm texture for {:?}", buffer); self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.x); self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, region.y); @@ -581,19 +581,6 @@ impl Gles2Renderer { ); self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, 0); self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, 0); - } else { - trace!(self.logger, "Uploading shm texture for {:?}", buffer); - self.gl.TexImage2D( - ffi::TEXTURE_2D, - 0, - gl_format as i32, - width, - height, - 0, - gl_format, - ffi::UNSIGNED_BYTE as u32, - slice.as_ptr().offset(offset as isize) as *const _, - ); } self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0); @@ -930,7 +917,7 @@ impl Renderer for Gles2Renderer { fn import_buffer( &mut self, buffer: &wl_buffer::WlBuffer, - damage: Option<&Damage>, + damage: &[Rectangle], egl: Option<&EGLBufferReader>, ) -> Result { let texture = if egl.and_then(|egl| egl.egl_buffer_dimensions(&buffer)).is_some() { @@ -938,10 +925,7 @@ impl Renderer for Gles2Renderer { } else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() { self.import_shm( &buffer, - damage.and_then(|damage| match damage { - Damage::Buffer(rect) => Some(*rect), - _ => None, - }), + damage, ) } else { Err(Gles2Error::UnknownBufferType) diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index de11695..6e7588f 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -10,13 +10,11 @@ use std::collections::HashSet; use std::error::Error; -#[cfg(feature = "wayland_frontend")] -use crate::wayland::compositor::Damage; use cgmath::{prelude::*, Matrix3, Vector2}; #[cfg(feature = "wayland_frontend")] use wayland_server::protocol::{wl_buffer, wl_shm}; -use crate::backend::SwapBuffersError; +use crate::{backend::SwapBuffersError, utils::Rectangle}; #[cfg(feature = "renderer_gl")] pub mod gles2; #[cfg(all(feature = "wayland_frontend", feature = "backend_egl"))] @@ -235,11 +233,14 @@ pub trait Renderer { /// /// The implementation defines, if the id keeps being valid, if the buffer is released, /// to avoid relying on implementation details, keep the buffer alive, until you destroyed this texture again. + /// + /// The `damage` argument provides a list of rectangle locating parts of the buffer that need to be updated. When provided + /// with an empty list `&[]`, the renderer is allows to not update the texture at all. #[cfg(all(feature = "wayland_frontend", feature = "backend_egl"))] fn import_buffer( &mut self, buffer: &wl_buffer::WlBuffer, - damage: Option<&Damage>, + damage: &[Rectangle], egl: Option<&EGLBufferReader>, ) -> Result; diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 3177142..4a234dd 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -28,6 +28,7 @@ use winit::{ platform::unix::WindowExtUnix, window::{Window as WinitWindow, WindowBuilder}, }; +use crate::utils::Rectangle; #[cfg(feature = "use_system_lib")] use crate::backend::egl::display::EGLBufferReader; diff --git a/src/utils/rectangle.rs b/src/utils/rectangle.rs index 575c565..febfb10 100644 --- a/src/utils/rectangle.rs +++ b/src/utils/rectangle.rs @@ -13,13 +13,13 @@ pub struct Rectangle { impl Rectangle { /// Checks whether given point is inside a rectangle - pub fn contains(&self, point: (i32, i32)) -> bool { + pub fn contains(self, point: (i32, i32)) -> bool { let (x, y) = point; (x >= self.x) && (x < self.x + self.width) && (y >= self.y) && (y < self.y + self.height) } /// Checks whether a given rectangle overlaps with this one - pub fn overlaps(&self, other: &Rectangle) -> bool { + pub fn overlaps(self, other: &Rectangle) -> bool { // if the rectangle is not outside of the other // they must overlap !( @@ -33,4 +33,14 @@ impl Rectangle { || self.y > other.y + other.height ) } + + /// Scales the dimensions of this rectangle by given factor + pub fn scale(self, factor: i32) -> Rectangle { + Rectangle { + x: self.x * factor, + y: self.y * factor, + width: self.width * factor, + height: self.height * factor, + } + } } diff --git a/src/wayland/compositor/handlers.rs b/src/wayland/compositor/handlers.rs index 3140c39..df5064d 100644 --- a/src/wayland/compositor/handlers.rs +++ b/src/wayland/compositor/handlers.rs @@ -78,7 +78,7 @@ where } wl_surface::Request::Damage { x, y, width, height } => { SurfaceData::::with_data(&surface, |d| { - d.damage = Damage::Surface(Rectangle { x, y, width, height }) + d.damage.push(Damage::Surface(Rectangle { x, y, width, height })); }); } wl_surface::Request::Frame { callback } => { @@ -113,7 +113,7 @@ where } wl_surface::Request::DamageBuffer { x, y, width, height } => { SurfaceData::::with_data(&surface, |d| { - d.damage = Damage::Buffer(Rectangle { x, y, width, height }) + d.damage.push(Damage::Buffer(Rectangle { x, y, width, height })) }); } wl_surface::Request::Destroy => { diff --git a/src/wayland/compositor/mod.rs b/src/wayland/compositor/mod.rs index 5d9a627..4f9b61b 100644 --- a/src/wayland/compositor/mod.rs +++ b/src/wayland/compositor/mod.rs @@ -87,12 +87,10 @@ use wayland_server::{ Display, Filter, Global, UserDataMap, }; -/// Description of which part of a surface +/// Description of a part of a surface that /// should be considered damaged and needs to be redrawn #[derive(Debug)] pub enum Damage { - /// The whole surface must be considered damaged (this is the default) - Full, /// A rectangle containing the damaged zone, in surface coordinates Surface(Rectangle), /// A rectangle containing the damaged zone, in buffer coordinates @@ -157,7 +155,7 @@ pub struct SurfaceAttributes { /// /// Hint provided by the client to suggest that only this part /// of the surface was changed and needs to be redrawn - pub damage: Damage, + pub damage: Vec, /// The frame callback associated with this surface for the commit /// /// The be triggered to notify the client about when it would be a @@ -196,7 +194,7 @@ impl Default for SurfaceAttributes { buffer_transform: wl_output::Transform::Normal, opaque_region: None, input_region: None, - damage: Damage::Full, + damage: Vec::new(), frame_callback: None, user_data: UserDataMap::new(), }