From 8e548c8c54fca6c33d2dd466a9f30c94e14535f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Torr=C3=B3?= Date: Tue, 23 Jun 2026 10:25:45 +0200 Subject: [PATCH] :bug: Fix blank tiles and atlas crash on render-wasm zoom/pan (#10367) * :bug: Fix missing tiles on page switch and pan/zoom end * :bug: Fix blank tiles and atlas crash on render-wasm zoom/pan --- render-wasm/src/main.rs | 6 ++++-- render-wasm/src/render/surfaces.rs | 14 ++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 2f7503d181..bcdd9bf28a 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -107,13 +107,14 @@ pub extern "C" fn set_canvas_background(raw_color: u32) -> Result<()> { #[wasm_error] pub extern "C" fn render(timestamp: i32, flags: u8) -> Result { with_state!(state, { + let render_state = get_render_state(); state.rebuild_touched_tiles(); // Drain the throttled modifier-tile invalidation accumulated // since the previous rAF. set_modifiers skips this work during // interactive_transform; we do it once here, with the current // modifier set, so the cost is paid once per rAF rather than // once per pointer move. - if get_render_state().options.is_interactive_transform() { + if render_state.options.is_interactive_transform() { // Collect into an owned Vec to release the immutable borrow on // `state.shapes` before the mutable `rebuild_modifier_tiles` call. let ids = state.shapes.modifier_ids().to_vec(); @@ -121,7 +122,8 @@ pub extern "C" fn render(timestamp: i32, flags: u8) -> Result { state.rebuild_modifier_tiles(&ids)?; } } - let frame_type = if flags & RenderFlag::Partial as u8 == RenderFlag::Partial as u8 { + let is_partial = flags & RenderFlag::Partial as u8 == RenderFlag::Partial as u8; + let frame_type = if is_partial && !render_state.preserve_target_during_render { state .continue_render_loop(timestamp) .map_err(|_| Error::RecoverableError("Error rendering".to_string()))? diff --git a/render-wasm/src/render/surfaces.rs b/render-wasm/src/render/surfaces.rs index 28210c6517..dc39595e96 100644 --- a/render-wasm/src/render/surfaces.rs +++ b/render-wasm/src/render/surfaces.rs @@ -1631,15 +1631,13 @@ impl TileTextureCache { } pub fn add(&mut self, tile_viewbox: &TileViewbox, tile: &Tile) -> TileAtlasTextureRef { - if self.grid.len() > TEXTURES_CACHE_CAPACITY { - // First we try to remove the obsolete tiles. - self.gc(); - } + // Evict against the real slot count (`provider.length`), not the + // hardcoded capacity — otherwise the guard never fires and the atlas + // fills up until `allocate()` has no slot left. + let capacity = self.provider.length.min(TEXTURES_CACHE_CAPACITY); - // If we still have a texture capacity problem, then - // we try to remove all of those tiles that aren't - // visible. - if self.grid.len() > TEXTURES_CACHE_CAPACITY { + if self.grid.len() >= capacity { + self.gc(); self.gc_non_visible(tile_viewbox); }