gles2: Use buffer damage to partially update texture

This commit is contained in:
Victor Brekenfeld 2021-05-16 23:07:48 +02:00
parent 2019be737f
commit b675b59e3b
1 changed files with 42 additions and 13 deletions

View File

@ -29,7 +29,7 @@ use crate::backend::egl::{
use crate::backend::SwapBuffersError; use crate::backend::SwapBuffersError;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use crate::wayland::compositor::SurfaceAttributes; use crate::wayland::compositor::{SurfaceAttributes, Damage};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_buffer, wl_shm}; use wayland_server::protocol::{wl_buffer, wl_shm};
@ -436,6 +436,7 @@ impl Gles2Renderer {
&mut self, &mut self,
buffer: &wl_buffer::WlBuffer, buffer: &wl_buffer::WlBuffer,
cache: &mut Option<Gles2Texture>, cache: &mut Option<Gles2Texture>,
mut damage: Option<crate::utils::Rectangle>,
) -> Result<Gles2Texture, Gles2Error> { ) -> Result<Gles2Texture, Gles2Error> {
use crate::wayland::shm::with_buffer_contents; use crate::wayland::shm::with_buffer_contents;
@ -465,6 +466,8 @@ impl Gles2Renderer {
let texture = cache.as_ref().cloned().unwrap_or_else(|| { let texture = cache.as_ref().cloned().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) };
// new texture, upload in full
damage = None;
Gles2Texture(Rc::new(Gles2TextureInternal { Gles2Texture(Rc::new(Gles2TextureInternal {
texture: tex, texture: tex,
texture_kind: shader_idx, texture_kind: shader_idx,
@ -476,6 +479,11 @@ impl Gles2Renderer {
})) }))
}); });
// new buffer has a different format, upload in full
if shader_idx != texture.0.texture_kind {
damage = None;
}
unsafe { unsafe {
self.gl.BindTexture(ffi::TEXTURE_2D, texture.0.texture); self.gl.BindTexture(ffi::TEXTURE_2D, texture.0.texture);
@ -484,17 +492,35 @@ 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);
self.gl.TexImage2D( if let Some(region) = damage {
ffi::TEXTURE_2D, self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.x);
0, self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, region.y);
gl_format as i32, self.gl.TexSubImage2D(
width, ffi::TEXTURE_2D,
height, 0,
0, region.x,
gl_format, region.y,
ffi::UNSIGNED_BYTE as u32, region.width,
slice.as_ptr().offset(offset as isize) as *const _, region.height,
); gl_format,
ffi::UNSIGNED_BYTE as u32,
slice.as_ptr().offset(offset as isize) as *const _,
);
self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, 0);
self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, 0);
} else {
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);
self.gl.BindTexture(ffi::TEXTURE_2D, 0); self.gl.BindTexture(ffi::TEXTURE_2D, 0);
@ -878,7 +904,10 @@ impl Renderer for Gles2Renderer {
}; };
self.import_egl(&buffer, egl.unwrap(), buffer_cache, texture_cache) self.import_egl(&buffer, egl.unwrap(), buffer_cache, texture_cache)
} 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, texture_cache) self.import_shm(&buffer, texture_cache, surface.and_then(|surf| match surf.damage {
Damage::Buffer(rect) => Some(rect),
_ => None,
}))
} else { } else {
Err(Gles2Error::UnknownBufferType) Err(Gles2Error::UnknownBufferType)
} }