flabbet 7 місяців тому
батько
коміт
80d037888d

+ 77 - 24
src/PixiEditor.ChangeableDocument/Rendering/DocumentRenderer.cs

@@ -15,11 +15,7 @@ namespace PixiEditor.ChangeableDocument.Rendering;
 
 public class DocumentRenderer : IPreviewRenderable
 {
-    private Paint ClearPaint { get; } = new Paint()
-    {
-        BlendMode = BlendMode.Src, Color = Drawie.Backend.Core.ColorsImpl.Colors.Transparent
-    };
-
+    private Queue<RenderRequest> renderRequests = new();
     private Texture renderTexture;
 
     public DocumentRenderer(IReadOnlyDocument document)
@@ -29,7 +25,9 @@ public class DocumentRenderer : IPreviewRenderable
 
     private IReadOnlyDocument Document { get; }
     public bool IsBusy { get; private set; }
-
+    
+    private bool isExecuting = false;
+    
     public void UpdateChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime)
     {
         try
@@ -47,7 +45,7 @@ public class DocumentRenderer : IPreviewRenderable
         }
     }
 
-    public void RenderLayers(DrawingSurface toRenderOn, HashSet<Guid> layersToCombine, int frame,
+    public async Task RenderLayers(DrawingSurface toRenderOn, HashSet<Guid> layersToCombine, int frame,
         ChunkResolution resolution, VecI renderSize)
     {
         IsBusy = true;
@@ -86,7 +84,7 @@ public class DocumentRenderer : IPreviewRenderable
     }
 
 
-    public void RenderLayer(DrawingSurface toRenderOn, Guid layerId, ChunkResolution resolution, KeyFrameTime frameTime,
+    public async Task RenderLayer(DrawingSurface toRenderOn, Guid layerId, ChunkResolution resolution, KeyFrameTime frameTime,
         VecI renderSize)
     {
         var node = Document.FindMember(layerId);
@@ -122,21 +120,17 @@ public class DocumentRenderer : IPreviewRenderable
         IsBusy = false;
     }
 
-    public void RenderNodePreview(IPreviewRenderable previewRenderable, DrawingSurface renderOn, RenderContext context,
+    public async Task RenderNodePreview(IPreviewRenderable previewRenderable, DrawingSurface renderOn, RenderContext context,
         string elementToRenderName)
     {
-        if (IsBusy)
-        {
-            return;
-        }
-
-        IsBusy = true;
-
-        if (previewRenderable is Node { IsDisposed: true }) return;
-
-        previewRenderable.RenderPreview(renderOn, context, elementToRenderName);
-
-        IsBusy = false;
+        //if (previewRenderable is Node { IsDisposed: true }) return;
+        TaskCompletionSource<bool> tcs = new();
+        RenderRequest request = new(tcs, context, renderOn, previewRenderable, elementToRenderName);
+        
+        renderRequests.Enqueue(request);
+        ExecuteRenderRequests();
+        
+        await tcs.Task;
     }
 
     public static IReadOnlyNodeGraph ConstructMembersOnlyGraph(IReadOnlyNodeGraph fullGraph)
@@ -192,10 +186,10 @@ public class DocumentRenderer : IPreviewRenderable
         return membersOnlyGraph;
     }
 
-    public RectD? GetPreviewBounds(int frame, string elementNameToRender = "") =>
+    RectD? IPreviewRenderable.GetPreviewBounds(int frame, string elementNameToRender = "") =>
         new(0, 0, Document.Size.X, Document.Size.Y);
 
-    public bool RenderPreview(DrawingSurface renderOn, RenderContext context,
+    bool IPreviewRenderable.RenderPreview(DrawingSurface renderOn, RenderContext context,
         string elementToRenderName)
     {
         IsBusy = true;
@@ -217,7 +211,7 @@ public class DocumentRenderer : IPreviewRenderable
         return true;
     }
 
-    public void RenderDocument(DrawingSurface toRenderOn, KeyFrameTime frameTime, VecI renderSize)
+    public async Task RenderDocument(DrawingSurface toRenderOn, KeyFrameTime frameTime, VecI renderSize)
     {
         IsBusy = true;
 
@@ -247,6 +241,38 @@ public class DocumentRenderer : IPreviewRenderable
         IsBusy = false;
     }
 
+    private void ExecuteRenderRequests()
+    {
+        if(isExecuting) return;
+        
+        isExecuting = true;
+        while (renderRequests.Count > 0)
+        {
+            RenderRequest request = renderRequests.Dequeue();
+
+            try
+            {
+                if (request.PreviewRenderable != null)
+                {
+                    request.PreviewRenderable.RenderPreview(request.RenderOn, request.Context,
+                        request.ElementToRenderName);
+                }
+                else if (request.NodeGraph != null)
+                {
+                    request.NodeGraph.Execute(request.Context);
+                }
+
+                request.TaskCompletionSource.SetResult(true);
+            }
+            catch (Exception e)
+            {
+                request.TaskCompletionSource.SetException(e);
+            }
+        }
+        
+        isExecuting = false;
+    }
+
     private static IInputProperty GetTargetInput(IInputProperty? input,
         IReadOnlyNodeGraph sourceGraph,
         NodeGraph membersOnlyGraph,
@@ -286,3 +312,30 @@ public class DocumentRenderer : IPreviewRenderable
         return found ?? (membersOnlyGraph.OutputNode as IRenderInput)?.Background;
     }
 }
+
+public struct RenderRequest
+{
+    public RenderContext Context { get; set; }
+    public DrawingSurface RenderOn { get; set; }
+    public IReadOnlyNodeGraph? NodeGraph { get; set; }
+    public IPreviewRenderable? PreviewRenderable { get; set; }
+    public string ElementToRenderName { get; set; }
+    public TaskCompletionSource<bool> TaskCompletionSource { get; set; }
+    
+    public RenderRequest(TaskCompletionSource<bool> completionSource, RenderContext context, DrawingSurface renderOn, IReadOnlyNodeGraph nodeGraph)
+    {
+        TaskCompletionSource = completionSource;
+        Context = context;
+        RenderOn = renderOn;
+        NodeGraph = nodeGraph;
+    }
+    
+    public RenderRequest(TaskCompletionSource<bool> completionSource, RenderContext context, DrawingSurface renderOn, IPreviewRenderable previewRenderable, string elementToRenderName)
+    {
+        TaskCompletionSource = completionSource;
+        Context = context;
+        RenderOn = renderOn;
+        PreviewRenderable = previewRenderable;
+        ElementToRenderName = elementToRenderName;
+    }
+}

+ 32 - 19
src/PixiEditor/Models/Rendering/PreviewPainter.cs

@@ -1,4 +1,5 @@
 using Avalonia;
+using Avalonia.Threading;
 using ChunkyImageLib.DataHolders;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core.Numerics;
@@ -20,10 +21,14 @@ public class PreviewPainter
     public KeyFrameTime FrameTime { get; set; }
     public VecI DocumentSize { get; set; }
     public DocumentRenderer Renderer { get; set; }
-    
+    public VecI Bounds { get; set; }
+    public Matrix3X3 Matrix { get; set; }
+
     private Texture renderTexture;
-    
-    public PreviewPainter(DocumentRenderer renderer, IPreviewRenderable previewRenderable, KeyFrameTime frameTime, VecI documentSize, ColorSpace processingColorSpace, string elementToRenderName = "")
+    private bool requestedRepaint;
+
+    public PreviewPainter(DocumentRenderer renderer, IPreviewRenderable previewRenderable, KeyFrameTime frameTime,
+        VecI documentSize, ColorSpace processingColorSpace, string elementToRenderName = "")
     {
         PreviewRenderable = previewRenderable;
         ElementToRenderName = elementToRenderName;
@@ -33,34 +38,42 @@ public class PreviewPainter
         Renderer = renderer;
     }
 
-    public void Paint(DrawingSurface renderOn, VecI boundsSize, Matrix3X3 matrix)
+    public void Paint(DrawingSurface renderOn)
     {
-        if (PreviewRenderable == null)
+        if (renderTexture == null || renderTexture.IsDisposed)
         {
             return;
         }
 
-        if (renderTexture == null || renderTexture.Size != boundsSize)
+        renderOn.Canvas.DrawSurface(renderTexture.DrawingSurface, 0, 0);
+    }
+
+    public void Repaint()
+    {
+        if (Bounds.ShortestAxis == 0 || requestedRepaint) return;
+
+        requestedRepaint = true;
+        
+        if (renderTexture == null || renderTexture.Size != Bounds)
         {
             renderTexture?.Dispose();
-            renderTexture = Texture.ForProcessing(boundsSize, ProcessingColorSpace);
+            renderTexture = Texture.ForProcessing(Bounds, ProcessingColorSpace);
         }
-        
+
         renderTexture.DrawingSurface.Canvas.Clear();
         renderTexture.DrawingSurface.Canvas.Save();
 
-        renderTexture.DrawingSurface.Canvas.SetMatrix(matrix);
-        
-        RenderContext context = new(renderTexture.DrawingSurface, FrameTime, ChunkResolution.Full, DocumentSize, ProcessingColorSpace);
+        renderTexture.DrawingSurface.Canvas.SetMatrix(Matrix);
 
-        Renderer.RenderNodePreview(PreviewRenderable, renderTexture.DrawingSurface, context, ElementToRenderName);
-        renderTexture.DrawingSurface.Canvas.Restore();
-        
-        renderOn.Canvas.DrawSurface(renderTexture.DrawingSurface, 0, 0);
-    }
+        RenderContext context = new(renderTexture.DrawingSurface, FrameTime, ChunkResolution.Full, DocumentSize,
+            ProcessingColorSpace);
 
-    public void Repaint()
-    {
-        RequestRepaint?.Invoke();
+        Renderer.RenderNodePreview(PreviewRenderable, renderTexture.DrawingSurface, context, ElementToRenderName)
+            .ContinueWith(_ =>
+            {
+                renderTexture.DrawingSurface.Canvas.Restore();
+                Dispatcher.UIThread.Invoke(() => RequestRepaint?.Invoke());
+                requestedRepaint = false;
+            });
     }
 }

+ 26 - 19
src/PixiEditor/Views/Visuals/PreviewPainterControl.cs

@@ -32,13 +32,13 @@ public class PreviewPainterControl : DrawieControl
     public PreviewPainterControl()
     {
         PreviewPainterProperty.Changed.Subscribe(PainterChanged);
+        BoundsProperty.Changed.Subscribe(UpdatePainterBounds);
     }
 
     public PreviewPainterControl(PreviewPainter previewPainter, int frameToRender)
     {
         PreviewPainter = previewPainter;
         FrameToRender = frameToRender;
-        PreviewPainterProperty.Changed.Subscribe(PainterChanged);
     }
 
 
@@ -67,26 +67,10 @@ public class PreviewPainterControl : DrawieControl
             return;
         }
 
