mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 19:28:12 +00:00
🎉 Scaffold drag-overlay fast path
This commit is contained in:
parent
f331325941
commit
3296ca0303
@ -461,6 +461,23 @@ pub extern "C" fn set_modifiers_start() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Toggle the drag-overlay fast path. When enabled (default), the
|
||||
/// renderer bypasses the tile walker during interactive transforms by
|
||||
/// compositing cached snapshots on top of a hole-punched atlas. Turn
|
||||
/// OFF to fall back to the legacy per-tile walk (useful to isolate
|
||||
/// regressions or for screenshots).
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_drag_overlay_enabled(enabled: bool) -> Result<()> {
|
||||
with_state_mut!(state, {
|
||||
state.render_state.options.set_drag_overlay(enabled);
|
||||
if !enabled {
|
||||
state.render_state.drag_overlay = None;
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Leave interactive transform mode and cancel any pending async
|
||||
/// render scheduled under it. The caller is responsible for triggering
|
||||
/// a final full-quality render (typically via `_render`) once the
|
||||
@ -473,6 +490,7 @@ pub extern "C" fn set_modifiers_end() -> Result<()> {
|
||||
let opts = &mut state.render_state.options;
|
||||
opts.set_fast_mode(false);
|
||||
opts.set_interactive_transform(false);
|
||||
state.render_state.drag_overlay = None;
|
||||
state.render_state.cancel_animation_frame();
|
||||
performance::end_measure!("set_modifiers_end");
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
mod debug;
|
||||
pub mod drag_overlay;
|
||||
mod fills;
|
||||
pub mod filters;
|
||||
mod fonts;
|
||||
@ -334,6 +335,14 @@ pub(crate) struct RenderState {
|
||||
/// Cleared at the beginning of a render pass; set to true after we clear Cache the first
|
||||
/// time we are about to blit a tile into Cache for this pass.
|
||||
pub cache_cleared_this_render: bool,
|
||||
/// Fast-path state for interactive drag / resize / rotate gestures.
|
||||
/// `None` outside gestures. When populated, the walker excludes the
|
||||
/// shapes in `shape_ids` while rebuilding the atlas backdrop, and the
|
||||
/// hot render path blits the cached snapshots on top of the
|
||||
/// hole-punched atlas in a single pass. See `drag_overlay` module
|
||||
/// docs for the full flow. Disabled entirely when
|
||||
/// `options.is_drag_overlay()` is `false`.
|
||||
pub drag_overlay: Option<drag_overlay::DragOverlay>,
|
||||
}
|
||||
|
||||
pub fn get_cache_size(viewbox: Viewbox, scale: f32, interest: i32) -> skia::ISize {
|
||||
@ -407,6 +416,7 @@ impl RenderState {
|
||||
preview_mode: false,
|
||||
export_context: None,
|
||||
cache_cleared_this_render: false,
|
||||
drag_overlay: None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -2604,6 +2614,19 @@ impl RenderState {
|
||||
|
||||
is_empty = false;
|
||||
|
||||
// Drag-overlay hole-punch: while the overlay is being built (snapshots
|
||||
// captured but the backdrop atlas not yet refreshed), skip every node
|
||||
// that is part of the selection so the atlas stores a clean backdrop
|
||||
// without the dragged shapes. Exports and already-ready overlays must
|
||||
// render every node normally.
|
||||
if !export {
|
||||
if let Some(overlay) = self.drag_overlay.as_ref() {
|
||||
if !overlay.backdrop_ready && overlay.shape_ids.contains(&node_id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let Some(element) = tree.get(&node_id) else {
|
||||
// The shape isn't available yet (likely still streaming in from WASM).
|
||||
// Skip it for this pass; a subsequent render will pick it up once present.
|
||||
|
||||
@ -22,6 +22,13 @@ pub struct RenderOptions {
|
||||
/// keeps per-frame flushing enabled (unlike pan/zoom, where
|
||||
/// `render_from_cache` drives target presentation).
|
||||
interactive_transform: bool,
|
||||
/// When ON, interactive transforms take a fast overlay path: the
|
||||
/// selected shapes are snapshotted once at gesture start, the atlas
|
||||
/// is hole-punched below them, and per-frame we blit the cached
|
||||
/// backdrop + snapshots with the current modifier matrix instead of
|
||||
/// walking the tile tree. Safe to toggle OFF to fall back to the
|
||||
/// tile-walker path.
|
||||
drag_overlay: bool,
|
||||
/// 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,
|
||||
@ -37,6 +44,7 @@ impl Default for RenderOptions {
|
||||
dpr: None,
|
||||
fast_mode: false,
|
||||
interactive_transform: false,
|
||||
drag_overlay: true,
|
||||
antialias_threshold: ANTIALIAS_THRESHOLD,
|
||||
viewport_interest_area_threshold: VIEWPORT_INTEREST_AREA_THRESHOLD,
|
||||
max_blocking_time_ms: MAX_BLOCKING_TIME_MS,
|
||||
@ -76,6 +84,17 @@ impl RenderOptions {
|
||||
self.interactive_transform = enabled;
|
||||
}
|
||||
|
||||
/// Drag overlay is a fast path taken while `interactive_transform`
|
||||
/// is active: selected shapes are cached once and composited over a
|
||||
/// hole-punched atlas backdrop, bypassing the tile walker entirely.
|
||||
pub fn is_drag_overlay(&self) -> bool {
|
||||
self.drag_overlay
|
||||
}
|
||||
|
||||
pub fn set_drag_overlay(&mut self, enabled: bool) {
|
||||
self.drag_overlay = enabled;
|
||||
}
|
||||
|
||||
/// True only when the viewport is the one being moved (pan/zoom)
|
||||
/// and the dedicated `render_from_cache` path owns Target
|
||||
/// presentation. In this mode `process_animation_frame` must not
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user