Fix disappearing images or panics when hiding and showing a window with wayland

Properly release GL resource when unmapping a window and detect stale
cache indices using a generation count. This fixes the disappearing
images (GL textures would be invalid and need to be re-created) as well
as the panics when an item's cache index ended up being re-used because
some other item was drawn first and allocated that indices. The latter
is fixed by using a generational counter on the cache that's bumped when
clearing, instead of a single "cache_ok" bool.
This commit is contained in:
Simon Hausmann 2021-05-28 09:11:03 +02:00
parent 9503ba69b3
commit d4385280eb
4 changed files with 64 additions and 10 deletions

View file

@ -25,8 +25,10 @@ use std::cell::{Cell, RefCell};
pub struct CachedRenderingData {
/// Used and modified by the backend, should be initialized to 0 by the user code
pub(crate) cache_index: Cell<usize>,
/// Set to false initially and when changes happen that require updating the cache
pub(crate) cache_ok: Cell<bool>,
/// Used and modified by the backend, should be initilized to 0 by the user code.
/// The backend compares this generation against the one of the cache to verify
/// the validity of the cache_index field.
pub(crate) cache_generation: Cell<usize>,
}
impl CachedRenderingData {
@ -38,7 +40,7 @@ impl CachedRenderingData {
cache: &mut RenderingCache<T>,
update_fn: impl FnOnce() -> T,
) -> T {
if self.cache_ok.get() {
if self.cache_generation.get() == cache.generation() {
let index = self.cache_index.get();
if let Some(existing_entry) = cache.get_mut(index) {
if let Some(data) =
@ -48,12 +50,9 @@ impl CachedRenderingData {
}
return existing_entry.data.clone();
}
// We may see cache_ok == true but get() on the cache failed with our index. That can
// only happen when the entire cache was destroyed in the meantime (through show and hide),
// in which case we re-allocate.
}
self.cache_index.set(cache.insert(crate::graphics::CachedGraphicsData::new(update_fn)));
self.cache_ok.set(true);
self.cache_generation.set(cache.generation());
cache.get(self.cache_index.get()).unwrap().data.clone()
}
@ -61,10 +60,10 @@ impl CachedRenderingData {
/// exists, i.e. if any data was ever cached. This is typically called by the graphics backend's
/// implementation of the release_item_graphics_cache function.
pub fn release<T>(&self, cache: &mut RenderingCache<T>) {
if self.cache_ok.get() {
if self.cache_generation.get() == cache.generation() {
let index = self.cache_index.get();
cache.remove(index);
self.cache_ok.set(false);
self.cache_generation.set(0);
}
}
}