diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index a6822c991e..cedf2e730d 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -525,7 +525,7 @@ impl RenderState { tiles, tile_viewbox: tiles::TileViewbox::new_with_interest( viewbox, - options.viewport_interest_area_threshold, + options.dpr_viewport_interest_area_threshold, 1.0, ), pending_tiles: PendingTiles::new_empty(), @@ -742,8 +742,11 @@ impl RenderState { } pub fn set_dpr(&mut self, dpr: f32) -> Result<()> { - if Some(dpr) != self.options.dpr { - self.options.dpr = Some(dpr); + // Only when this function returns true (it means the value + // was properly changed) the rest of the functions is called. + if self.options.set_dpr(dpr) { + self.tile_viewbox + .set_interest(self.options.dpr_viewport_interest_area_threshold); self.resize( self.viewbox.width.floor() as i32, self.viewbox.height.floor() as i32, @@ -758,11 +761,15 @@ impl RenderState { } pub fn set_viewport_interest_area_threshold(&mut self, value: i32) { - self.options.set_viewport_interest_area_threshold(value); - // The TileViewbox stores its own copy of `interest` (set at - // construction). Without propagating, options change wouldn't - // affect pending_tiles generation. - self.tile_viewbox.set_interest(value); + // Only when this function returns true (it means the value + // was changed properly) the tile_viewbox.set_interest is called. + if self.options.set_viewport_interest_area_threshold(value) { + // The TileViewbox stores its own copy of `interest` (set at + // construction). Without propagating, options change wouldn't + // affect pending_tiles generation. + self.tile_viewbox + .set_interest(self.options.dpr_viewport_interest_area_threshold); + } } pub fn set_node_batch_threshold(&mut self, value: i32) { @@ -786,8 +793,8 @@ impl RenderState { } pub fn resize(&mut self, width: i32, height: i32) -> Result<()> { - let dpr_width = (width as f32 * self.options.dpr()).floor() as i32; - let dpr_height = (height as f32 * self.options.dpr()).floor() as i32; + let dpr_width = (width as f32 * self.options.dpr).floor() as i32; + let dpr_height = (height as f32 * self.options.dpr).floor() as i32; self.surfaces .resize(&mut self.gpu_state, dpr_width, dpr_height)?; self.viewbox.set_wh(width as f32, height as f32); @@ -1739,7 +1746,7 @@ impl RenderState { // and drawing from it avoids mixing a partially-updated Cache surface with missing tiles. if self.options.is_fast_mode() && self.render_in_progress && self.surfaces.has_atlas() { self.surfaces - .draw_atlas_to_target(self.viewbox, self.options.dpr(), bg_color); + .draw_atlas_to_target(self.viewbox, self.options.dpr, bg_color); if self.options.is_debug_visible() { debug::render(self); @@ -1759,15 +1766,15 @@ impl RenderState { // Scale and translate the target according to the cached data let navigate_zoom = self.viewbox.zoom / self.cached_viewbox.zoom; - let interest = self.options.viewport_interest_area_threshold; + let interest = self.options.dpr_viewport_interest_area_threshold; let TileRect(start_tile_x, start_tile_y, _, _) = tiles::get_tiles_for_viewbox_with_interest( self.cached_viewbox, interest, cached_scale, ); - let offset_x = self.viewbox.area.left * self.cached_viewbox.zoom * self.options.dpr(); - let offset_y = self.viewbox.area.top * self.cached_viewbox.zoom * self.options.dpr(); + let offset_x = self.viewbox.area.left * self.cached_viewbox.zoom * self.options.dpr; + let offset_y = self.viewbox.area.top * self.cached_viewbox.zoom * self.options.dpr; let translate_x = (start_tile_x as f32 * tiles::TILE_SIZE) - offset_x; let translate_y = (start_tile_y as f32 * tiles::TILE_SIZE) - offset_y; @@ -1780,8 +1787,8 @@ impl RenderState { let cache_h = cache_dim.height as f32; // Viewport in target pixels. - let vw = (self.viewbox.width * self.options.dpr()).max(1.0); - let vh = (self.viewbox.height * self.options.dpr()).max(1.0); + let vw = (self.viewbox.width * self.options.dpr).max(1.0); + let vh = (self.viewbox.height * self.options.dpr).max(1.0); // Inverse-map viewport corners into cache coordinates. // target = (cache * navigate_zoom) translated by (translate_x, translate_y) (in cache coords). @@ -1809,7 +1816,7 @@ impl RenderState { if self.surfaces.has_atlas() { self.surfaces.draw_atlas_to_target( self.viewbox, - self.options.dpr(), + self.options.dpr, bg_color, ); @@ -1966,12 +1973,12 @@ impl RenderState { let viewbox_cache_size = get_cache_size( self.viewbox, scale, - self.options.viewport_interest_area_threshold, + self.options.dpr_viewport_interest_area_threshold, ); let cached_viewbox_cache_size = get_cache_size( self.cached_viewbox, scale, - self.options.viewport_interest_area_threshold, + self.options.dpr_viewport_interest_area_threshold, ); // Only resize cache if the new size is larger than the cached size // This avoids unnecessary surface recreations when the cache size decreases @@ -1980,7 +1987,7 @@ impl RenderState { { self.surfaces.resize_cache( viewbox_cache_size, - self.options.viewport_interest_area_threshold, + self.options.dpr_viewport_interest_area_threshold, )?; } @@ -3750,11 +3757,11 @@ impl RenderState { if let Some((_, export_scale)) = self.export_context { return export_scale; } - self.viewbox.zoom() * self.options.dpr() + self.viewbox.zoom() * self.options.dpr } pub fn get_cached_scale(&self) -> f32 { - self.cached_viewbox.zoom() * self.options.dpr() + self.cached_viewbox.zoom() * self.options.dpr } pub fn zoom_changed(&self) -> bool { diff --git a/render-wasm/src/render/options.rs b/render-wasm/src/render/options.rs index 40a3125ccd..0f80b28bcb 100644 --- a/render-wasm/src/render/options.rs +++ b/render-wasm/src/render/options.rs @@ -7,7 +7,7 @@ const SHOW_WASM_INFO: u32 = 0x08; // Render performance options // This is the extra area used for tile rendering (tiles beyond viewport). // Higher values pre-render more tiles, reducing empty squares during pan but using more memory. -const VIEWPORT_INTEREST_AREA_THRESHOLD: i32 = 3; +const VIEWPORT_INTEREST_AREA_THRESHOLD: i32 = 1; const MAX_BLOCKING_TIME_MS: i32 = 32; const NODE_BATCH_THRESHOLD: i32 = 3; const BLUR_DOWNSCALE_THRESHOLD: f32 = 8.0; @@ -15,7 +15,7 @@ const ANTIALIAS_THRESHOLD: f32 = 7.0; #[derive(Debug, Copy, Clone, PartialEq)] pub struct RenderOptions { pub flags: u32, - pub dpr: Option, + pub dpr: f32, fast_mode: bool, /// Active while the user is interacting with a shape (drag, resize, /// rotate). Implies `fast_mode` semantics for expensive effects but @@ -25,6 +25,7 @@ pub struct RenderOptions { /// Minimum on-screen size (CSS px at 1:1 zoom) above which vector antialiasing is enabled. pub antialias_threshold: f32, pub viewport_interest_area_threshold: i32, + pub dpr_viewport_interest_area_threshold: i32, pub max_blocking_time_ms: i32, pub node_batch_threshold: i32, pub blur_downscale_threshold: f32, @@ -34,11 +35,12 @@ impl Default for RenderOptions { fn default() -> Self { Self { flags: 0, - dpr: None, + dpr: 1.0, fast_mode: false, interactive_transform: false, antialias_threshold: ANTIALIAS_THRESHOLD, viewport_interest_area_threshold: VIEWPORT_INTEREST_AREA_THRESHOLD, + dpr_viewport_interest_area_threshold: VIEWPORT_INTEREST_AREA_THRESHOLD, max_blocking_time_ms: MAX_BLOCKING_TIME_MS, node_batch_threshold: NODE_BATCH_THRESHOLD, blur_downscale_threshold: BLUR_DOWNSCALE_THRESHOLD, @@ -64,6 +66,24 @@ impl RenderOptions { self.fast_mode = enabled; } + /// Updates the dpr viewport interest area threshold. + /// This function is updated when the dpr or the + /// viewport_interest_area_threshold is changed + fn update_dpr_viewport_interest_area_threshold(&mut self) { + self.dpr_viewport_interest_area_threshold = + (self.dpr * self.viewport_interest_area_threshold as f32).ceil() as i32; + } + + /// Sets the devicePixelRatio. + pub fn set_dpr(&mut self, value: f32) -> bool { + if value > 0.0 && self.dpr != value { + self.dpr = value; + self.update_dpr_viewport_interest_area_threshold(); + return true; + } + false + } + /// Interactive transform is ON while the user is dragging, resizing /// or rotating a shape. Callers use it to keep per-frame flushing /// enabled and to render visible tiles in a single frame so tiles @@ -84,10 +104,6 @@ impl RenderOptions { self.fast_mode && !self.interactive_transform } - pub fn dpr(&self) -> f32 { - self.dpr.unwrap_or(1.0) - } - pub fn is_text_editor_v3(&self) -> bool { self.flags & TEXT_EDITOR_V3 == TEXT_EDITOR_V3 } @@ -96,33 +112,44 @@ impl RenderOptions { self.flags & SHOW_WASM_INFO == SHOW_WASM_INFO } - pub fn set_antialias_threshold(&mut self, value: f32) { + pub fn set_antialias_threshold(&mut self, value: f32) -> bool { if value.is_finite() && value > 0.0 { self.antialias_threshold = value; + return true; } + false } - pub fn set_blur_downscale_threshold(&mut self, value: f32) { + pub fn set_blur_downscale_threshold(&mut self, value: f32) -> bool { if value.is_finite() && value > 0.0 { self.blur_downscale_threshold = value; + return true; } + false } - pub fn set_viewport_interest_area_threshold(&mut self, value: i32) { - if value >= 0 { + pub fn set_viewport_interest_area_threshold(&mut self, value: i32) -> bool { + if value >= 0 && self.viewport_interest_area_threshold != value { self.viewport_interest_area_threshold = value; + self.update_dpr_viewport_interest_area_threshold(); + return true; } + false } - pub fn set_node_batch_threshold(&mut self, value: i32) { + pub fn set_node_batch_threshold(&mut self, value: i32) -> bool { if value > 0 { self.node_batch_threshold = value; + return true; } + false } - pub fn set_max_blocking_time_ms(&mut self, value: i32) { + pub fn set_max_blocking_time_ms(&mut self, value: i32) -> bool { if value > 0 { self.max_blocking_time_ms = value; + return true; } + false } } diff --git a/render-wasm/src/render/text_editor.rs b/render-wasm/src/render/text_editor.rs index 10e6e11725..8c990942ec 100644 --- a/render-wasm/src/render/text_editor.rs +++ b/render-wasm/src/render/text_editor.rs @@ -21,7 +21,7 @@ pub fn render_overlay( }; canvas.save(); - let zoom = viewbox.zoom * options.dpr(); + let zoom = viewbox.zoom * options.dpr; canvas.scale((zoom, zoom)); canvas.translate((-viewbox.area.left, -viewbox.area.top)); diff --git a/render-wasm/src/render/ui.rs b/render-wasm/src/render/ui.rs index bb7cc72c0f..243d775812 100644 --- a/render-wasm/src/render/ui.rs +++ b/render-wasm/src/render/ui.rs @@ -11,7 +11,7 @@ pub fn render(render_state: &mut RenderState, shapes: ShapesPoolRef) { canvas.save(); let viewbox = render_state.viewbox; - let zoom = viewbox.zoom * render_state.options.dpr(); + let zoom = viewbox.zoom * render_state.options.dpr; canvas.scale((zoom, zoom));