-        RectD? previewBounds =
-            PreviewPainter.PreviewRenderable.GetPreviewBounds(FrameToRender, PreviewPainter.ElementToRenderName);
-        
-        float x = (float)(previewBounds?.Width ?? 0);
-        float y = (float)(previewBounds?.Height ?? 0);
-
-        surface.Canvas.Save();
-
-        Matrix3X3 matrix = Matrix3X3.Identity;
-        if (previewBounds != null)
-        {
-            matrix = UniformScale(x, y, previewBounds.Value);
-        }
-
-        PreviewPainter.Paint(surface, new VecI((int)Bounds.Size.Width, (int)Bounds.Size.Height), matrix);
-
-        surface.Canvas.Restore();
+        PreviewPainter.Paint(surface);
     }
 
-    private Matrix3X3 UniformScale(float x, float y,  RectD previewBounds)
+    private Matrix3X3 UniformScale(float x, float y, RectD previewBounds)
     {
         float scaleX = (float)Bounds.Width / x;
         float scaleY = (float)Bounds.Height / y;
@@ -98,4 +82,27 @@ public class PreviewPainterControl : DrawieControl
         Matrix3X3 matrix = Matrix3X3.CreateScale(scale, scale);
         return matrix.Concat(Matrix3X3.CreateTranslation(dX, dY));
     }
+
+    private void UpdatePainterBounds(AvaloniaPropertyChangedEventArgs<Rect> args)
+    {
+        if (PreviewPainter == null)
+        {
+            return;
+        }
+
+        PreviewPainter.Bounds = new VecI((int)Bounds.Width, (int)Bounds.Height);
+
+        RectD? previewBounds =
+            PreviewPainter.PreviewRenderable.GetPreviewBounds(FrameToRender, PreviewPainter.ElementToRenderName);
+        
+        if (previewBounds == null)
+        {
+            return;
+        }
+
+        float x = (float)(previewBounds?.Width ?? 0);
+        float y = (float)(previewBounds?.Height ?? 0);
+
+        PreviewPainter.Matrix = UniformScale(x, y, previewBounds.Value);
+    }
 }