Krzysztof Krysiński 1 nedēļu atpakaļ
vecāks
revīzija
2a1f39dcb9

+ 10 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Filter.cs

@@ -1,9 +1,10 @@
 using System.Diagnostics.Contracts;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
+using PixiEditor.Common;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph;
 
-public sealed class Filter : IDisposable
+public sealed class Filter : IDisposable, ICacheable
 {
     public Filter(ColorFilter? colorFilter, ImageFilter? imageFilter)
     {
@@ -45,4 +46,12 @@ public sealed class Filter : IDisposable
         ColorFilter?.Dispose();
         ImageFilter?.Dispose();
     }
+
+    public int GetCacheHash()
+    {
+        HashCode hash = new();
+        hash.Add(ColorFilter?.GetHashCode() ?? 0);
+        hash.Add(ImageFilter?.GetHashCode() ?? 0);
+        return hash.ToHashCode();
+    }
 }

+ 3 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/NodeGraph.cs

@@ -1,4 +1,5 @@
 using System.Collections.Immutable;
+using System.Diagnostics;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 using PixiEditor.ChangeableDocument.Rendering;
@@ -193,7 +194,8 @@ public class NodeGraph : IReadOnlyNodeGraph
         HashCode hash = new();
         foreach (var node in Nodes)
         {
-            hash.Add(node.GetCacheHash());
+            int nodeCache = node.GetCacheHash();
+            hash.Add(nodeCache);
         }
 
         return hash.ToHashCode();

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CacheTriggerFlags.cs

@@ -6,5 +6,6 @@ public enum CacheTriggerFlags
     None = 0,
     Inputs = 1,
     Timeline = 2,
-    All = Inputs | Timeline
+    RenderSize = 4,
+    All = Inputs | Timeline | RenderSize
 }

+ 5 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CreateImageNode.cs

@@ -30,6 +30,9 @@ public class CreateImageNode : Node
 
     private TextureCache textureCache = new();
 
+    protected override bool ExecuteOnlyOnCacheChange => true;
+    protected override CacheTriggerFlags CacheTrigger => CacheTriggerFlags.Inputs;
+
     public CreateImageNode()
     {
         Output = CreateOutput<Texture>(nameof(Output), "IMAGE", null);
@@ -57,7 +60,8 @@ public class CreateImageNode : Node
 
     private Texture Render(RenderContext context)
     {
-        var surface = textureCache.RequestTexture(0, (VecI)(Size.Value * context.ChunkResolution.Multiplier()), context.ProcessingColorSpace, false);
+        int id = (Size.Value * context.ChunkResolution.Multiplier()).GetHashCode();
+        var surface = textureCache.RequestTexture(id, (VecI)(Size.Value * context.ChunkResolution.Multiplier()), context.ProcessingColorSpace, false);
         surface.DrawingSurface.Canvas.SetMatrix(Matrix3X3.Identity);
 
         if (Fill.Value is ColorPaintable colorPaintable)

+ 4 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/ApplyFilterNode.cs

@@ -28,6 +28,9 @@ public sealed class ApplyFilterNode : RenderNode, IRenderInput
     
     public InputProperty<bool> InvertMask { get; }
 
+    protected override bool ExecuteOnlyOnCacheChange => true;
+    protected override CacheTriggerFlags CacheTrigger => CacheTriggerFlags.Inputs;
+
     public ApplyFilterNode()
     {
         Background = CreateRenderInput("Input", "IMAGE");
@@ -40,7 +43,7 @@ public sealed class ApplyFilterNode : RenderNode, IRenderInput
 
     protected override void Paint(RenderContext context, DrawingSurface surface)
     {
-        AllowHighDpiRendering = (Background.Connection.Node as RenderNode)?.AllowHighDpiRendering ?? true;
+        AllowHighDpiRendering = (Background.Connection?.Node as RenderNode)?.AllowHighDpiRendering ?? true;
         base.Paint(context, surface);
     }
 

+ 5 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -264,10 +264,15 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
             return;
         }
 
+        int saved = renderOnto.Canvas.Save();
+        renderOnto.Canvas.Scale((float)context.ChunkResolution.InvertedMultiplier());
+
         img.DrawCommittedRegionOn(
             new RectI(0, 0, img.LatestSize.X, img.LatestSize.Y),
             context.ChunkResolution,
             renderOnto, VecI.Zero, replacePaint, context.DesiredSamplingOptions);
+
+        renderOnto.Canvas.RestoreToCount(saved);
     }
 
     private KeyFrameData GetFrameWithImage(KeyFrameTime frame)

+ 3 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageLeftNode.cs

@@ -64,8 +64,9 @@ public class ModifyImageLeftNode : Node, IPairNode
 
             int saved = texture.DrawingSurface.Canvas.Save();
 
-            VecD scaling = PreviewUtility.CalculateUniformScaling(context.DocumentSize, texture.Size);
-            VecD offset = PreviewUtility.CalculateCenteringOffset(context.DocumentSize, texture.Size, scaling);
+            VecI size = Image.Value?.Size ?? context.RenderOutputSize;
+            VecD scaling = PreviewUtility.CalculateUniformScaling(size, texture.Size);
+            VecD offset = PreviewUtility.CalculateCenteringOffset(size, texture.Size, scaling);
             texture.DrawingSurface.Canvas.Translate((float)offset.X, (float)offset.Y);
             texture.DrawingSurface.Canvas.Scale((float)scaling.X, (float)scaling.Y);
             var previewCtx =

+ 5 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageRightNode.cs

@@ -115,6 +115,11 @@ public class ModifyImageRightNode : RenderNode, IPairNode, ICustomShaderNode
         builder.Dispose();
     }
 
