From 949b80d9e97f4dd1a96f131ffdf7a6c1988af96d Mon Sep 17 00:00:00 2001 From: Samuel Selleck Date: Tue, 29 Oct 2024 16:42:32 -0700 Subject: [PATCH] keep track of failed context borrows --- pax-runtime-api/src/lib.rs | 2 +- pax-runtime/src/engine/mod.rs | 8 +-- .../src/engine/pax_pixels_render_context.rs | 56 +++++++++++++++---- pax-runtime/src/engine/piet_render_context.rs | 2 +- pax-runtime/src/properties.rs | 4 +- 5 files changed, 53 insertions(+), 19 deletions(-) diff --git a/pax-runtime-api/src/lib.rs b/pax-runtime-api/src/lib.rs index f2038ea5b..72880b4aa 100644 --- a/pax-runtime-api/src/lib.rs +++ b/pax-runtime-api/src/lib.rs @@ -71,7 +71,7 @@ pub trait RenderContext { fn layers(&self) -> usize; fn resize_layers_to(&mut self, layer_count: usize, dirty_canvases: Rc>>); fn clear(&mut self, layer: usize); - fn flush(&mut self, layer: usize); + fn flush(&mut self, layer: usize, dirty_canvases: Rc>>); fn resize(&mut self, width: usize, height: usize); } diff --git a/pax-runtime/src/engine/mod.rs b/pax-runtime/src/engine/mod.rs index 6f622882f..5923a693a 100644 --- a/pax-runtime/src/engine/mod.rs +++ b/pax-runtime/src/engine/mod.rs @@ -271,7 +271,6 @@ impl PaxEngine { /// a. find lowest node (last child of last node) /// b. start rendering, from lowest node on-up, throughout tree pub fn tick(&mut self) -> Vec { - // self.runtime_context.set_all_canvases_dirty(); // // 1. UPDATE NODES (properties, etc.). This part we should be able to // completely remove once reactive properties dirty-dag is a thing. @@ -299,7 +298,7 @@ impl PaxEngine { .borrow() .get(i) .cloned() - .unwrap_or(true) + .unwrap_or(false) { rcs.clear(i); } @@ -310,10 +309,11 @@ impl PaxEngine { .recurse_render_queue(&mut self.runtime_context, rcs); self.runtime_context.recurse_flush_queued_renders(rcs); + self.runtime_context.clear_all_dirty_canvases(); + for i in 0..rcs.layers() { - rcs.flush(i); + rcs.flush(i, Rc::clone(&self.runtime_context.dirty_canvases)); } - self.runtime_context.clear_all_dirty_canvases(); //dirtify the canvases that where created this frame for i in new_range { diff --git a/pax-runtime/src/engine/pax_pixels_render_context.rs b/pax-runtime/src/engine/pax_pixels_render_context.rs index 10378219b..0e98a33d1 100644 --- a/pax-runtime/src/engine/pax_pixels_render_context.rs +++ b/pax-runtime/src/engine/pax_pixels_render_context.rs @@ -8,6 +8,7 @@ pub struct PaxPixelsRenderer { layer_factory: Rc Pin>>>>>, image_map: HashMap, + failed_context_gets: RefCell>, } pub enum RenderLayerState { @@ -24,6 +25,7 @@ impl PaxPixelsRenderer { backends: Default::default(), layer_factory: Rc::new(layer_factory), image_map: Default::default(), + failed_context_gets: RefCell::new(vec![]), } } } @@ -34,10 +36,17 @@ impl PaxPixelsRenderer { match backends.get_mut(layer) { Some(layer_state) => match layer_state { RenderLayerState::Pending => { - log::warn!( - "tried to retrieve layer {} context that wasn't ready", - layer - ); + let mut failed_context_gets = self.failed_context_gets.borrow_mut(); + if failed_context_gets.len() <= layer { + failed_context_gets.resize(layer + 1, false); + } + failed_context_gets[layer] = true; + // this happens to often to be useful right now - how to handle asyncness + // better here feels important + // log::warn!( + // "tried to retrieve layer {} context that wasn't ready", + // layer + // ); } RenderLayerState::Ready(renderer) => f(renderer), }, @@ -155,13 +164,20 @@ impl RenderContext for PaxPixelsRenderer { let dirty_canvases = Rc::clone(&dirty_canvases); wasm_bindgen_futures::spawn_local(async move { let backend = (factory)(i).await; - if let (Some(change), Some(backend)) = - (backends.borrow_mut().get_mut(i), backend) - { - *change = RenderLayerState::Ready(backend); - if let Some(dirty_bit) = dirty_canvases.borrow_mut().get_mut(i) { - *dirty_bit = true; + match (backends.borrow_mut().get_mut(i), backend) { + (Some(change), Some(backend)) => { + *change = RenderLayerState::Ready(backend); + if let Some(dirty_bit) = dirty_canvases.borrow_mut().get_mut(i) { + *dirty_bit = true; + } } + (Some(_), None) => log::warn!( + "failed to set poll state to ready: backend failed to initialize" + ), + (None, Some(_)) => { + log::warn!("failed to set poll state to ready: layer doesn't exist anymore") + } + (None, None) => log::warn!("failed to set poll state to ready: layer doesn't exist AND backend failed to initialize") } }); } @@ -175,8 +191,26 @@ impl RenderContext for PaxPixelsRenderer { }); } - fn flush(&mut self, layer: usize) { + fn flush(&mut self, layer: usize, dirty_canvases: Rc>>) { + // HACK: GPU rendering currently doesn't correctly handle + // re-dirtyfying canvases that where created but not ready before + // being drawn to - maybe encapsulate canvas dirtifiation inside + // rendercontext? + if let Some(dirty_bit) = dirty_canvases.borrow_mut().get_mut(layer) { + *dirty_bit = true; + } + self.with_layer_context(layer, |context| { + if let Some(failed) = self.failed_context_gets.borrow_mut().get_mut(layer) { + if *failed { + if let Some(dirty_bit) = dirty_canvases.borrow_mut().get_mut(layer) { + // if we failed to draw to this layer last frame because the context wasn't + // vailable yet, set this canvas to dirty for next frame + *dirty_bit = true; + } + *failed = false; + } + } context.flush(); }); } diff --git a/pax-runtime/src/engine/piet_render_context.rs b/pax-runtime/src/engine/piet_render_context.rs index da029181f..ad6689354 100644 --- a/pax-runtime/src/engine/piet_render_context.rs +++ b/pax-runtime/src/engine/piet_render_context.rs @@ -131,7 +131,7 @@ impl api::RenderContext for PietRenderer { } } - fn flush(&mut self, _layer: usize) { + fn flush(&mut self, _layer: usize, _dirty_canvases: Rc>>) { // NOTE: used for GPU rendering to flush changes to the screen, not needed // during CPU rendering } diff --git a/pax-runtime/src/properties.rs b/pax-runtime/src/properties.rs index e8e6a883d..9ac5bfc06 100644 --- a/pax-runtime/src/properties.rs +++ b/pax-runtime/src/properties.rs @@ -153,7 +153,7 @@ impl RuntimeContext { pub fn resize_canvas_layers_to(&self, id: usize) { let mut dirty_canvases = borrow_mut!(self.dirty_canvases); - dirty_canvases.resize(id, false); + dirty_canvases.resize(id, true); } pub fn clear_all_dirty_canvases(&self) { @@ -171,7 +171,7 @@ impl RuntimeContext { } pub fn is_canvas_dirty(&self, id: &usize) -> bool { - *borrow!(self.dirty_canvases).get(*id).unwrap_or(&false) + *borrow!(self.dirty_canvases).get(*id).unwrap_or(&true) } pub fn set_all_canvases_dirty(&self) {