gemini feat: optimize drawing performance by caching layer styles during strokes and improve UI/UX for layer styles and menus, improved drop shadow
This commit is contained in:
@@ -126,7 +126,7 @@ impl Engine {
|
||||
pub fn begin_stroke(&mut self, layer_id: u64, x: f32, y: f32) {
|
||||
self.last_stroke_pos = Some((x, y, 1.0));
|
||||
self.sketch_history.clear();
|
||||
if let Some(layer) = self.document.get_layer_by_id(layer_id) {
|
||||
if let Some(layer) = self.document.get_layer_by_id_mut(layer_id) {
|
||||
let layer_pixels = (layer.width * layer.height * 4) as usize; // RGBA byte size
|
||||
let layer_size = (layer.width * layer.height) as usize; // pixel count (for mask)
|
||||
|
||||
@@ -143,6 +143,19 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
// Backup and clear layer.effects to disable expensive effect compositing during the stroke
|
||||
if !layer.effects.is_empty() {
|
||||
self.stroke_effects_backup = Some(layer.effects.clone());
|
||||
layer.effects.clear();
|
||||
// Clear the cache so it stops rendering the old effects immediately
|
||||
*layer.effects_cache.lock().unwrap() = None;
|
||||
}
|
||||
if !layer.styles.is_empty() {
|
||||
self.stroke_styles_backup = Some(layer.styles.clone());
|
||||
layer.styles.clear();
|
||||
*layer.effects_cache.lock().unwrap() = None;
|
||||
}
|
||||
|
||||
// Initialize last_stroke_bounds with brush radius around first point
|
||||
// Used for sub-rect snapshot in end_stroke (avoid 33MB clone on 4K)
|
||||
let tip = &self.current_tip;
|
||||
@@ -196,9 +209,20 @@ impl Engine {
|
||||
if let Some((id, before_shapes)) = self.stroke_before.take() {
|
||||
if id == layer_id {
|
||||
if let Some(idx) = self.document.layer_index_by_id(layer_id) {
|
||||
let layer = &self.document.layers[idx];
|
||||
let layer = &mut self.document.layers[idx];
|
||||
let lw = layer.width;
|
||||
let layer_pixels = (layer.width * layer.height * 4) as usize; // RGBA byte size
|
||||
// Restore layer effects from backup so they are re-composited correctly
|
||||
if let Some(backup) = self.stroke_effects_backup.take() {
|
||||
layer.effects = backup;
|
||||
}
|
||||
if let Some(backup) = self.stroke_styles_backup.take() {
|
||||
layer.styles = backup;
|
||||
}
|
||||
|
||||
if !layer.effects.is_empty() || !layer.styles.is_empty() {
|
||||
layer.effects_dirty.store(true, std::sync::atomic::Ordering::Release);
|
||||
}
|
||||
|
||||
// Take the pooled before buffer (no allocation)
|
||||
log::debug!("[end_stroke] layer_pixels={}, stroke_before_buf={:?}", layer_pixels, self.stroke_before_buf.as_ref().map(|b| b.len()));
|
||||
@@ -286,6 +310,7 @@ impl Engine {
|
||||
self.last_stroke_bounds = None;
|
||||
self.last_stroke_pos = None;
|
||||
self.below_cache_dirty = false;
|
||||
self.document.composite_dirty = true;
|
||||
if let Some(mask) = &mut self.active_stroke_mask {
|
||||
mask.fill(0);
|
||||
}
|
||||
@@ -297,6 +322,7 @@ impl Engine {
|
||||
self.last_stroke_pos = None;
|
||||
self.last_stroke_bounds = None;
|
||||
self.below_cache_dirty = false;
|
||||
self.document.composite_dirty = true;
|
||||
log::trace!("[end_stroke_async] fallback cleanup done, below_cache retained for reuse");
|
||||
if let Some(mask) = &mut self.active_stroke_mask {
|
||||
mask.fill(0);
|
||||
|
||||
Reference in New Issue
Block a user