+    public override RectD? GetPreviewBounds(RenderContext ctx, string elementToRenderName)
+    {
+        return size.HasValue ? new RectD(0, 0, size.Value.X, size.Value.Y) : null;
+    }
+
     public override void RenderPreview(DrawingSurface renderOn, RenderContext context, string elementToRenderName)
     {
         var startNode = FindStartNode();

+ 11 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Node.cs

@@ -12,6 +12,7 @@ using Drawie.Backend.Core.Shaders;
 using Drawie.Backend.Core.Shaders.Generation;
 using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 
@@ -83,13 +84,18 @@ public abstract class Node : IReadOnlyNode, IDisposable
 
     protected virtual bool CacheChanged(RenderContext context)
     {
-        bool changed = lastRenderSize != context.RenderOutputSize;
+        bool changed = false;
 
         if (CacheTrigger.HasFlag(CacheTriggerFlags.Inputs))
         {
             changed |= inputs.Any(x => x.CacheChanged);
         }
 
+        if (CacheTrigger.HasFlag(CacheTriggerFlags.RenderSize))
+        {
+            changed |= lastRenderSize != context.RenderOutputSize;
+        }
+
         if (CacheTrigger.HasFlag(CacheTriggerFlags.Timeline))
         {
             changed |= lastFrameTime.Frame != context.FrameTime.Frame ||
@@ -117,7 +123,8 @@ public abstract class Node : IReadOnlyNode, IDisposable
         lastContentCacheHash = GetContentCacheHash();
     }
 
-    public void TraverseBackwards(Func<IReadOnlyNode, IInputProperty, bool> action, Func<IInputProperty, bool>? branchCondition = null)
+    public void TraverseBackwards(Func<IReadOnlyNode, IInputProperty, bool> action,
+        Func<IInputProperty, bool>? branchCondition = null)
     {
         var visited = new HashSet<IReadOnlyNode>();
         var queueNodes = new Queue<(IReadOnlyNode, IInputProperty)>();
@@ -143,6 +150,7 @@ public abstract class Node : IReadOnlyNode, IDisposable
                 {
                     continue;
                 }
+
                 if (inputProperty.Connection != null)
                 {
                     queueNodes.Enqueue((inputProperty.Connection.Node, inputProperty));
@@ -613,6 +621,7 @@ public abstract class Node : IReadOnlyNode, IDisposable
         hash.Add(GetType());
         hash.Add(DisplayName);
         hash.Add(Position);
+
         foreach (var input in inputs)
         {
             hash.Add(input.GetCacheHash());

+ 29 - 30
src/PixiEditor/Models/Rendering/SceneRenderer.cs

@@ -27,8 +27,6 @@ internal class SceneRenderer : IDisposable
     private KeyFrameTime lastFrameTime;
     private Dictionary<Guid, bool> lastFramesVisibility = new();
 
-    private ChunkResolution? lastResolution;
-
     private TextureCache textureCache = new();
 
     public SceneRenderer(IReadOnlyDocument trackerDocument, IDocument documentViewModel)
@@ -63,15 +61,15 @@ internal class SceneRenderer : IDisposable
                 renderedCount++;
             }
 
-            if(renderedCount == 0 && previewTextures is { Count: > 0 })
+            if (renderedCount == 0 && previewTextures is { Count: > 0 })
             {
                 RenderOnlyPreviews(affectedArea, previewTextures);
             }
-
         }, DispatcherPriority.Background);
     }
 
-    private void RenderOnlyPreviews(AffectedArea affectedArea, Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
+    private void RenderOnlyPreviews(AffectedArea affectedArea,
+        Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
     {
         ViewportInfo previewGenerationViewport = new()
         {
@@ -88,7 +86,8 @@ internal class SceneRenderer : IDisposable
         rendered.Dispose();
     }
 
-    public Texture? RenderScene(ViewportInfo viewport, AffectedArea affectedArea,Dictionary<Guid, List<PreviewRenderRequest>>? previewTextures = null)
+    public Texture? RenderScene(ViewportInfo viewport, AffectedArea affectedArea,
+        Dictionary<Guid, List<PreviewRenderRequest>>? previewTextures = null)
     {
         /*if (Document.Renderer.IsBusy || DocumentViewModel.Busy ||
             target.DeviceClipBounds.Size.ShortestAxis <= 0) return;*/
@@ -113,7 +112,8 @@ internal class SceneRenderer : IDisposable
 
         IReadOnlyNodeGraph finalGraph = RenderingUtils.SolveFinalNodeGraph(targetOutput, Document);
         bool shouldRerender =
-            ShouldRerender(renderTargetSize, targetMatrix, resolution, viewportId, targetOutput, finalGraph, previewTextures, visibleDocumentRegion);
+            ShouldRerender(renderTargetSize, targetMatrix, resolution, viewportId, targetOutput, finalGraph,
+                previewTextures, visibleDocumentRegion);
 
         if (shouldRerender)
         {
@@ -142,7 +142,8 @@ internal class SceneRenderer : IDisposable
         {
             finalSize = (VecI)(finalSize * resolution.Multiplier());
 
-            renderTexture = textureCache.RequestTexture(viewportId.GetHashCode(), finalSize, Document.ProcessingColorSpace);
+            renderTexture =
+                textureCache.RequestTexture(viewportId.GetHashCode(), finalSize, Document.ProcessingColorSpace);
             renderTarget = renderTexture.DrawingSurface;
             renderTarget.Canvas.Save();
             renderTexture.DrawingSurface.Canvas.Save();
@@ -212,14 +213,8 @@ internal class SceneRenderer : IDisposable
             return true;
         }
 
-        if(previewTextures is { Count: > 0 })
-        {
-            return true;
-        }
-
-        if (lastResolution != resolution)
+        if (previewTextures is { Count: > 0 })
         {
-            lastResolution = resolution;
             return true;
         }
 
@@ -229,12 +224,14 @@ internal class SceneRenderer : IDisposable
             HighResRendering = HighResRendering,
             TargetOutput = targetOutput,
             GraphCacheHash = finalGraph.GetCacheHash(),
-            VisibleDocumentRegion = (RectD?)visibleDocumentRegion ?? new RectD(0, 0, Document.Size.X, Document.Size.Y)
+            ZoomLevel = matrix.ScaleX,
+            VisibleDocumentRegion =
+                (RectD?)visibleDocumentRegion ?? new RectD(0, 0, Document.Size.X, Document.Size.Y)
         };
 
         if (lastRenderedStates.TryGetValue(viewportId, out var lastState))
         {
-            if (!lastState.Equals(renderState))
+            if (lastState.ShouldRerender(renderState))
             {
                 lastRenderedStates[viewportId] = renderState;
                 return true;
@@ -280,15 +277,6 @@ internal class SceneRenderer : IDisposable
             }
         }
 
-        // if (!renderInDocumentSize)
-        //{
-        double zoomDiff = Math.Abs(matrix.ScaleX - cachedTexture.DrawingSurface.Canvas.TotalMatrix.ScaleX);
-        zoomDiff += Math.Abs(matrix.ScaleY - cachedTexture.DrawingSurface.Canvas.TotalMatrix.ScaleY);
-        if (zoomDiff != 0)
-        {
-            return true;
-        }
-        //}
 
         return false;
     }
@@ -373,11 +361,22 @@ struct RenderState
     public string TargetOutput { get; set; }
     public int GraphCacheHash { get; set; }
     public RectD VisibleDocumentRegion { get; set; }
+    public double ZoomLevel { get; set; }
+
+    public bool ShouldRerender(RenderState other)
+    {
+        return !ChunkResolution.Equals(other.ChunkResolution) || HighResRendering != other.HighResRendering ||
+               TargetOutput != other.TargetOutput || GraphCacheHash != other.GraphCacheHash ||
+               VisibleRegionChanged(other) || ZoomDiff(other) > 0;
+    }
+
+    private bool VisibleRegionChanged(RenderState other)
+    {
+        return !other.VisibleDocumentRegion.IsFullyInside(VisibleDocumentRegion);
+    }
 
-    public bool Equals(RenderState other)
+    private double ZoomDiff(RenderState other)
     {
-        return ChunkResolution.Equals(other.ChunkResolution) && HighResRendering == other.HighResRendering &&
-               TargetOutput == other.TargetOutput && GraphCacheHash == other.GraphCacheHash &&
-               VisibleDocumentRegion == other.VisibleDocumentRegion;
+        return Math.Abs(ZoomLevel - other.ZoomLevel);
     }
 }