only use 100%

This commit is contained in:
Alejandro Alonso 2026-04-06 11:29:31 +02:00
parent f1362ba73a
commit 55a70e7b88
3 changed files with 92 additions and 17 deletions

View File

@ -422,6 +422,21 @@ impl RenderState {
})
}
/// Device scale when workspace zoom is 100% (`viewbox.zoom == 1`): `1.0 * dpr`.
fn base_zoom_placeholder_scale_bits(&self) -> u32 {
(1.0_f32 * self.options.dpr()).to_bits()
}
/// Scale bits used to look up tile textures in the cache.
/// In `fast_mode`, always use the 100% zoom cache; otherwise use current scale.
fn tile_texture_cache_lookup_scale_bits(&self) -> u32 {
if self.options.is_fast_mode() {
self.base_zoom_placeholder_scale_bits()
} else {
self.get_scale().to_bits()
}
}
fn rect_union(a: Rect, b: Rect) -> Rect {
Rect::from_ltrb(
a.left().min(b.left()),
@ -1489,6 +1504,9 @@ impl RenderState {
target_world_rect,
current_scale,
current_scale_bits,
self.options
.is_fast_mode()
.then_some(self.base_zoom_placeholder_scale_bits()),
true,
);
}
@ -1576,9 +1594,14 @@ impl RenderState {
let _tile_start = performance::begin_timed_log!("tile_cache_update");
performance::begin_measure!("tile_cache");
let scale_bits = scale.to_bits();
self.pending_tiles
.update(&self.tile_viewbox, &self.surfaces, scale_bits);
let lookup_bits = self.tile_texture_cache_lookup_scale_bits();
self.pending_tiles.update(
&self.tile_viewbox,
&self.surfaces,
scale,
self.options.is_fast_mode(),
lookup_bits,
);
performance::end_measure!("tile_cache");
performance::end_timed_log!("tile_cache_update", _tile_start);
@ -2612,16 +2635,14 @@ impl RenderState {
while !should_stop {
if let Some(current_tile) = self.current_tile {
let scale = self.get_scale();
let scale_bits = scale.to_bits();
if self
.surfaces
.has_cached_tile_surface(current_tile, scale_bits)
{
let lookup_bits = self.tile_texture_cache_lookup_scale_bits();
let fast_mode = self.options.is_fast_mode();
if !fast_mode && self.surfaces.has_cached_tile_surface(current_tile, lookup_bits) {
performance::begin_measure!("render_shape_tree::cached");
let tile_rect = self.get_current_tile_bounds()?;
self.surfaces.draw_cached_tile_surface(
current_tile,
scale_bits,
lookup_bits,
tile_rect,
self.background_color,
);
@ -2646,7 +2667,8 @@ impl RenderState {
self.background_color,
target_world_rect,
scale,
scale_bits,
lookup_bits,
fast_mode.then_some(self.base_zoom_placeholder_scale_bits()),
true,
);
performance::begin_measure!("render_shape_tree::uncached");

View File

@ -566,6 +566,24 @@ impl Surfaces {
self.tiles.has(tile, scale_bits)
}
pub fn world_rect_has_any_tile_at_scale_bits(&self, world_rect: Rect, scale_bits: u32) -> bool {
let scale = f32::from_bits(scale_bits);
if !scale.is_finite() || scale <= 0.0 {
return false;
}
let tile_size_world = super::tiles::get_tile_size(scale);
let super::tiles::TileRect(sx, sy, ex, ey) =
super::tiles::get_tiles_for_rect(world_rect, tile_size_world);
for x in sx..=ex {
for y in sy..=ey {
if self.tiles.has_stale(Tile::from(x, y), scale_bits) {
return true;
}
}
}
false
}
pub fn cached_scale_bits(&self) -> Vec<u32> {
self.tiles.scale_bits().collect()
}
@ -670,6 +688,7 @@ impl Surfaces {
}
/// Draw a placeholder for a missing tile using cached tiles from other zoom levels.
/// If `forced_src_scale_bits` is set, only that scale is used as the source (used by fast_mode).
pub fn draw_tile_fallback_cross_zoom(
&mut self,
tile_viewbox: &TileViewbox,
@ -678,12 +697,15 @@ impl Surfaces {
target_world_rect: Rect,
target_scale: f32,
target_scale_bits: u32,
forced_src_scale_bits: Option<u32>,
debug_trace: bool,
) -> usize {
let Some(candidate_scale_bits) = self
.tiles
.best_fallback_scale_bits(target_scale, target_scale_bits)
else {
let Some(candidate_scale_bits) = (if let Some(bits) = forced_src_scale_bits {
Some(bits)
} else {
self.tiles
.best_fallback_scale_bits(target_scale, target_scale_bits)
}) else {
if debug_trace {
}
return 0;
@ -706,7 +728,12 @@ impl Surfaces {
for x in sx..=ex {
for y in sy..=ey {
let src_tile = Tile::from(x, y);
let Some(src_image) = self.tiles.get(src_tile, candidate_scale_bits) else {
let src_image_opt = if forced_src_scale_bits.is_some() {
self.tiles.get_stale(src_tile, candidate_scale_bits)
} else {
self.tiles.get(src_tile, candidate_scale_bits)
};
let Some(src_image) = src_image_opt else {
continue;
};
@ -833,6 +860,12 @@ impl TileTextureCache {
self.grid.contains_key(&key) && !self.removed.contains(&key)
}
/// Like `has` but ignores the `removed` tombstone (stale placeholder).
pub fn has_stale(&self, tile: Tile, scale_bits: u32) -> bool {
let key = TileCacheKey { tile, scale_bits };
self.grid.contains_key(&key)
}
fn gc(&mut self) {
println!("gc");
// Make a real remove
@ -896,6 +929,12 @@ impl TileTextureCache {
self.grid.get(&key)
}
/// Like `get` but returns the image even if it is marked as `removed`.
pub fn get_stale(&self, tile: Tile, scale_bits: u32) -> Option<&skia::Image> {
let key = TileCacheKey { tile, scale_bits };
self.grid.get(&key)
}
pub fn remove(&mut self, tile: Tile, scale_bits: u32) {
self.removed.insert(TileCacheKey { tile, scale_bits });
}

View File

@ -261,7 +261,14 @@ impl PendingTiles {
result
}
pub fn update(&mut self, tile_viewbox: &TileViewbox, surfaces: &Surfaces, scale_bits: u32) {
pub fn update(
&mut self,
tile_viewbox: &TileViewbox,
surfaces: &Surfaces,
current_scale: f32,
fast_mode: bool,
lookup_scale_bits: u32,
) {
self.list.clear();
// Generate spiral for the interest area (viewport + margin)
@ -279,7 +286,14 @@ impl PendingTiles {
for tile in spiral {
let is_visible = tile_viewbox.visible_rect.contains(&tile);
let is_cached = surfaces.has_cached_tile_surface(tile, scale_bits);
let is_cached = if fast_mode {
// fast_mode reads only 100% zoom cache; tile indices differ across scales,
// so decide cacheability by world rect coverage at the lookup scale.
let world_rect = super::tiles::get_tile_rect(tile, current_scale);
surfaces.world_rect_has_any_tile_at_scale_bits(world_rect, lookup_scale_bits)
} else {
surfaces.has_cached_tile_surface(tile, lookup_scale_bits)
};
match (is_visible, is_cached) {
(true, true) => visible_cached.push(tile),