Fix damage handling to support multiple rectangles
This commit is contained in:
parent
978ef1b393
commit
6bfe6e1f25
|
@ -15,7 +15,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
utils::Rectangle,
|
utils::Rectangle,
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::{roles::Role, SubsurfaceRole, TraversalAction},
|
compositor::{roles::Role, SubsurfaceRole, TraversalAction, Damage},
|
||||||
data_device::DnDIconRole,
|
data_device::DnDIconRole,
|
||||||
seat::CursorImageRole,
|
seat::CursorImageRole,
|
||||||
},
|
},
|
||||||
|
@ -90,7 +90,11 @@ where
|
||||||
let mut data = data.borrow_mut();
|
let mut data = data.borrow_mut();
|
||||||
if data.texture.is_none() {
|
if data.texture.is_none() {
|
||||||
if let Some(buffer) = data.current_state.buffer.take() {
|
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::<Vec<_>>();
|
||||||
|
match renderer.import_buffer(&buffer, &damage, egl_buffer_reader) {
|
||||||
Ok(m) => {
|
Ok(m) => {
|
||||||
let buffer = if smithay::wayland::shm::with_buffer_contents(&buffer, |_,_| ()).is_ok() {
|
let buffer = if smithay::wayland::shm::with_buffer_contents(&buffer, |_,_| ()).is_ok() {
|
||||||
buffer.release();
|
buffer.release();
|
||||||
|
|
|
@ -28,10 +28,10 @@ use crate::backend::egl::{
|
||||||
ffi::egl::{self as ffi_egl, types::EGLImage},
|
ffi::egl::{self as ffi_egl, types::EGLImage},
|
||||||
EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
|
EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
|
||||||
};
|
};
|
||||||
use crate::backend::SwapBuffersError;
|
use crate::{backend::SwapBuffersError, utils::Rectangle};
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use crate::{backend::egl::display::EGLBufferReader, wayland::compositor::Damage};
|
use crate::backend::egl::display::EGLBufferReader;
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_commons::user_data::UserDataMap;
|
use wayland_commons::user_data::UserDataMap;
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
|
@ -503,7 +503,7 @@ impl Gles2Renderer {
|
||||||
fn import_shm(
|
fn import_shm(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &wl_buffer::WlBuffer,
|
buffer: &wl_buffer::WlBuffer,
|
||||||
mut damage: Option<crate::utils::Rectangle>,
|
mut damage: &[crate::utils::Rectangle],
|
||||||
) -> Result<Gles2Texture, Gles2Error> {
|
) -> Result<Gles2Texture, Gles2Error> {
|
||||||
use crate::wayland::shm::with_buffer_contents;
|
use crate::wayland::shm::with_buffer_contents;
|
||||||
|
|
||||||
|
@ -534,7 +534,7 @@ impl Gles2Renderer {
|
||||||
let mut tex = 0;
|
let mut tex = 0;
|
||||||
unsafe { self.gl.GenTextures(1, &mut tex) };
|
unsafe { self.gl.GenTextures(1, &mut tex) };
|
||||||
// different buffer, upload in full
|
// different buffer, upload in full
|
||||||
damage = None;
|
damage = &[];
|
||||||
let texture = Gles2Texture(Rc::new(Gles2TextureInternal {
|
let texture = Gles2Texture(Rc::new(Gles2TextureInternal {
|
||||||
texture: tex,
|
texture: tex,
|
||||||
texture_kind: shader_idx,
|
texture_kind: shader_idx,
|
||||||
|
@ -564,7 +564,7 @@ impl Gles2Renderer {
|
||||||
self.gl
|
self.gl
|
||||||
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
.TexParameteri(ffi::TEXTURE_2D, ffi::TEXTURE_WRAP_T, ffi::CLAMP_TO_EDGE as i32);
|
||||||
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, stride / pixelsize);
|
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);
|
trace!(self.logger, "Uploading partial shm texture for {:?}", buffer);
|
||||||
self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.x);
|
self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.x);
|
||||||
self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, region.y);
|
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_PIXELS, 0);
|
||||||
self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, 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);
|
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
|
||||||
|
@ -930,7 +917,7 @@ impl Renderer for Gles2Renderer {
|
||||||
fn import_buffer(
|
fn import_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &wl_buffer::WlBuffer,
|
buffer: &wl_buffer::WlBuffer,
|
||||||
damage: Option<&Damage>,
|
damage: &[Rectangle],
|
||||||
egl: Option<&EGLBufferReader>,
|
egl: Option<&EGLBufferReader>,
|
||||||
) -> Result<Self::TextureId, Self::Error> {
|
) -> Result<Self::TextureId, Self::Error> {
|
||||||
let texture = if egl.and_then(|egl| egl.egl_buffer_dimensions(&buffer)).is_some() {
|
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() {
|
} else if crate::wayland::shm::with_buffer_contents(&buffer, |_, _| ()).is_ok() {
|
||||||
self.import_shm(
|
self.import_shm(
|
||||||
&buffer,
|
&buffer,
|
||||||
damage.and_then(|damage| match damage {
|
damage,
|
||||||
Damage::Buffer(rect) => Some(*rect),
|
|
||||||
_ => None,
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(Gles2Error::UnknownBufferType)
|
Err(Gles2Error::UnknownBufferType)
|
||||||
|
|
|
@ -10,13 +10,11 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
|
||||||
use crate::wayland::compositor::Damage;
|
|
||||||
use cgmath::{prelude::*, Matrix3, Vector2};
|
use cgmath::{prelude::*, Matrix3, Vector2};
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use wayland_server::protocol::{wl_buffer, wl_shm};
|
use wayland_server::protocol::{wl_buffer, wl_shm};
|
||||||
|
|
||||||
use crate::backend::SwapBuffersError;
|
use crate::{backend::SwapBuffersError, utils::Rectangle};
|
||||||
#[cfg(feature = "renderer_gl")]
|
#[cfg(feature = "renderer_gl")]
|
||||||
pub mod gles2;
|
pub mod gles2;
|
||||||
#[cfg(all(feature = "wayland_frontend", feature = "backend_egl"))]
|
#[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,
|
/// 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.
|
/// 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"))]
|
#[cfg(all(feature = "wayland_frontend", feature = "backend_egl"))]
|
||||||
fn import_buffer(
|
fn import_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &wl_buffer::WlBuffer,
|
buffer: &wl_buffer::WlBuffer,
|
||||||
damage: Option<&Damage>,
|
damage: &[Rectangle],
|
||||||
egl: Option<&EGLBufferReader>,
|
egl: Option<&EGLBufferReader>,
|
||||||
) -> Result<Self::TextureId, Self::Error>;
|
) -> Result<Self::TextureId, Self::Error>;
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ use winit::{
|
||||||
platform::unix::WindowExtUnix,
|
platform::unix::WindowExtUnix,
|
||||||
window::{Window as WinitWindow, WindowBuilder},
|
window::{Window as WinitWindow, WindowBuilder},
|
||||||
};
|
};
|
||||||
|
use crate::utils::Rectangle;
|
||||||
|
|
||||||
#[cfg(feature = "use_system_lib")]
|
#[cfg(feature = "use_system_lib")]
|
||||||
use crate::backend::egl::display::EGLBufferReader;
|
use crate::backend::egl::display::EGLBufferReader;
|
||||||
|
|
|
@ -13,13 +13,13 @@ pub struct Rectangle {
|
||||||
|
|
||||||
impl Rectangle {
|
impl Rectangle {
|
||||||
/// Checks whether given point is inside a 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;
|
let (x, y) = point;
|
||||||
(x >= self.x) && (x < self.x + self.width) && (y >= self.y) && (y < self.y + self.height)
|
(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
|
/// 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
|
// if the rectangle is not outside of the other
|
||||||
// they must overlap
|
// they must overlap
|
||||||
!(
|
!(
|
||||||
|
@ -33,4 +33,14 @@ impl Rectangle {
|
||||||
|| self.y > other.y + other.height
|
|| 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ where
|
||||||
}
|
}
|
||||||
wl_surface::Request::Damage { x, y, width, height } => {
|
wl_surface::Request::Damage { x, y, width, height } => {
|
||||||
SurfaceData::<R>::with_data(&surface, |d| {
|
SurfaceData::<R>::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 } => {
|
wl_surface::Request::Frame { callback } => {
|
||||||
|
@ -113,7 +113,7 @@ where
|
||||||
}
|
}
|
||||||
wl_surface::Request::DamageBuffer { x, y, width, height } => {
|
wl_surface::Request::DamageBuffer { x, y, width, height } => {
|
||||||
SurfaceData::<R>::with_data(&surface, |d| {
|
SurfaceData::<R>::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 => {
|
wl_surface::Request::Destroy => {
|
||||||
|
|
|
@ -87,12 +87,10 @@ use wayland_server::{
|
||||||
Display, Filter, Global, UserDataMap,
|
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
|
/// should be considered damaged and needs to be redrawn
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Damage {
|
pub enum Damage {
|
||||||
/// The whole surface must be considered damaged (this is the default)
|
|
||||||
Full,
|
|
||||||
/// A rectangle containing the damaged zone, in surface coordinates
|
/// A rectangle containing the damaged zone, in surface coordinates
|
||||||
Surface(Rectangle),
|
Surface(Rectangle),
|
||||||
/// A rectangle containing the damaged zone, in buffer coordinates
|
/// 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
|
/// Hint provided by the client to suggest that only this part
|
||||||
/// of the surface was changed and needs to be redrawn
|
/// of the surface was changed and needs to be redrawn
|
||||||
pub damage: Damage,
|
pub damage: Vec<Damage>,
|
||||||
/// The frame callback associated with this surface for the commit
|
/// The frame callback associated with this surface for the commit
|
||||||
///
|
///
|
||||||
/// The be triggered to notify the client about when it would be a
|
/// 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,
|
buffer_transform: wl_output::Transform::Normal,
|
||||||
opaque_region: None,
|
opaque_region: None,
|
||||||
input_region: None,
|
input_region: None,
|
||||||
damage: Damage::Full,
|
damage: Vec::new(),
|
||||||
frame_callback: None,
|
frame_callback: None,
|
||||||
user_data: UserDataMap::new(),
|
user_data: UserDataMap::new(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue