Browse Source

Fixed bounds performance issue and non updating canvases

flabbet 10 months ago
parent
commit
1651feb1e2

+ 12 - 0
src/ChunkyImageLib/ChunkyImage.cs

@@ -60,6 +60,9 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
     private bool disposed = false;
     private readonly object lockObject = new();
     private int commitCounter = 0;
+    
+    private RectI cachedPreciseBounds = RectI.Empty;
+    private int lastBoundsCacheHash = -1;
 
     public const int FullChunkSize = ChunkPool.FullChunkSize;
     private static Paint ClippingPaint { get; } = new Paint() { BlendMode = BlendMode.DstIn };
@@ -189,11 +192,17 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
         {
             ThrowIfDisposed();
 
+            if (lastBoundsCacheHash == GetCacheHash())
+            {
+                return cachedPreciseBounds;
+            }
+
             var chunkSize = suggestedResolution.PixelSize();
             var multiplier = suggestedResolution.Multiplier();
             RectI scaledCommittedSize = (RectI)(new RectD(VecI.Zero, CommittedSize * multiplier)).RoundOutwards();
 
             RectI? preciseBounds = null;
+            
             foreach (var (chunkPos, fullResChunk) in committedChunks[ChunkResolution.Full])
             {
                 if (committedChunks[suggestedResolution].TryGetValue(chunkPos, out Chunk? requestedResChunk))
@@ -228,6 +237,9 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
             preciseBounds = (RectI?)preciseBounds?.Scale(suggestedResolution.InvertedMultiplier()).RoundOutwards();
             preciseBounds = preciseBounds?.Intersect(new RectI(preciseBounds.Value.Pos, CommittedSize));
 
+            cachedPreciseBounds = preciseBounds.GetValueOrDefault();
+            lastBoundsCacheHash = GetCacheHash();
+            
             return preciseBounds;
         }
     }

+ 3 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -82,18 +82,17 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         return (GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage).LatestSize;
     }
 
-    protected internal override void DrawLayer(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear, bool useFilters = true)
+    protected internal override void DrawLayer(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool useFilters = true)
     {
         int scaled = workingSurface.Canvas.Save();
         float multiplier = (float)ctx.ChunkResolution.InvertedMultiplier();
         workingSurface.Canvas.Scale(multiplier, multiplier);
-        base.DrawLayer(ctx, workingSurface, shouldClear, useFilters);
+        base.DrawLayer(ctx, workingSurface, useFilters);
         
         workingSurface.Canvas.RestoreToCount(scaled);
     }
 
     protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
-        bool shouldClear,
         Paint paint)
     {
         workingSurface.Canvas.DrawSurface(renderedSurfaces[ctx.ChunkResolution].DrawingSurface, VecI.Zero, paint); 
@@ -102,7 +101,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     // Draw with filters is a bit tricky since some filters sample data from chunks surrounding the chunk being drawn,
     // this is why we need to do intermediate drawing to a temporary surface and then apply filters to that surface
     protected override void DrawWithFilters(SceneObjectRenderContext context, DrawingSurface workingSurface,
-        bool shouldClear, Paint paint)
+        Paint paint)
     {
         // TODO: Implement non-chunk rendering
         /*var frameImage = GetFrameWithImage(context.FrameTime).Data as ChunkyImage;

+ 7 - 8
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LayerNode.cs

@@ -33,7 +33,6 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
         DrawingSurface target = sceneContext.TargetSurface;
 
         VecI targetSize = GetTargetSize(sceneContext);
-        bool shouldClear = Background.Value == null;
 
         /*if (FilterlessOutput.Connections.Count > 0)
         {
@@ -51,12 +50,12 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
             FilterlessOutput.Value = filterlessWorkingSurface;
         }*/
 
-        RenderImage(targetSize, sceneContext, target, shouldClear);
+        RenderContent(targetSize, sceneContext, target);
 
         Output.Value = target;
     }
 
-    private void RenderImage(VecI size, SceneObjectRenderContext context, DrawingSurface renderOnto, bool shouldClear)
+    private void RenderContent(VecI size, SceneObjectRenderContext context, DrawingSurface renderOnto)
     {
         if (Output.Connections.Count > 0)
         {
@@ -102,7 +101,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
 
     protected abstract VecI GetTargetSize(RenderContext ctx);
 
-    protected internal virtual void DrawLayer(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
+    protected internal virtual void DrawLayer(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
         bool useFilters = true)
     {
         blendPaint.Color = blendPaint.Color.WithAlpha((byte)Math.Round(Opacity.Value * 255));
@@ -110,19 +109,19 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
         if (useFilters && Filters.Value != null)
         {
             blendPaint.SetFilters(Filters.Value);
-            DrawWithFilters(ctx, workingSurface, shouldClear, blendPaint);
+            DrawWithFilters(ctx, workingSurface, blendPaint);
         }
         else
         {
             blendPaint.SetFilters(null);
-            DrawWithoutFilters(ctx, workingSurface, shouldClear, blendPaint);
+            DrawWithoutFilters(ctx, workingSurface, blendPaint);
         }
     }
 
-    protected abstract void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
+    protected abstract void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
         Paint paint);
 
-    protected abstract void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
+    protected abstract void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
         Paint paint);
 
     protected Texture TryInitWorkingSurface(VecI imageSize, ChunkResolution resolution, int id)

+ 2 - 17
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/VectorLayerNode.cs

@@ -47,17 +47,12 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
     public override VecD ScenePosition => ShapeData?.TransformedAABB.TopLeft ?? VecD.Zero;
     public override VecD SceneSize => ShapeData?.TransformedAABB.Size ?? VecD.Zero;
 
-    public override void Render(SceneObjectRenderContext sceneContext)
-    {
-        Rasterize(sceneContext.TargetSurface, sceneContext.ChunkResolution, blendPaint);
-    }
-
     protected override VecI GetTargetSize(RenderContext ctx)
     {
         return ctx.DocumentSize;
     }
 
-    protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
+    protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
         Paint paint)
     {
         if (ShapeData == null)
@@ -65,26 +60,16 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
             return;
         }
 
-        if (shouldClear)
-        {
-            workingSurface.Canvas.Clear();
-        }
-
         Rasterize(workingSurface, ctx.ChunkResolution, paint);
     }
 
-    protected override void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear, Paint paint)
+    protected override void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, Paint paint)
     {
         if (ShapeData == null)
         {
             return;
         }
 
-        if (shouldClear)
-        {
-            workingSurface.Canvas.Clear();
-        }
-
         Rasterize(workingSurface, ctx.ChunkResolution, paint);
     }
 

+ 2 - 2
src/PixiEditor.ChangeableDocument/Rendering/DocumentRenderer.cs

@@ -68,13 +68,13 @@ public class DocumentRenderer
         return toDrawOn;
     }*/
     
-    public void RenderChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime, IReadOnlyCollection<Guid> membersToUpdate)
+    public void RenderChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime)
     {
         try
         {
             Document.NodeGraph.TryTraverse((node =>
             {
-                if (node is IReadOnlyImageNode imageNode && membersToUpdate.Contains(imageNode.Id))
+                if (node is IReadOnlyImageNode imageNode)
                 {
                     imageNode.RenderChunk(chunkPos, resolution, frameTime);
                 }

+ 2 - 2
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -111,13 +111,13 @@ internal class ActionAccumulator
             if (DrawingBackendApi.Current.IsHardwareAccelerated)
             {
                 renderResult.AddRange(canvasUpdater.UpdateGatheredChunksSync(affectedAreas,
-                    undoBoundaryPassed || viewportRefreshRequest, document.SelectedMembers)); 
+                    undoBoundaryPassed || viewportRefreshRequest)); 
                 renderResult.AddRange(previewUpdater.UpdateGatheredChunksSync(affectedAreas, undoBoundaryPassed));
             }
             else
             {
                 renderResult.AddRange(await canvasUpdater.UpdateGatheredChunks(affectedAreas,
-                    undoBoundaryPassed || viewportRefreshRequest, document.SelectedMembers));
+                    undoBoundaryPassed || viewportRefreshRequest));
                 renderResult.AddRange(await previewUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed));
             }
 

+ 10 - 11
src/PixiEditor/Models/Rendering/CanvasUpdater.cs

@@ -71,18 +71,18 @@ internal class CanvasUpdater
     /// Don't call this outside ActionAccumulator
     /// </summary>
     public async Task<List<IRenderInfo>> UpdateGatheredChunks
-        (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed, IReadOnlyCollection<Guid> membersToRender)
+        (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
     {
-        return await Task.Run(() => Render(chunkGatherer, rerenderDelayed, membersToRender)).ConfigureAwait(true);
+        return await Task.Run(() => Render(chunkGatherer, rerenderDelayed)).ConfigureAwait(true);
     }
 
     /// <summary>
     /// Don't call this outside ActionAccumulator
     /// </summary>
     public List<IRenderInfo> UpdateGatheredChunksSync
-        (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed, IReadOnlyCollection<Guid> documentSelectedMembers)
+        (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
     {
-        return Render(chunkGatherer, rerenderDelayed, documentSelectedMembers);
+        return Render(chunkGatherer, rerenderDelayed);
     }
 
     private Dictionary<ChunkResolution, HashSet<VecI>> FindChunksVisibleOnViewports(bool onDelayed, bool all)
@@ -160,8 +160,7 @@ internal class CanvasUpdater
         }
     }
 
-    private List<IRenderInfo> Render(AffectedAreasGatherer chunkGatherer, bool rerenderDelayed,
-        IReadOnlyCollection<Guid> membersToRender)
+    private List<IRenderInfo> Render(AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
     {
         Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender =
             FindGlobalChunksToRerender(chunkGatherer, rerenderDelayed);
@@ -195,12 +194,12 @@ internal class CanvasUpdater
 
         List<IRenderInfo> infos = new();
         UpdateMainImage(chunksToRerender, updatingStoredChunks ? null : chunkGatherer.MainImageArea.GlobalArea.Value,
-            infos, membersToRender);
+            infos);
         return infos;
     }
 
     private void UpdateMainImage(Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender,
-        RectI? globalClippingRectangle, List<IRenderInfo> infos, IReadOnlyCollection<Guid> membersToRender)
+        RectI? globalClippingRectangle, List<IRenderInfo> infos)
     {
         if (chunksToRerender.Count == 0)
             return;
@@ -215,7 +214,7 @@ internal class CanvasUpdater
             
             foreach (var chunkPos in chunks)
             {
-                RenderChunk(chunkPos, resolution, membersToRender);
+                RenderChunk(chunkPos, resolution);
                 RectI chunkRect = new(chunkPos * chunkSize, new(chunkSize, chunkSize));
                 if (globalScaledClippingRectangle is RectI rect)
                     chunkRect = chunkRect.Intersect(rect);
@@ -328,8 +327,8 @@ internal class CanvasUpdater
         }
     }
 
-    private void RenderChunk(VecI chunkPos, ChunkResolution resolution, IReadOnlyCollection<Guid> membersToRender)
+    private void RenderChunk(VecI chunkPos, ChunkResolution resolution)
     {
-        doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameTime, membersToRender);
+        doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameTime);
     }
 }