Merge pull request #276 from cmeissl/renderer/v4-fix-egl-drm-rendering

disable texture cache for egl imports
This commit is contained in:
Victor Brekenfeld 2021-05-23 21:58:01 +02:00 committed by GitHub
commit e5a1afd306
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 73 additions and 59 deletions

View File

@ -2,8 +2,8 @@
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use std::cell::RefCell; use std::cell::RefCell;
use std::convert::TryFrom;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom;
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt; use std::fmt;
use std::ptr; use std::ptr;
@ -25,20 +25,17 @@ use crate::backend::allocator::{
Format, Format,
}; };
use crate::backend::egl::{ use crate::backend::egl::{
ffi::egl::{self as ffi_egl, types::EGLImage}, EGLContext, EGLSurface, ffi::egl::{self as ffi_egl, types::EGLImage},
Format as EGLFormat, MakeCurrentError, EGLContext, EGLSurface, Format as EGLFormat, MakeCurrentError,
}; };
use crate::backend::SwapBuffersError; use crate::backend::SwapBuffersError;
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use crate::{ use crate::{backend::egl::display::EGLBufferReader, wayland::compositor::Damage};
backend::egl::display::EGLBufferReader,
wayland::compositor::Damage,
};
#[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_buffer, wl_shm};
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
use wayland_commons::user_data::UserDataMap; use wayland_commons::user_data::UserDataMap;
#[cfg(feature = "wayland_frontend")]
use wayland_server::protocol::{wl_buffer, wl_shm};
#[allow(clippy::all, missing_docs)] #[allow(clippy::all, missing_docs)]
pub mod ffi { pub mod ffi {
@ -78,10 +75,14 @@ struct Gles2TextureInternal {
impl Drop for Gles2TextureInternal { impl Drop for Gles2TextureInternal {
fn drop(&mut self) { fn drop(&mut self) {
let _ = self.destruction_callback_sender.send(CleanupResource::Texture(self.texture)); let _ = self
.destruction_callback_sender
.send(CleanupResource::Texture(self.texture));
if let Some(images) = self.egl_images.take() { if let Some(images) = self.egl_images.take() {
for image in images { for image in images {
let _ = self.destruction_callback_sender.send(CleanupResource::EGLImage(image)); let _ = self
.destruction_callback_sender
.send(CleanupResource::EGLImage(image));
} }
} }
} }
@ -245,8 +246,9 @@ impl From<Gles2Error> for SwapBuffersError {
| x @ Gles2Error::GLExtensionNotSupported(_) | x @ Gles2Error::GLExtensionNotSupported(_)
| x @ Gles2Error::UnconstraintRenderingOperation => SwapBuffersError::ContextLost(Box::new(x)), | x @ Gles2Error::UnconstraintRenderingOperation => SwapBuffersError::ContextLost(Box::new(x)),
Gles2Error::ContextActivationError(err) => err.into(), Gles2Error::ContextActivationError(err) => err.into(),
x @ Gles2Error::FramebufferBindingError x @ Gles2Error::FramebufferBindingError | x @ Gles2Error::BindBufferEGLError(_) => {
| x @ Gles2Error::BindBufferEGLError(_) => SwapBuffersError::TemporaryFailure(Box::new(x)), SwapBuffersError::TemporaryFailure(Box::new(x))
}
} }
} }
} }
@ -471,7 +473,8 @@ 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.retain(|entry, tex| entry.buffer.as_ref().is_alive()); self.textures
.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 {
CleanupResource::Texture(texture) => unsafe { CleanupResource::Texture(texture) => unsafe {
@ -479,7 +482,7 @@ impl Gles2Renderer {
}, },
CleanupResource::EGLImage(image) => unsafe { CleanupResource::EGLImage(image) => unsafe {
ffi_egl::DestroyImageKHR(**self.egl.display.display, image); ffi_egl::DestroyImageKHR(**self.egl.display.display, image);
} },
} }
} }
Ok(()) Ok(())
@ -534,7 +537,13 @@ impl Gles2Renderer {
egl_images: None, egl_images: None,
destruction_callback_sender: self.destruction_callback_sender.clone(), destruction_callback_sender: self.destruction_callback_sender.clone(),
})); }));
self.textures.insert(BufferEntry { id: buffer.as_ref().id(), buffer: buffer.clone() }, texture.clone()); self.textures.insert(
BufferEntry {
id: buffer.as_ref().id(),
buffer: buffer.clone(),
},
texture.clone(),
);
texture texture
}); });
@ -598,53 +607,55 @@ impl Gles2Renderer {
return Err(Gles2Error::GLExtensionNotSupported(&["GL_OES_EGL_image"])); return Err(Gles2Error::GLExtensionNotSupported(&["GL_OES_EGL_image"]));
} }
self.existing_texture(buffer)?.map(Ok).unwrap_or_else(|| { // We can not use the caching logic for textures here as the
self.make_current()?; // egl buffers a potentially managed external which will fail the
// clean up check if the buffer is still alive. For wl_drm the
// is_alive check will always return true and the cache entry
// will never be cleaned up.
self.make_current()?;
let egl = reader let egl = reader
.egl_buffer_contents(&buffer) .egl_buffer_contents(&buffer)
.map_err(Gles2Error::EGLBufferAccessError)?; .map_err(Gles2Error::EGLBufferAccessError)?;
let tex = self.import_egl_image( let tex = self.import_egl_image(egl.image(0).unwrap(), egl.format == EGLFormat::External, None)?;
egl.image(0).unwrap(),
egl.format == EGLFormat::External,
None,
)?;
let texture = Gles2Texture(Rc::new(Gles2TextureInternal { let texture = Gles2Texture(Rc::new(Gles2TextureInternal {
texture: tex, texture: tex,
texture_kind: match egl.format { texture_kind: match egl.format {
EGLFormat::RGB => 1, EGLFormat::RGB => 1,
EGLFormat::RGBA => 0, EGLFormat::RGBA => 0,
EGLFormat::External => 2, EGLFormat::External => 2,
_ => unreachable!("EGLBuffer currenly does not expose multi-planar buffers to us"), _ => unreachable!("EGLBuffer currenly does not expose multi-planar buffers to us"),
}, },
is_external: egl.format == EGLFormat::External, is_external: egl.format == EGLFormat::External,
y_inverted: egl.y_inverted, y_inverted: egl.y_inverted,
width: egl.width, width: egl.width,
height: egl.height, height: egl.height,
buffer: Some(buffer.clone()), buffer: Some(buffer.clone()),
egl_images: Some(egl.into_images()), egl_images: Some(egl.into_images()),
destruction_callback_sender: self.destruction_callback_sender.clone(), destruction_callback_sender: self.destruction_callback_sender.clone(),
})); }));
self.egl.unbind()?; self.egl.unbind()?;
self.textures.insert(BufferEntry { id: buffer.as_ref().id(), buffer: buffer.clone() }, texture.clone()); Ok(texture)
Ok(texture)
})
} }
#[cfg(feature = "wayland_frontend")] #[cfg(feature = "wayland_frontend")]
fn existing_texture( fn existing_texture(&self, buffer: &wl_buffer::WlBuffer) -> Result<Option<Gles2Texture>, Gles2Error> {
&self, let existing_texture = self
buffer: &wl_buffer::WlBuffer, .textures
) -> Result<Option<Gles2Texture>, Gles2Error> { .iter()
let existing_texture = self.textures.iter().find(|(old_buffer, _)| { .find(|(old_buffer, _)| &old_buffer.buffer == buffer)
&old_buffer.buffer == buffer .map(|(_, tex)| tex.clone());
}).map(|(_, tex)| tex.clone());
if let Some(texture) = existing_texture { if let Some(texture) = existing_texture {
trace!(self.logger, "Re-using texture {:?} for {:?}", texture.0.texture, buffer); trace!(
self.logger,
"Re-using texture {:?} for {:?}",
texture.0.texture,
buffer
);
if texture.0.is_external { if texture.0.is_external {
Ok(Some(texture)) Ok(Some(texture))
} else { } else {
@ -917,10 +928,13 @@ impl Renderer for Gles2Renderer {
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, damage.and_then(|damage| match damage { self.import_shm(
Damage::Buffer(rect) => Some(*rect), &buffer,
_ => None damage.and_then(|damage| match damage {
})) Damage::Buffer(rect) => Some(*rect),
_ => None,
}),
)
} else { } else {
Err(Gles2Error::UnknownBufferType) Err(Gles2Error::UnknownBufferType)
}?; }?;
@ -1077,7 +1091,7 @@ impl Renderer for Gles2Renderer {
// In case of a drm atomic backend the fence could be supplied by using the // In case of a drm atomic backend the fence could be supplied by using the
// IN_FENCE_FD property. // IN_FENCE_FD property.
// See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#explicit-fencing-properties for // See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#explicit-fencing-properties for
// the topic on submitting a IN_FENCE_FD and the mesa kmskube example // the topic on submitting a IN_FENCE_FD and the mesa kmskube example
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c // https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c
// especially here // especially here
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L147 // https://gitlab.freedesktop.org/mesa/kmscube/-/blob/9f63f359fab1b5d8e862508e4e51c9dfe339ccb0/drm-atomic.c#L147