Fixup import_buffer definition to account for subsurface damage

This commit is contained in:
Victor Brekenfeld 2021-05-27 17:34:37 +02:00
parent 12e80ca2c6
commit 25c61c7a73
3 changed files with 27 additions and 24 deletions

View File

@ -1,6 +1,6 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use std::{cell::RefCell, rc::Rc}; use std::cell::RefCell;
use slog::Logger; use slog::Logger;
use smithay::{ use smithay::{
@ -9,10 +9,7 @@ use smithay::{
renderer::{Frame, Renderer, Texture, Transform}, renderer::{Frame, Renderer, Texture, Transform},
SwapBuffersError, SwapBuffersError,
}, },
reexports::{ reexports::wayland_server::protocol::{wl_buffer, wl_surface},
calloop::LoopHandle,
wayland_server::protocol::{wl_buffer, wl_surface},
},
utils::Rectangle, utils::Rectangle,
wayland::{ wayland::{
compositor::{roles::Role, Damage, SubsurfaceRole, TraversalAction}, compositor::{roles::Role, Damage, SubsurfaceRole, TraversalAction},
@ -98,7 +95,16 @@ 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, &attributes, egl_buffer_reader) { let damage = attributes
.damage
.iter()
.map(|dmg| match dmg {
Damage::Buffer(rect) => *rect,
// TODO also apply transformations
Damage::Surface(rect) => rect.scale(attributes.buffer_scale),
})
.collect::<Vec<_>>();
match renderer.import_buffer(&buffer, Some(&attributes), &damage, egl_buffer_reader) {
Ok(m) => { Ok(m) => {
let buffer = if smithay::wayland::shm::with_buffer_contents( let buffer = if smithay::wayland::shm::with_buffer_contents(
&buffer, &buffer,

View File

@ -32,8 +32,7 @@ use crate::backend::SwapBuffersError;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use crate::{ use crate::{
backend::egl::display::EGLBufferReader, backend::egl::display::EGLBufferReader, utils::Rectangle, wayland::compositor::SurfaceAttributes,
wayland::compositor::{Damage, SurfaceAttributes},
}; };
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_commons::user_data::UserDataMap; use wayland_commons::user_data::UserDataMap;
@ -506,7 +505,8 @@ impl Gles2Renderer {
fn import_shm( fn import_shm(
&mut self, &mut self,
buffer: &wl_buffer::WlBuffer, buffer: &wl_buffer::WlBuffer,
surface: &SurfaceAttributes, surface: Option<&SurfaceAttributes>,
damage: &[Rectangle],
) -> Result<Gles2Texture, Gles2Error> { ) -> Result<Gles2Texture, Gles2Error> {
use crate::wayland::shm::with_buffer_contents; use crate::wayland::shm::with_buffer_contents;
@ -539,9 +539,7 @@ impl Gles2Renderer {
// why not store a `Gles2Texture`? because the user might do so. // why not store a `Gles2Texture`? because the user might do so.
// this is guaranteed a non-public internal type, so we are good. // this is guaranteed a non-public internal type, so we are good.
surface surface
.user_data .and_then(|surface| surface.user_data.get::<Rc<Gles2TextureInternal>>().cloned())
.get::<Rc<Gles2TextureInternal>>()
.cloned()
.unwrap_or_else(|| { .unwrap_or_else(|| {
let mut tex = 0; let mut tex = 0;
unsafe { self.gl.GenTextures(1, &mut tex) }; unsafe { self.gl.GenTextures(1, &mut tex) };
@ -571,7 +569,7 @@ impl Gles2Renderer {
.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 upload_full { if upload_full || damage.is_empty() {
trace!(self.logger, "Uploading shm texture for {:?}", buffer); trace!(self.logger, "Uploading shm texture for {:?}", buffer);
self.gl.TexImage2D( self.gl.TexImage2D(
ffi::TEXTURE_2D, ffi::TEXTURE_2D,
@ -585,11 +583,7 @@ impl Gles2Renderer {
slice.as_ptr().offset(offset as isize) as *const _, slice.as_ptr().offset(offset as isize) as *const _,
); );
} else { } else {
for region in surface.damage.iter().map(|dmg| match dmg { for region in damage.iter() {
Damage::Buffer(rect) => *rect,
// TODO also apply transformations
Damage::Surface(rect) => rect.scale(surface.buffer_scale),
}) {
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);
@ -945,13 +939,14 @@ impl Renderer for Gles2Renderer {
fn import_buffer( fn import_buffer(
&mut self, &mut self,
buffer: &wl_buffer::WlBuffer, buffer: &wl_buffer::WlBuffer,
surface: &SurfaceAttributes, surface: Option<&SurfaceAttributes>,
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() {
self.import_egl(&buffer, egl.unwrap()) self.import_egl(&buffer, egl.unwrap())
} 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(&buffer, surface) self.import_shm(&buffer, surface, damage)
} else { } else {
Err(Gles2Error::UnknownBufferType) Err(Gles2Error::UnknownBufferType)
}?; }?;

View File

@ -11,12 +11,11 @@ use std::collections::HashSet;
use std::error::Error; use std::error::Error;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use crate::wayland::compositor::SurfaceAttributes; use crate::{utils::Rectangle, wayland::compositor::SurfaceAttributes};
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, 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"))]
@ -236,13 +235,16 @@ 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.
/// ///
/// If provided the `SurfaceAttributes` can be used to do caching of rendering resources and is generally recommended.
///
/// The `damage` argument provides a list of rectangle locating parts of the buffer that need to be updated. When provided /// 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. /// with an empty list `&[]`, the renderer is allowed 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,
surface: &SurfaceAttributes, surface: Option<&SurfaceAttributes>,
damage: &[Rectangle],
egl: Option<&EGLBufferReader>, egl: Option<&EGLBufferReader>,
) -> Result<Self::TextureId, Self::Error>; ) -> Result<Self::TextureId, Self::Error>;