renderer: Properly cache shm-resource surface-global
This commit is contained in:
parent
6bfe6e1f25
commit
67a9478293
|
@ -90,11 +90,7 @@ 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() {
|
||||||
let damage = attributes.damage.iter().map(|dmg| match dmg {
|
match renderer.import_buffer(&buffer, &attributes, egl_buffer_reader) {
|
||||||
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,13 @@ 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, utils::Rectangle};
|
use crate::{backend::SwapBuffersError};
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use crate::backend::egl::display::EGLBufferReader;
|
use crate::{
|
||||||
|
backend::egl::display::EGLBufferReader,
|
||||||
|
wayland::compositor::{Damage, SurfaceAttributes},
|
||||||
|
};
|
||||||
#[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")]
|
||||||
|
@ -150,7 +153,7 @@ pub struct Gles2Renderer {
|
||||||
extensions: Vec<String>,
|
extensions: Vec<String>,
|
||||||
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
textures: HashMap<BufferEntry, Gles2Texture>,
|
dmabuf_cache: HashMap<BufferEntry, Gles2Texture>,
|
||||||
egl: EGLContext,
|
egl: EGLContext,
|
||||||
gl: ffi::Gles2,
|
gl: ffi::Gles2,
|
||||||
destruction_callback: Receiver<CleanupResource>,
|
destruction_callback: Receiver<CleanupResource>,
|
||||||
|
@ -457,7 +460,7 @@ impl Gles2Renderer {
|
||||||
target_surface: None,
|
target_surface: None,
|
||||||
buffers: Vec::new(),
|
buffers: Vec::new(),
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
textures: HashMap::new(),
|
dmabuf_cache: HashMap::new(),
|
||||||
destruction_callback: rx,
|
destruction_callback: rx,
|
||||||
destruction_callback_sender: tx,
|
destruction_callback_sender: tx,
|
||||||
logger_ptr,
|
logger_ptr,
|
||||||
|
@ -482,7 +485,7 @@ impl Gles2Renderer {
|
||||||
fn cleanup(&mut self) -> Result<(), Gles2Error> {
|
fn cleanup(&mut self) -> Result<(), Gles2Error> {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
self.textures
|
self.dmabuf_cache
|
||||||
.retain(|entry, _tex| entry.buffer.as_ref().is_alive());
|
.retain(|entry, _tex| entry.buffer.as_ref().is_alive());
|
||||||
for resource in self.destruction_callback.try_iter() {
|
for resource in self.destruction_callback.try_iter() {
|
||||||
match resource {
|
match resource {
|
||||||
|
@ -503,7 +506,7 @@ impl Gles2Renderer {
|
||||||
fn import_shm(
|
fn import_shm(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &wl_buffer::WlBuffer,
|
buffer: &wl_buffer::WlBuffer,
|
||||||
mut damage: &[crate::utils::Rectangle],
|
surface: &SurfaceAttributes,
|
||||||
) -> Result<Gles2Texture, Gles2Error> {
|
) -> Result<Gles2Texture, Gles2Error> {
|
||||||
use crate::wayland::shm::with_buffer_contents;
|
use crate::wayland::shm::with_buffer_contents;
|
||||||
|
|
||||||
|
@ -530,31 +533,30 @@ impl Gles2Renderer {
|
||||||
format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
|
format => return Err(Gles2Error::UnsupportedPixelFormat(format)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let texture = self.existing_texture(&buffer)?.unwrap_or_else(|| {
|
let mut upload_full = false;
|
||||||
let mut tex = 0;
|
|
||||||
unsafe { self.gl.GenTextures(1, &mut tex) };
|
let texture = Gles2Texture(
|
||||||
// different buffer, upload in full
|
// why not store a `Gles2Texture`? because the user might do so.
|
||||||
damage = &[];
|
// this is guaranteed a non-public internal type, so we are good.
|
||||||
let texture = Gles2Texture(Rc::new(Gles2TextureInternal {
|
surface.user_data.get::<Rc<Gles2TextureInternal>>().cloned().unwrap_or_else(|| {
|
||||||
texture: tex,
|
let mut tex = 0;
|
||||||
texture_kind: shader_idx,
|
unsafe { self.gl.GenTextures(1, &mut tex) };
|
||||||
is_external: false,
|
// new texture, upload in full
|
||||||
y_inverted: false,
|
upload_full = true;
|
||||||
width: width as u32,
|
let texture = Rc::new(Gles2TextureInternal {
|
||||||
height: height as u32,
|
texture: tex,
|
||||||
buffer: Some(buffer.clone()),
|
texture_kind: shader_idx,
|
||||||
egl_images: None,
|
is_external: false,
|
||||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
y_inverted: false,
|
||||||
}));
|
width: width as u32,
|
||||||
self.textures.insert(
|
height: height as u32,
|
||||||
BufferEntry {
|
buffer: Some(buffer.clone()),
|
||||||
id: buffer.as_ref().id(),
|
egl_images: None,
|
||||||
buffer: buffer.clone(),
|
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||||
},
|
});
|
||||||
texture.clone(),
|
texture
|
||||||
);
|
})
|
||||||
texture
|
);
|
||||||
});
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.BindTexture(ffi::TEXTURE_2D, texture.0.texture);
|
self.gl.BindTexture(ffi::TEXTURE_2D, texture.0.texture);
|
||||||
|
@ -564,23 +566,44 @@ 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);
|
||||||
for region in damage {
|
|
||||||
trace!(self.logger, "Uploading partial shm texture for {:?}", buffer);
|
|
||||||
self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.x);
|
if upload_full {
|
||||||
self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, region.y);
|
trace!(self.logger, "Uploading shm texture for {:?}", buffer);
|
||||||
self.gl.TexSubImage2D(
|
self.gl.TexImage2D(
|
||||||
ffi::TEXTURE_2D,
|
ffi::TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
region.x,
|
gl_format as i32,
|
||||||
region.y,
|
width,
|
||||||
region.width,
|
height,
|
||||||
region.height,
|
0,
|
||||||
gl_format,
|
gl_format,
|
||||||
ffi::UNSIGNED_BYTE as u32,
|
ffi::UNSIGNED_BYTE as u32,
|
||||||
slice.as_ptr().offset(offset as isize) as *const _,
|
slice.as_ptr().offset(offset as isize) as *const _,
|
||||||
);
|
);
|
||||||
self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, 0);
|
} else {
|
||||||
self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, 0);
|
for region in surface.damage.iter().map(|dmg| match dmg {
|
||||||
|
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);
|
||||||
|
self.gl.PixelStorei(ffi::UNPACK_SKIP_PIXELS, region.x);
|
||||||
|
self.gl.PixelStorei(ffi::UNPACK_SKIP_ROWS, region.y);
|
||||||
|
self.gl.TexSubImage2D(
|
||||||
|
ffi::TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
region.x,
|
||||||
|
region.y,
|
||||||
|
region.width,
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
|
self.gl.PixelStorei(ffi::UNPACK_ROW_LENGTH, 0);
|
||||||
|
@ -632,14 +655,13 @@ impl Gles2Renderer {
|
||||||
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
destruction_callback_sender: self.destruction_callback_sender.clone(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.egl.unbind()?;
|
|
||||||
Ok(texture)
|
Ok(texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
fn existing_texture(&self, buffer: &wl_buffer::WlBuffer) -> Result<Option<Gles2Texture>, Gles2Error> {
|
fn existing_dmabuf_texture(&self, buffer: &wl_buffer::WlBuffer) -> Result<Option<Gles2Texture>, Gles2Error> {
|
||||||
let existing_texture = self
|
let existing_texture = self
|
||||||
.textures
|
.dmabuf_cache
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(old_buffer, _)| &old_buffer.buffer == buffer)
|
.find(|(old_buffer, _)| &old_buffer.buffer == buffer)
|
||||||
.map(|(_, tex)| tex.clone());
|
.map(|(_, tex)| tex.clone());
|
||||||
|
@ -917,7 +939,7 @@ impl Renderer for Gles2Renderer {
|
||||||
fn import_buffer(
|
fn import_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &wl_buffer::WlBuffer,
|
buffer: &wl_buffer::WlBuffer,
|
||||||
damage: &[Rectangle],
|
surface: &SurfaceAttributes,
|
||||||
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() {
|
||||||
|
@ -925,7 +947,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,
|
surface,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(Gles2Error::UnknownBufferType)
|
Err(Gles2Error::UnknownBufferType)
|
||||||
|
|
|
@ -13,6 +13,8 @@ use std::error::Error;
|
||||||
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};
|
||||||
|
#[cfg(feature = "wayland_frontend")]
|
||||||
|
use crate::wayland::compositor::SurfaceAttributes;
|
||||||
|
|
||||||
use crate::{backend::SwapBuffersError, utils::Rectangle};
|
use crate::{backend::SwapBuffersError, utils::Rectangle};
|
||||||
#[cfg(feature = "renderer_gl")]
|
#[cfg(feature = "renderer_gl")]
|
||||||
|
@ -240,7 +242,7 @@ pub trait Renderer {
|
||||||
fn import_buffer(
|
fn import_buffer(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &wl_buffer::WlBuffer,
|
buffer: &wl_buffer::WlBuffer,
|
||||||
damage: &[Rectangle],
|
surface: &SurfaceAttributes,
|
||||||
egl: Option<&EGLBufferReader>,
|
egl: Option<&EGLBufferReader>,
|
||||||
) -> Result<Self::TextureId, Self::Error>;
|
) -> Result<Self::TextureId, Self::Error>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue