瀏覽代碼

Fixed preview painter for multiple controls

flabbet 7 月之前
父節點
當前提交
a25cb735b2

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit 2237f26dbac88d9dffac3e7916ef10198b115c18
+Subproject commit 0f4cbd35e77d52f89c944d5fcc7d732ccd22bd82

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

@@ -194,18 +194,10 @@ public class DocumentRenderer : IPreviewRenderable
     {
         IsBusy = true;
 
-        if (renderTexture == null || renderTexture.Size != Document.Size)
-        {
-            renderTexture?.Dispose();
-            renderTexture = Texture.ForProcessing(Document.Size, Document.ProcessingColorSpace);
-        }
-
-        renderTexture.DrawingSurface.Canvas.Clear();
-        context.RenderSurface = renderTexture.DrawingSurface;
+        renderOn.Canvas.Clear();
+        context.RenderSurface = renderOn;
         Document.NodeGraph.Execute(context);
 
-        renderOn.Canvas.DrawSurface(renderTexture.DrawingSurface, 0, 0);
-
         IsBusy = false;
 
         return true;

+ 133 - 26
src/PixiEditor/Models/Rendering/PreviewPainter.cs

@@ -17,16 +17,20 @@ public class PreviewPainter
     public string ElementToRenderName { get; set; }
     public IPreviewRenderable PreviewRenderable { get; set; }
     public ColorSpace ProcessingColorSpace { get; set; }
-    public event Action RequestRepaint;
     public KeyFrameTime FrameTime { get; set; }
     public VecI DocumentSize { get; set; }
     public DocumentRenderer Renderer { get; set; }
-    public VecI Bounds { get; set; }
 
-    public event Func<Matrix3X3?>? RequestMatrix;
+    private Dictionary<int, Texture> renderTextures = new();
+    private Dictionary<int, PainterInstance> painterInstances = new();
 
-    private Texture renderTexture;
-    private bool requestedRepaint;
+    private HashSet<int> dirtyTextures = new HashSet<int>();
+    private HashSet<int> repaintingTextures = new HashSet<int>();
+
+    private Dictionary<int, VecI> pendingResizes = new();
+    private HashSet<int> pendingRemovals = new();
+
+    private int lastRequestId = 0;
 
     public PreviewPainter(DocumentRenderer renderer, IPreviewRenderable previewRenderable, KeyFrameTime frameTime,
         VecI documentSize, ColorSpace processingColorSpace, string elementToRenderName = "")
@@ -39,8 +43,13 @@ public class PreviewPainter
         Renderer = renderer;
     }
 
-    public void Paint(DrawingSurface renderOn)
+    public void Paint(DrawingSurface renderOn, int painterId)
     {
+        if (!renderTextures.TryGetValue(painterId, out Texture? renderTexture))
+        {
+            return;
+        }
+
         if (renderTexture == null || renderTexture.IsDisposed)
         {
             return;
@@ -49,33 +58,131 @@ public class PreviewPainter
         renderOn.Canvas.DrawSurface(renderTexture.DrawingSurface, 0, 0);
     }
 
-    public void Repaint()
+    public PainterInstance AttachPainterInstance()
     {
-        if (Bounds.ShortestAxis == 0 || requestedRepaint) return;
-        
-        if (renderTexture == null || renderTexture.Size != Bounds)
+        int requestId = lastRequestId++;
+
+        PainterInstance painterInstance = new() { RequestId = requestId };
+
+        painterInstances[requestId] = painterInstance;
+
+        return painterInstance;
+    }
+
+    public void ChangeRenderTextureSize(int requestId, VecI size)
+    {
+        if (repaintingTextures.Contains(requestId))
         {
-            renderTexture?.Dispose();
-            renderTexture = Texture.ForProcessing(Bounds, ProcessingColorSpace);
+            pendingResizes[requestId] = size;
+            return;
         }
-        
-        renderTexture.DrawingSurface.Canvas.Clear();
-        renderTexture.DrawingSurface.Canvas.Save();
 
-        Matrix3X3? matrix = RequestMatrix?.Invoke();
+        if (renderTextures.ContainsKey(requestId))
+        {
+            renderTextures[requestId].Dispose();
+        }
+
+        renderTextures[requestId] = Texture.ForProcessing(size, ProcessingColorSpace);
+    }
+
+    public void RemovePainterInstance(int requestId)
+    {
+        painterInstances.Remove(requestId);
+        dirtyTextures.Remove(requestId);
         
-        renderTexture.DrawingSurface.Canvas.SetMatrix(matrix ?? Matrix3X3.Identity);
+        if (repaintingTextures.Contains(requestId))
+        {
+            pendingRemovals.Add(requestId);
+            return;
+        }
+
+        renderTextures[requestId]?.Dispose();
+        renderTextures.Remove(requestId);
+    }
 
-        RenderContext context = new(renderTexture.DrawingSurface, FrameTime, ChunkResolution.Full, DocumentSize,
-            ProcessingColorSpace);
+    public void Repaint()
+    {
+        foreach (var texture in renderTextures)
+        {
+            dirtyTextures.Add(texture.Key);
+        }
+
+        RepaintDirty();
+    }
 
-        requestedRepaint = true;
-        Renderer.RenderNodePreview(PreviewRenderable, renderTexture.DrawingSurface, context, ElementToRenderName)
-            .ContinueWith(_ =>
+    public void RepaintFor(int requestId)
+    {
+        dirtyTextures.Add(requestId);
+        RepaintDirty();
+    }
+
+    private void RepaintDirty()
+    {
+        var dirtyArray = dirtyTextures.ToArray();
+        foreach (var texture in dirtyArray)
+        {
+            if (!renderTextures.TryGetValue(texture, out var renderTexture))
             {
-                renderTexture.DrawingSurface.Canvas.Restore();
-                Dispatcher.UIThread.Invoke(() => RequestRepaint?.Invoke());
-                requestedRepaint = false;
-            });
+                continue;
+            }
+
+            repaintingTextures.Add(texture);
+
+            renderTexture.DrawingSurface.Canvas.Clear();
+            renderTexture.DrawingSurface.Canvas.Save();
+
+            PainterInstance painterInstance = painterInstances[texture];
+
+            Matrix3X3? matrix = painterInstance.RequestMatrix?.Invoke();
+
+            renderTexture.DrawingSurface.Canvas.SetMatrix(matrix ?? Matrix3X3.Identity);
+
+            RenderContext context = new(renderTexture.DrawingSurface, FrameTime, ChunkResolution.Full, DocumentSize,
+                ProcessingColorSpace);
+
+            dirtyTextures.Remove(texture);
+            Renderer.RenderNodePreview(PreviewRenderable, renderTexture.DrawingSurface, context, ElementToRenderName)
+                .ContinueWith(_ =>
+                {
+                    Dispatcher.UIThread.Invoke(() =>
+                    {
+                        if(pendingRemovals.Contains(texture))
+                        {
+                            renderTexture.Dispose();
+                            renderTextures.Remove(texture);
+                            pendingRemovals.Remove(texture);
+                            pendingResizes.Remove(texture);
+                            dirtyTextures.Remove(texture);
+                            return;
+                        }
+                        
+                        if (renderTexture != null && !renderTexture.IsDisposed)
+                        {
+                            renderTexture.DrawingSurface.Canvas.Restore();
+                        }
+
+                        painterInstance.RequestRepaint?.Invoke();
+                        repaintingTextures.Remove(texture);
+
+                        if (pendingResizes.Remove(texture, out VecI size))
+                        {
+                            ChangeRenderTextureSize(texture, size);
+                            dirtyTextures.Add(texture);
+                        }
+
+                        if (repaintingTextures.Count == 0 && dirtyTextures.Count > 0)
+                        {
+                            RepaintDirty();
+                        }
+                    });
+                });
+        }
     }
 }
+
+public class PainterInstance
+{
+    public int RequestId { get; set; }
+    public Func<Matrix3X3?>? RequestMatrix;
+    public Action RequestRepaint;
+}

+ 0 - 22
src/PixiEditor/Views/Nodes/NodeView.cs

@@ -149,7 +149,6 @@ public class NodeView : TemplatedControl
     static NodeView()
     {
         IsSelectedProperty.Changed.Subscribe(NodeSelectionChanged);
-        ResultPreviewProperty.Changed.Subscribe(PreviewPainterChanged);
     }
 
     protected override void OnPointerPressed(PointerPressedEventArgs e)
@@ -256,25 +255,4 @@ public class NodeView : TemplatedControl
             nodeView.PseudoClasses.Set(":selected", e.NewValue.Value);
         }
     }
-
-    private static void PreviewPainterChanged(AvaloniaPropertyChangedEventArgs<PreviewPainter> e)
-    {
-        if (e.Sender is NodeView nodeView)
-        {
-            if (e.OldValue.Value != null)
-            {
-                e.OldValue.Value.RequestRepaint -= nodeView.OnPainterRenderRequest;
-            }
-
-            if (e.NewValue.Value != null)
-            {
-                e.NewValue.Value.RequestRepaint += nodeView.OnPainterRenderRequest;
-            }
-        }
-    }
-    
-    private void OnPainterRenderRequest()
-    {
-        InvalidateVisual();
-    }
 }

+ 18 - 10
src/PixiEditor/Views/Rendering/Scene.cs

@@ -140,7 +140,9 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
 
     private PixelSize lastSize = PixelSize.Empty;
     private Cursor lastCursor;
-    public static readonly StyledProperty<string> RenderOutputProperty = AvaloniaProperty.Register<Scene, string>("RenderOutput");
+
+    public static readonly StyledProperty<string> RenderOutputProperty =
+        AvaloniaProperty.Register<Scene, string>("RenderOutput");
 
     static Scene()
     {
@@ -194,11 +196,11 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
         InitializeComposition();
     }
 
-    protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
+    protected override async void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
     {
         if (initialized)
         {
-            FreeGraphicsResources();
+            await FreeGraphicsResources();
         }
 
         initialized = false;
@@ -261,7 +263,8 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
     {
         DrawCheckerboard(renderTexture.DrawingSurface, bounds);
         DrawOverlays(renderTexture.DrawingSurface, bounds, OverlayRenderSorting.Background);
-        SceneRenderer.RenderScene(renderTexture.DrawingSurface, CalculateResolution(), RenderOutput == "DEFAULT" ? null : RenderOutput);
+        SceneRenderer.RenderScene(renderTexture.DrawingSurface, CalculateResolution(),
+            RenderOutput == "DEFAULT" ? null : RenderOutput);
         DrawOverlays(renderTexture.DrawingSurface, bounds, OverlayRenderSorting.Foreground);
     }
 
@@ -464,7 +467,7 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
             }
         }
     }
-    
+
     protected override void OnKeyUp(KeyEventArgs e)
     {
         base.OnKeyUp(e);
@@ -562,7 +565,7 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
     {
         updateQueued = false;
         var root = this.GetVisualRoot();
-        if (root == null)
+        if (root == null || !initialized)
         {
             return;
         }
@@ -617,14 +620,19 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
         return (true, string.Empty);
     }
 
-    protected void FreeGraphicsResources()
+    protected async Task FreeGraphicsResources()
     {
-        resources?.DisposeAsync();
+        renderTexture?.Dispose();
+        renderTexture = null;
+        
         framebuffer?.Dispose();
         framebuffer = null;
 
-        renderTexture?.Dispose();
-        renderTexture = null;
+        if (resources != null)
+        {
+            await resources.DisposeAsync();
+        }
+
         resources = null;
     }
 

+ 37 - 14
src/PixiEditor/Views/Visuals/PreviewPainterControl.cs

@@ -29,6 +29,8 @@ public class PreviewPainterControl : DrawieControl
         set { SetValue(FrameToRenderProperty, value); }
     }
 
+    private PainterInstance? painterInstance;
+
     static PreviewPainterControl()
     {
         PreviewPainterProperty.Changed.Subscribe(PainterChanged);
@@ -37,7 +39,6 @@ public class PreviewPainterControl : DrawieControl
 
     public PreviewPainterControl()
     {
-        
     }
 
     public PreviewPainterControl(PreviewPainter previewPainter, int frameToRender)
@@ -51,16 +52,32 @@ public class PreviewPainterControl : DrawieControl
         var sender = args.Sender as PreviewPainterControl;
         if (args.OldValue.Value != null)
         {
-            args.OldValue.Value.RequestMatrix -= sender.OnPainterRequestMatrix;
-            args.OldValue.Value.RequestRepaint -= sender.OnPainterRenderRequest;
+            if (sender.painterInstance != null)
+            {
+                args.OldValue.Value.RemovePainterInstance(sender.painterInstance.RequestId);
+            }
+
+
+            sender.painterInstance = null;
         }
 
         if (args.NewValue.Value != null)
         {
-            args.NewValue.Value.RequestMatrix += sender.OnPainterRequestMatrix;
-            args.NewValue.Value.RequestRepaint += sender.OnPainterRenderRequest;
-            
-            args.NewValue.Value.Repaint();
+            sender.painterInstance = args.NewValue.Value.AttachPainterInstance();
+            if (sender.Bounds is { Width: > 0, Height: > 0 })
+            {
+                sender.PreviewPainter.ChangeRenderTextureSize(sender.painterInstance.RequestId,
+                    new VecI((int)sender.Bounds.Width, (int)sender.Bounds.Height));
+            }
+
+            sender.painterInstance.RequestMatrix = sender.OnPainterRequestMatrix;
+            sender.painterInstance.RequestRepaint = sender.OnPainterRenderRequest;
+
+            args.NewValue.Value.RepaintFor(sender.painterInstance.RequestId);
+        }
+        else
+        {
+            sender.painterInstance = null;
         }
     }
 
@@ -71,12 +88,12 @@ public class PreviewPainterControl : DrawieControl
 
     public override void Draw(DrawingSurface surface)
     {
-        if (PreviewPainter == null)
+        if (PreviewPainter == null || painterInstance == null)
         {
             return;
         }
 
-        PreviewPainter.Paint(surface);
+        PreviewPainter.Paint(surface, painterInstance.RequestId);
     }
 
     private Matrix3X3 UniformScale(float x, float y, RectD previewBounds)
@@ -95,15 +112,21 @@ public class PreviewPainterControl : DrawieControl
     private static void UpdatePainterBounds(AvaloniaPropertyChangedEventArgs<Rect> args)
     {
         var sender = args.Sender as PreviewPainterControl;
-        if(sender == null) return;
-        
-        if (sender.PreviewPainter == null)
+
+        if (sender?.PreviewPainter == null)
         {
             return;
         }
 
-        sender.PreviewPainter.Bounds = new VecI((int)sender.Bounds.Width, (int)sender.Bounds.Height);
-        sender.PreviewPainter.Repaint();
+        if (sender.painterInstance != null)
+        {
+            if (args.NewValue.Value is { Width: > 0, Height: > 0 })
+            {
+                sender.PreviewPainter.ChangeRenderTextureSize(sender.painterInstance.RequestId,
+                    new VecI((int)args.NewValue.Value.Width, (int)args.NewValue.Value.Height));
+                sender.PreviewPainter.RepaintFor(sender.painterInstance.RequestId);
+            }
+        }
     }
 
     private Matrix3X3? OnPainterRequestMatrix()