gles2: Avoid reference cycle in buffer user_data
This commit is contained in:
parent
50b1996d57
commit
918241eb31
|
@ -3,10 +3,11 @@
|
||||||
#[cfg(feature = "wayland_frontend")]
|
#[cfg(feature = "wayland_frontend")]
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::Rc;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicUsize, Ordering},
|
atomic::{AtomicUsize, Ordering},
|
||||||
mpsc::{channel, Receiver, Sender},
|
mpsc::{channel, Receiver, Sender},
|
||||||
|
@ -111,6 +112,23 @@ struct Gles2Buffer {
|
||||||
_dmabuf: Dmabuf,
|
_dmabuf: Dmabuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BufferEntry {
|
||||||
|
id: u32,
|
||||||
|
buffer: wl_buffer::WlBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for BufferEntry {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
|
||||||
|
self.id.hash(hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialEq for BufferEntry {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.buffer == other.buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for BufferEntry {}
|
||||||
|
|
||||||
/// A renderer utilizing OpenGL ES 2
|
/// A renderer utilizing OpenGL ES 2
|
||||||
pub struct Gles2Renderer {
|
pub struct Gles2Renderer {
|
||||||
id: usize,
|
id: usize,
|
||||||
|
@ -120,7 +138,7 @@ pub struct Gles2Renderer {
|
||||||
current_projection: Option<Matrix3<f32>>,
|
current_projection: Option<Matrix3<f32>>,
|
||||||
extensions: Vec<String>,
|
extensions: Vec<String>,
|
||||||
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
programs: [Gles2Program; shaders::FRAGMENT_COUNT],
|
||||||
textures: Vec<Weak<Gles2TextureInternal>>,
|
textures: HashMap<BufferEntry, Gles2Texture>,
|
||||||
gl: ffi::Gles2,
|
gl: ffi::Gles2,
|
||||||
egl: EGLContext,
|
egl: EGLContext,
|
||||||
destruction_callback: Receiver<CleanupResource>,
|
destruction_callback: Receiver<CleanupResource>,
|
||||||
|
@ -404,7 +422,7 @@ impl Gles2Renderer {
|
||||||
target_buffer: None,
|
target_buffer: None,
|
||||||
target_surface: None,
|
target_surface: None,
|
||||||
buffers: Vec::new(),
|
buffers: Vec::new(),
|
||||||
textures: Vec::new(),
|
textures: HashMap::new(),
|
||||||
current_projection: None,
|
current_projection: None,
|
||||||
destruction_callback: rx,
|
destruction_callback: rx,
|
||||||
destruction_callback_sender: tx,
|
destruction_callback_sender: tx,
|
||||||
|
@ -429,7 +447,7 @@ impl Gles2Renderer {
|
||||||
|
|
||||||
fn cleanup(&mut self) -> Result<(), Gles2Error> {
|
fn cleanup(&mut self) -> Result<(), Gles2Error> {
|
||||||
self.make_current()?;
|
self.make_current()?;
|
||||||
self.textures.retain(|tex| tex.upgrade().is_some());
|
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 {
|
||||||
|
@ -492,7 +510,7 @@ 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.push(Rc::downgrade(&texture.0));
|
self.textures.insert(BufferEntry { id: buffer.as_ref().id(), buffer: buffer.clone() }, texture.clone());
|
||||||
texture
|
texture
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -585,7 +603,7 @@ impl Gles2Renderer {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.egl.unbind()?;
|
self.egl.unbind()?;
|
||||||
self.textures.push(Rc::downgrade(&texture.0));
|
self.textures.insert(BufferEntry { id: buffer.as_ref().id(), buffer: buffer.clone() }, texture.clone());
|
||||||
Ok(texture)
|
Ok(texture)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -594,25 +612,25 @@ impl Gles2Renderer {
|
||||||
&self,
|
&self,
|
||||||
buffer: &wl_buffer::WlBuffer,
|
buffer: &wl_buffer::WlBuffer,
|
||||||
) -> Result<Option<Gles2Texture>, Gles2Error> {
|
) -> Result<Option<Gles2Texture>, Gles2Error> {
|
||||||
let existing_texture = self.textures.iter().find(|tex| {
|
let existing_texture = self.textures.iter().find(|(old_buffer, _)| {
|
||||||
if let Some(texture) = tex.upgrade() {
|
&old_buffer.buffer == buffer
|
||||||
if let Some(old_buffer) = texture.buffer.as_ref() {
|
}).map(|(_, tex)| tex.clone());
|
||||||
return old_buffer == buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}).and_then(|tex| tex.upgrade());
|
|
||||||
|
|
||||||
if let Some(texture) = existing_texture {
|
if let Some(texture) = existing_texture {
|
||||||
if texture.is_external {
|
trace!(self.logger, "Re-using texture {:?} for {:?}", texture.0.texture, buffer);
|
||||||
Ok(Some(Gles2Texture(texture)))
|
if texture.0.is_external {
|
||||||
|
Ok(Some(texture))
|
||||||
} else {
|
} else {
|
||||||
if let Some(egl_images) = texture.egl_images.as_ref() {
|
if let Some(egl_images) = texture.0.egl_images.as_ref() {
|
||||||
self.make_current()?;
|
if egl_images[0] == ffi_egl::NO_IMAGE_KHR {
|
||||||
let tex = Some(texture.texture);
|
return Ok(None);
|
||||||
self.import_egl_image(egl_images[0], false, tex)?;
|
|
||||||
}
|
}
|
||||||
Ok(Some(Gles2Texture(texture)))
|
self.make_current()?;
|
||||||
|
let tex = Some(texture.0.texture);
|
||||||
|
self.import_egl_image(egl_images[0], false, tex)?;
|
||||||
|
self.egl.unbind()?;
|
||||||
|
}
|
||||||
|
Ok(Some(texture))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -637,8 +655,8 @@ impl Gles2Renderer {
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
self.gl.BindTexture(target, tex);
|
self.gl.BindTexture(target, tex);
|
||||||
|
|
||||||
self.gl.EGLImageTargetTexture2DOES(target, image);
|
self.gl.EGLImageTargetTexture2DOES(target, image);
|
||||||
|
self.gl.BindTexture(target, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(tex)
|
Ok(tex)
|
||||||
|
|
Loading…
Reference in New Issue