anvil: Properly free textures
This commit is contained in:
parent
85bef5fec6
commit
0661ebebb8
|
@ -1,5 +1,5 @@
|
|||
#[cfg(feature = "egl")]
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{cell::RefCell, rc::Rc, sync::mpsc::Sender};
|
||||
|
||||
#[cfg(feature = "udev")]
|
||||
use smithay::backend::renderer::{Renderer, Texture};
|
||||
|
@ -86,6 +86,7 @@ impl BufferUtils {
|
|||
Ok(BufferTextures {
|
||||
buffer,
|
||||
textures: HashMap::new(),
|
||||
callbacks: HashMap::new(),
|
||||
egl: egl_buffer, // I guess we need to keep this alive ?
|
||||
})
|
||||
}
|
||||
|
@ -103,6 +104,7 @@ impl BufferUtils {
|
|||
pub struct BufferTextures<T> {
|
||||
buffer: WlBuffer,
|
||||
pub textures: HashMap<dev_t, T>,
|
||||
callbacks: HashMap<dev_t, Sender<T>>,
|
||||
#[cfg(feature = "egl")]
|
||||
egl: Option<EGLBuffer>,
|
||||
}
|
||||
|
@ -110,10 +112,11 @@ pub struct BufferTextures<T> {
|
|||
#[cfg(feature = "udev")]
|
||||
impl<T: Texture> BufferTextures<T> {
|
||||
#[cfg(feature = "egl")]
|
||||
pub fn load_texture<'a, R: Renderer<Texture=T>>(
|
||||
pub fn load_texture<'a, R: Renderer<TextureId=T>>(
|
||||
&'a mut self,
|
||||
id: u64,
|
||||
renderer: &mut R,
|
||||
texture_destruction_callback: &Sender<T>,
|
||||
) -> Result<&'a T, R::Error> {
|
||||
if self.textures.contains_key(&id) {
|
||||
return Ok(&self.textures[&id]);
|
||||
|
@ -122,10 +125,13 @@ impl<T: Texture> BufferTextures<T> {
|
|||
if let Some(buffer) = self.egl.as_ref() {
|
||||
//EGL buffer
|
||||
let texture = renderer.import_egl(&buffer)?;
|
||||
self.textures.insert(id, texture);
|
||||
if let Some(old_texture) = self.textures.insert(id, texture) {
|
||||
let _ = renderer.destroy_texture(old_texture);
|
||||
}
|
||||
self.callbacks.insert(id, texture_destruction_callback.clone());
|
||||
Ok(&self.textures[&id])
|
||||
} else {
|
||||
self.load_shm_texture(id, renderer)
|
||||
self.load_shm_texture(id, renderer, texture_destruction_callback)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,22 +140,27 @@ impl<T: Texture> BufferTextures<T> {
|
|||
&'a mut self,
|
||||
id: u64,
|
||||
renderer: &mut R,
|
||||
texture_destruction_callback: &Sender<T>,
|
||||
) -> Result<&'a T, R::Error> {
|
||||
if self.textures.contains_key(&id) {
|
||||
return Ok(&self.textures[&id]);
|
||||
}
|
||||
|
||||
self.load_shm_texture(id, renderer)
|
||||
self.load_shm_texture(id, renderer, texture_destruction_callback)
|
||||
}
|
||||
|
||||
fn load_shm_texture<'a, R: Renderer<Texture=T>>(
|
||||
fn load_shm_texture<'a, R: Renderer<TextureId=T>>(
|
||||
&'a mut self,
|
||||
id: u64,
|
||||
renderer: &mut R,
|
||||
texture_destruction_callback: &Sender<T>,
|
||||
) -> Result<&'a T, R::Error> {
|
||||
let texture = renderer.import_shm(&self.buffer)?;
|
||||
|
||||
self.textures.insert(id, texture);
|
||||
if let Some(old_texture) = self.textures.insert(id, texture) {
|
||||
let _ = renderer.destroy_texture(old_texture)?;
|
||||
}
|
||||
self.callbacks.insert(id, texture_destruction_callback.clone());
|
||||
Ok(&self.textures[&id])
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +168,9 @@ impl<T: Texture> BufferTextures<T> {
|
|||
#[cfg(feature = "udev")]
|
||||
impl<T> Drop for BufferTextures<T> {
|
||||
fn drop(&mut self) {
|
||||
self.buffer.release()
|
||||
self.buffer.release();
|
||||
for (id, texture) in self.textures.drain() {
|
||||
self.callbacks.get(&id).unwrap().send(texture).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
sync::mpsc::Sender,
|
||||
};
|
||||
|
||||
use slog::Logger;
|
||||
|
@ -25,6 +26,7 @@ use crate::buffer_utils::{BufferUtils, BufferTextures};
|
|||
pub fn draw_cursor<R, E, T>(
|
||||
renderer: &mut R,
|
||||
renderer_id: u64,
|
||||
texture_destruction_callback: &Sender<T>,
|
||||
buffer_utils: &BufferUtils,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(x, y): (i32, i32),
|
||||
|
@ -32,7 +34,7 @@ pub fn draw_cursor<R, E, T>(
|
|||
log: &Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, TextureId=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -46,12 +48,13 @@ pub fn draw_cursor<R, E, T>(
|
|||
(0, 0)
|
||||
}
|
||||
};
|
||||
draw_surface_tree(renderer, renderer_id, buffer_utils, surface, (x - dx, y - dy), token, log);
|
||||
draw_surface_tree(renderer, renderer_id, texture_destruction_callback, buffer_utils, surface, (x - dx, y - dy), token, log);
|
||||
}
|
||||
|
||||
fn draw_surface_tree<R, E, T>(
|
||||
renderer: &mut R,
|
||||
renderer_id: u64,
|
||||
texture_destruction_callback: &Sender<T>,
|
||||
buffer_utils: &BufferUtils,
|
||||
root: &wl_surface::WlSurface,
|
||||
location: (i32, i32),
|
||||
|
@ -59,7 +62,7 @@ fn draw_surface_tree<R, E, T>(
|
|||
log: &Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, TextureId=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -72,7 +75,7 @@ fn draw_surface_tree<R, E, T>(
|
|||
let mut data = data.borrow_mut();
|
||||
if data.texture.is_none() {
|
||||
if let Some(buffer) = data.current_state.buffer.take() {
|
||||
match buffer_utils.load_buffer::<R::Texture>(buffer) {
|
||||
match buffer_utils.load_buffer::<R::TextureId>(buffer) {
|
||||
Ok(m) => data.texture = Some(Box::new(m) as Box<dyn std::any::Any + 'static>),
|
||||
// there was an error reading the buffer, release it, we
|
||||
// already logged the error
|
||||
|
@ -133,7 +136,7 @@ fn draw_surface_tree<R, E, T>(
|
|||
x += sub_x;
|
||||
y += sub_y;
|
||||
}
|
||||
let texture = buffer_textures.load_texture(renderer_id, renderer).unwrap();
|
||||
let texture = buffer_textures.load_texture(renderer_id, renderer, texture_destruction_callback).unwrap();
|
||||
renderer.render_texture_at(texture, (x, y), Transform::Normal /* TODO */, 1.0);
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +148,7 @@ fn draw_surface_tree<R, E, T>(
|
|||
pub fn draw_windows<R, E, T>(
|
||||
renderer: &mut R,
|
||||
renderer_id: u64,
|
||||
texture_destruction_callback: &Sender<T>,
|
||||
buffer_utils: &BufferUtils,
|
||||
window_map: &MyWindowMap,
|
||||
output_rect: Option<Rectangle>,
|
||||
|
@ -152,7 +156,7 @@ pub fn draw_windows<R, E, T>(
|
|||
log: &::slog::Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, TextureId=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -172,6 +176,7 @@ pub fn draw_windows<R, E, T>(
|
|||
draw_surface_tree(
|
||||
renderer,
|
||||
renderer_id,
|
||||
texture_destruction_callback,
|
||||
buffer_utils,
|
||||
&wl_surface,
|
||||
initial_place,
|
||||
|
@ -187,6 +192,7 @@ pub fn draw_windows<R, E, T>(
|
|||
pub fn draw_dnd_icon<R, E, T>(
|
||||
renderer: &mut R,
|
||||
renderer_id: u64,
|
||||
texture_destruction_callback: &Sender<T>,
|
||||
buffer_utils: &BufferUtils,
|
||||
surface: &wl_surface::WlSurface,
|
||||
(x, y): (i32, i32),
|
||||
|
@ -194,7 +200,7 @@ pub fn draw_dnd_icon<R, E, T>(
|
|||
log: &::slog::Logger,
|
||||
)
|
||||
where
|
||||
R: Renderer<Error=E, Texture=T>,
|
||||
R: Renderer<Error=E, TextureId=T>,
|
||||
E: std::error::Error,
|
||||
T: Texture + 'static,
|
||||
{
|
||||
|
@ -204,7 +210,7 @@ pub fn draw_dnd_icon<R, E, T>(
|
|||
"Trying to display as a dnd icon a surface that does not have the DndIcon role."
|
||||
);
|
||||
}
|
||||
draw_surface_tree(renderer, renderer_id, buffer_utils, surface, (x, y), token, log);
|
||||
draw_surface_tree(renderer, renderer_id, texture_destruction_callback, buffer_utils, surface, (x, y), token, log);
|
||||
}
|
||||
|
||||
pub fn schedule_initial_render<R: Renderer + 'static, Data: 'static>(
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
os::unix::io::{AsRawFd, RawFd},
|
||||
path::PathBuf,
|
||||
rc::Rc,
|
||||
sync::{atomic::Ordering, Arc, Mutex},
|
||||
sync::{atomic::Ordering, Arc, Mutex, mpsc},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
|
@ -494,6 +494,8 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
|||
&self.logger,
|
||||
)));
|
||||
|
||||
// we leak this texture (we would need to call `destroy_texture` on Drop of DrmRenderer),
|
||||
// but only on shutdown anyway, because we do not support hot-pluggin, so it does not really matter.
|
||||
let pointer_image = {
|
||||
let context = EGLContext::new_shared(&egl, &context, self.logger.clone()).unwrap();
|
||||
let mut renderer = unsafe { Gles2Renderer::new(context, self.logger.clone()).unwrap() };
|
||||
|
@ -508,6 +510,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
|||
buffer_utils: self.buffer_utils.clone(),
|
||||
compositor_token: self.compositor_token,
|
||||
backends: backends.clone(),
|
||||
texture_destruction_callback: mpsc::channel(),
|
||||
window_map: self.window_map.clone(),
|
||||
output_map: self.output_map.clone(),
|
||||
pointer_location: self.pointer_location.clone(),
|
||||
|
@ -647,6 +650,7 @@ pub struct DrmRenderer {
|
|||
buffer_utils: BufferUtils,
|
||||
compositor_token: CompositorToken<Roles>,
|
||||
backends: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
|
||||
texture_destruction_callback: (mpsc::Sender<Gles2Texture>, mpsc::Receiver<Gles2Texture>),
|
||||
window_map: Rc<RefCell<MyWindowMap>>,
|
||||
output_map: Rc<RefCell<Vec<MyOutput>>>,
|
||||
pointer_location: Rc<RefCell<(f64, f64)>>,
|
||||
|
@ -672,6 +676,7 @@ impl DrmRenderer {
|
|||
if let Some(surface) = self.backends.borrow().get(&crtc) {
|
||||
let result = DrmRenderer::render_surface(
|
||||
&mut *surface.borrow_mut(),
|
||||
&self.texture_destruction_callback.0,
|
||||
&self.buffer_utils,
|
||||
self.device_id,
|
||||
crtc,
|
||||
|
@ -739,12 +744,17 @@ impl DrmRenderer {
|
|||
self.window_map
|
||||
.borrow()
|
||||
.send_frames(self.start_time.elapsed().as_millis() as u32);
|
||||
|
||||
while let Ok(texture) = self.texture_destruction_callback.1.try_recv() {
|
||||
let _ = surface.borrow_mut().destroy_texture(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_surface(
|
||||
surface: &mut RenderSurface,
|
||||
texture_destruction_callback: &mpsc::Sender<Gles2Texture>,
|
||||
buffer_utils: &BufferUtils,
|
||||
device_id: dev_t,
|
||||
crtc: crtc::Handle,
|
||||
|
@ -777,6 +787,7 @@ impl DrmRenderer {
|
|||
draw_windows(
|
||||
surface,
|
||||
device_id,
|
||||
texture_destruction_callback,
|
||||
buffer_utils,
|
||||
window_map,
|
||||
Some(Rectangle {
|
||||
|
@ -800,7 +811,7 @@ impl DrmRenderer {
|
|||
{
|
||||
if let Some(ref wl_surface) = dnd_icon.as_ref() {
|
||||
if wl_surface.as_ref().is_alive() {
|
||||
draw_dnd_icon(surface, device_id, buffer_utils, wl_surface, (ptr_x, ptr_y), compositor_token.clone(), logger);
|
||||
draw_dnd_icon(surface, device_id, texture_destruction_callback, buffer_utils, wl_surface, (ptr_x, ptr_y), compositor_token.clone(), logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -819,6 +830,7 @@ impl DrmRenderer {
|
|||
draw_cursor(
|
||||
surface,
|
||||
device_id,
|
||||
texture_destruction_callback,
|
||||
buffer_utils,
|
||||
wl_surface,
|
||||
(ptr_x, ptr_y),
|
||||
|
|
|
@ -91,6 +91,7 @@ pub fn run_winit(
|
|||
|
||||
info!(log, "Initialization completed, starting the main loop.");
|
||||
|
||||
let (texture_send, texture_receive) = std::sync::mpsc::channel();
|
||||
while state.running.load(Ordering::SeqCst) {
|
||||
if input
|
||||
.dispatch_new_events(|event, _| state.process_input_event(event))
|
||||
|
@ -113,7 +114,7 @@ pub fn run_winit(
|
|||
renderer.clear([0.8, 0.8, 0.9, 1.0]).expect("Failed to clear frame");
|
||||
|
||||
// draw the windows
|
||||
draw_windows(&mut renderer, 0, &buffer_utils, &*state.window_map.borrow(), None, state.ctoken, &log);
|
||||
draw_windows(&mut renderer, 0, &texture_send, &buffer_utils, &*state.window_map.borrow(), None, state.ctoken, &log);
|
||||
|
||||
let (x, y) = *state.pointer_location.borrow();
|
||||
// draw the dnd icon if any
|
||||
|
@ -121,7 +122,7 @@ pub fn run_winit(
|
|||
let guard = state.dnd_icon.lock().unwrap();
|
||||
if let Some(ref surface) = *guard {
|
||||
if surface.as_ref().is_alive() {
|
||||
draw_dnd_icon(&mut renderer, 0, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
draw_dnd_icon(&mut renderer, 0, &texture_send, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +141,7 @@ pub fn run_winit(
|
|||
// draw as relevant
|
||||
if let CursorImageStatus::Image(ref surface) = *guard {
|
||||
renderer.window().set_cursor_visible(false);
|
||||
draw_cursor(&mut renderer, 0, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
draw_cursor(&mut renderer, 0, &texture_send, &buffer_utils, surface, (x as i32, y as i32), state.ctoken, &log);
|
||||
} else {
|
||||
renderer.window().set_cursor_visible(true);
|
||||
}
|
||||
|
@ -162,6 +163,10 @@ pub fn run_winit(
|
|||
display.borrow_mut().flush_clients(&mut state);
|
||||
state.window_map.borrow_mut().refresh();
|
||||
}
|
||||
|
||||
while let Ok(texture) = texture_receive.try_recv() {
|
||||
let _ = renderer.destroy_texture(texture);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup stuff
|
||||
|
|
Loading…
Reference in New Issue