Browse Source

efficient rendering wip

flabbet 10 months ago
parent
commit
bf5779767d

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/SceneObjectRenderContext.cs

@@ -9,7 +9,7 @@ public class SceneObjectRenderContext : RenderContext
 {
     public RectD LocalBounds { get; }
 
-    public SceneObjectRenderContext(DrawingSurface surface, RectD localBounds, KeyFrameTime frameTime, VecI chunkToUpdate, ChunkResolution chunkResolution, VecI docSize) : base(surface, frameTime, chunkToUpdate, chunkResolution, docSize)
+    public SceneObjectRenderContext(DrawingSurface surface, RectD localBounds, KeyFrameTime frameTime, ChunkResolution chunkResolution, VecI docSize) : base(surface, frameTime, chunkResolution, docSize)
     {
         LocalBounds = localBounds;
     }

+ 46 - 24
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -23,6 +23,8 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     private VecI size;
     private ChunkyImage layerImage => keyFrames[0]?.Data as ChunkyImage;
 
+    private Dictionary<ChunkResolution, Texture> renderedSurfaces = new();
+
 
     protected Dictionary<(ChunkResolution, int), Texture> workingSurfaces =
         new Dictionary<(ChunkResolution, int), Texture>();
@@ -79,18 +81,35 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         return (GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage).LatestSize;
     }
 
-    protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
+    protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
+        bool shouldClear,
         Paint paint)
     {
-        var frameImage = GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage;
-        if (!frameImage.DrawMostUpToDateChunkOn(
-                ctx.ChunkToUpdate,
-                ctx.ChunkResolution,
-                workingSurface,
-                ctx.ChunkToUpdate * ctx.ChunkResolution.PixelSize(),
-                blendPaint) && shouldClear)
+        //if (ctx.ChunkToUpdate != null)
         {
-            workingSurface.Canvas.DrawRect((RectD)CalculateDestinationRect(ctx), clearPaint);
+            var frameImage = GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage;
+            /*if (!frameImage.DrawMostUpToDateChunkOn(
+                    ctx.ChunkToUpdate.Value,
+                    ctx.ChunkResolution,
+                    workingSurface,
+                    ctx.ChunkToUpdate.Value * ctx.ChunkResolution.PixelSize(),
+                    blendPaint) && shouldClear)
+            {
+                workingSurface.Canvas.DrawRect((RectD)CalculateDestinationRect(ctx), clearPaint);
+            }*/
+
+            for (int y = 0; y < 8; y++)
+            {
+                for (int x = 0; x < 8; x++)
+                {
+                    frameImage.DrawMostUpToDateChunkOn(
+                        new VecI(x, y),
+                        ctx.ChunkResolution,
+                        workingSurface,
+                        new VecI(x, y) * ctx.ChunkResolution.PixelSize(),
+                        blendPaint);
+                }
+            }
         }
     }
 
@@ -100,17 +119,19 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         bool shouldClear, Paint paint)
     {
         var frameImage = GetFrameWithImage(context.FrameTime).Data as ChunkyImage;
-        
+
+        VecI chunkToUpdate = context.ChunkToUpdate.Value;
+
         VecI imageChunksSize = frameImage.LatestSize / context.ChunkResolution.PixelSize();
-        bool requiresTopLeft = context.ChunkToUpdate.X > 0 || context.ChunkToUpdate.Y > 0;
-        bool requiresTop = context.ChunkToUpdate.Y > 0;
-        bool requiresLeft = context.ChunkToUpdate.X > 0;
-        bool requiresTopRight = context.ChunkToUpdate.X < imageChunksSize.X - 1 && context.ChunkToUpdate.Y > 0;
-        bool requiresRight = context.ChunkToUpdate.X < imageChunksSize.X - 1;
-        bool requiresBottomRight = context.ChunkToUpdate.X < imageChunksSize.X - 1 &&
-                                   context.ChunkToUpdate.Y < imageChunksSize.Y - 1;
-        bool requiresBottom = context.ChunkToUpdate.Y < imageChunksSize.Y - 1;
-        bool requiresBottomLeft = context.ChunkToUpdate.X > 0 && context.ChunkToUpdate.Y < imageChunksSize.Y - 1;
+        bool requiresTopLeft = chunkToUpdate.X > 0 || chunkToUpdate.Y > 0;
+        bool requiresTop = chunkToUpdate.Y > 0;
+        bool requiresLeft = chunkToUpdate.X > 0;
+        bool requiresTopRight = chunkToUpdate.X < imageChunksSize.X - 1 && chunkToUpdate.Y > 0;
+        bool requiresRight = chunkToUpdate.X < imageChunksSize.X - 1;
+        bool requiresBottomRight = chunkToUpdate.X < imageChunksSize.X - 1 &&
+                                   chunkToUpdate.Y < imageChunksSize.Y - 1;
+        bool requiresBottom = chunkToUpdate.Y < imageChunksSize.Y - 1;
+        bool requiresBottomLeft = chunkToUpdate.X > 0 && chunkToUpdate.Y < imageChunksSize.Y - 1;
 
         VecI tempSizeInChunks = new VecI(1, 1);
         if (requiresLeft)
@@ -134,7 +155,8 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         }
 
         VecI tempSize = tempSizeInChunks * context.ChunkResolution.PixelSize();
-        tempSize = new VecI(Math.Min(tempSize.X, (int)context.LocalBounds.Size.X), Math.Min(tempSize.Y, (int)context.LocalBounds.Size.Y));
+        tempSize = new VecI(Math.Min(tempSize.X, (int)context.LocalBounds.Size.X),
+            Math.Min(tempSize.Y, (int)context.LocalBounds.Size.Y));
 
         if (shouldClear)
         {
@@ -195,19 +217,19 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     public override bool RenderPreview(Texture renderOn, VecI chunk, ChunkResolution resolution, int frame)
     {
         var img = GetLayerImageAtFrame(frame);
-        
+
         if (img is null)
         {
             return false;
         }
-        
+
         img.DrawMostUpToDateChunkOn(
             chunk,
             resolution,
             renderOn.DrawingSurface,
             chunk * resolution.PixelSize(),
             blendPaint);
-        
+
         return true;
     }
 
@@ -215,7 +237,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     private void DrawChunk(ChunkyImage frameImage, RenderContext context, Texture tempSurface, VecI vecI,
         Paint paint)
     {
-        VecI chunkPos = context.ChunkToUpdate + vecI;
+        VecI chunkPos = context.ChunkToUpdate.Value + vecI;
         if (frameImage.LatestOrCommittedChunkExists(chunkPos))
         {
             frameImage.DrawMostUpToDateChunkOn(

+ 15 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LayerNode.cs

@@ -14,6 +14,11 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
     protected Dictionary<(ChunkResolution, int), Texture> workingSurfaces =
         new Dictionary<(ChunkResolution, int), Texture>();
 
+    public LayerNode()
+    {
+    }
+
+    
     public override void Render(SceneObjectRenderContext sceneContext)
     {
         if (!IsVisible.Value || Opacity.Value <= 0 || IsEmptyMask())
@@ -55,6 +60,14 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
     {
         if (Output.Connections.Count > 0)
         {
+            //Texture cached = TryInitWorkingSurface(size, context.ChunkResolution, -1);
+            if (context.ChunkToUpdate == null)
+            {
+                //renderOnto.Canvas.DrawSurface(, 0, 0, blendPaint);
+                DrawLayer(context, renderOnto, shouldClear);
+                return;
+            }
+
             if (!HasOperations())
             {
                 if (Background.Value != null)
@@ -63,7 +76,6 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
                 }
                 
                 DrawLayer(context, renderOnto, false);
-
                 return;
             }
 
@@ -88,11 +100,11 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
                 tempSurface.DrawingSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0,
                     blendPaint);
 
-                renderOnto.Canvas.DrawSurface(tempSurface.DrawingSurface, VecI.Zero, blendPaint);
+                //cached.DrawingSurface.Canvas.DrawSurface(tempSurface.DrawingSurface, VecI.Zero, blendPaint);
                 return;
             }
 
-            renderOnto.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0, blendPaint);
+            //cached.DrawingSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0, blendPaint);
         }
     }
 

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

@@ -79,7 +79,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         sceneSurface.Canvas.Translate((float)ScenePosition.X, (float)ScenePosition.Y);
         
         SceneObjectRenderContext renderObjectContext = new SceneObjectRenderContext(sceneSurface, localBounds, 
-            context.FrameTime, context.ChunkToUpdate, context.ChunkResolution, context.DocumentSize);
+            context.FrameTime, context.ChunkResolution, context.DocumentSize) { ChunkToUpdate = context.ChunkToUpdate };
         
         Render(renderObjectContext);
         
@@ -101,10 +101,10 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
             else if (EmbeddedMask != null)
             {
                 EmbeddedMask.DrawMostUpToDateChunkOn(
-                    context.ChunkToUpdate,
+                    context.ChunkToUpdate.Value,
                     context.ChunkResolution,
                     surface,
-                    context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
+                    context.ChunkToUpdate.Value * context.ChunkResolution.PixelSize(),
                     maskPaint);
             }
         }
@@ -171,7 +171,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         }
 
         int chunkSize = (int)Math.Round(context.ChunkResolution.PixelSize() / divider);
-        VecI chunkPos = context.ChunkToUpdate;
+        VecI chunkPos = context.ChunkToUpdate.Value;
 
         int x = (int)(chunkPos.X * chunkSize);
         int y = (int)(chunkPos.Y * chunkSize);
@@ -187,7 +187,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
     protected RectI CalculateDestinationRect(RenderContext context)
     {
         int chunkSize = context.ChunkResolution.PixelSize();
-        VecI chunkPos = context.ChunkToUpdate;
+        VecI chunkPos = context.ChunkToUpdate.Value;
 
         int x = chunkPos.X * chunkSize;
         int y = chunkPos.Y * chunkSize;

+ 18 - 6
src/PixiEditor.ChangeableDocument/Rendering/DocumentRenderer.cs

@@ -13,6 +13,8 @@ namespace PixiEditor.ChangeableDocument.Rendering;
 
 public class DocumentRenderer
 {
+    private Dictionary<ChunkResolution, Texture> updateCanvases = new Dictionary<ChunkResolution, Texture>();
+    
     private Paint ClearPaint { get; } = new Paint()
     {
         BlendMode = BlendMode.Src, Color = PixiEditor.DrawingApi.Core.ColorsImpl.Colors.Transparent
@@ -67,22 +69,32 @@ public class DocumentRenderer
         return toDrawOn;
     }*/
     
-    public OneOf<Chunk, EmptyChunk> RenderChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime,
+    public void RenderChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime,
         RectI? globalClippingRect = null)
     {
-        //RenderingContext context = new(frameTime, chunkPos, resolution, Document.Size);
+        Texture target;
+        if(updateCanvases.TryGetValue(resolution, out Texture canvas))
+        {
+            target = canvas;
+        }
+        else
+        {
+            target = new Texture(Document.Size);
+            updateCanvases[resolution] = target;
+        }
+        
+        RenderContext context = new(target.DrawingSurface, frameTime, resolution, Document.Size);
+        context.ChunkToUpdate = chunkPos;
         try
         {
-            //return RenderChunkOnGraph(chunkPos, resolution, globalClippingRect, Document.NodeGraph, context);
-            return new EmptyChunk();
+            Document.NodeGraph.Execute(context);
         }
         catch (ObjectDisposedException)
         {
-            return new EmptyChunk();
         }
         finally
         {
-            //context.Dispose();
+            context.Dispose();
         }
     }
 

+ 2 - 3
src/PixiEditor.ChangeableDocument/Rendering/RenderContext.cs

@@ -19,7 +19,7 @@ public class RenderContext : IDisposable
     public Paint ReplacingPaintWithOpacity = new() { BlendMode = DrawingApiBlendMode.Src };
 
     public KeyFrameTime FrameTime { get; }
-    public VecI ChunkToUpdate { get; }
+    public VecI? ChunkToUpdate { get; set; }
     public ChunkResolution ChunkResolution { get; }
     public VecI DocumentSize { get; set; }
     
@@ -27,11 +27,10 @@ public class RenderContext : IDisposable
 
     public bool IsDisposed { get; private set; }
     
-    public RenderContext(DrawingSurface targetSurface, KeyFrameTime frameTime, VecI chunkToUpdate, ChunkResolution chunkResolution, VecI docSize)
+    public RenderContext(DrawingSurface targetSurface, KeyFrameTime frameTime, ChunkResolution chunkResolution, VecI docSize)
     {
         TargetSurface = targetSurface;
         FrameTime = frameTime;
-        ChunkToUpdate = chunkToUpdate;
         ChunkResolution = chunkResolution;
         DocumentSize = docSize;
     }

+ 4 - 4
src/PixiEditor.ChangeableDocument/Rendering/SceneRenderer.cs

@@ -9,17 +9,17 @@ public class SceneRenderer
 {
     public IReadOnlyDocument Document { get; }
     
-    private readonly Func<KeyFrameTime> _frameTimeGetter;
+    private readonly Func<KeyFrameTime> getActiveFrameTime;
     
-    public SceneRenderer(IReadOnlyDocument document, Func<KeyFrameTime> frameTimeGetter)
+    public SceneRenderer(IReadOnlyDocument document, Func<KeyFrameTime> getActiveFrameTime)
     {
         Document = document;
-        _frameTimeGetter = frameTimeGetter;
+        this.getActiveFrameTime = getActiveFrameTime;
     }
 
     public void RenderScene(DrawingSurface target)
     {
-        using RenderContext ctx = new(target, _frameTimeGetter(), VecI.Zero, ChunkResolution.Full, Document.Size);
+        using RenderContext ctx = new(target, getActiveFrameTime(), ChunkResolution.Full, Document.Size);
         Document.NodeGraph.Execute(ctx);
     }
 }

+ 5 - 49
src/PixiEditor/Models/Rendering/CanvasUpdater.cs

@@ -211,12 +211,10 @@ internal class CanvasUpdater
             if (globalClippingRectangle is not null)
                 globalScaledClippingRectangle =
                     (RectI?)((RectI)globalClippingRectangle).Scale(resolution.Multiplier()).RoundOutwards();
-
-            /*
-            Texture screenSurface = doc.Surfaces[resolution];
+            
             foreach (var chunkPos in chunks)
             {
-                RenderChunk(chunkPos, screenSurface, resolution, globalClippingRectangle,
+                RenderChunk(chunkPos, resolution, globalClippingRectangle,
                     globalScaledClippingRectangle);
                 RectI chunkRect = new(chunkPos * chunkSize, new(chunkSize, chunkSize));
                 if (globalScaledClippingRectangle is RectI rect)
@@ -228,7 +226,6 @@ internal class CanvasUpdater
                     resolution
                 ));
             }
-        */
         }
     }
 
@@ -331,50 +328,9 @@ internal class CanvasUpdater
         }
     }
 
-    /*private void RenderChunk(VecI chunkPos, Texture screenSurface, ChunkResolution resolution,
+    private void RenderChunk(VecI chunkPos, ChunkResolution resolution,
         RectI? globalClippingRectangle, RectI? globalScaledClippingRectangle)
     {
-        if (screenSurface is null || screenSurface.IsDisposed)
-            return;
-
-
-        doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameTime, globalClippingRectangle)
-            .Switch(
-                (Chunk chunk) =>
-                {
-                    if (screenSurface.IsDisposed) return;
-
-                    if (globalScaledClippingRectangle is not null)
-                    {
-                        screenSurface.DrawingSurface.Canvas.Save();
-                        screenSurface.DrawingSurface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
-                    }
-
-                    screenSurface.DrawingSurface.Canvas.DrawSurface(
-                        chunk.Surface.DrawingSurface,
-                        chunkPos.Multiply(new VecI(resolution.PixelSize())), ReplacingPaint);
-                    chunk.Dispose();
-
-
-                    if (globalScaledClippingRectangle is not null)
-                        screenSurface.DrawingSurface.Canvas.Restore();
-                },
-                (EmptyChunk _) =>
-                {
-                    if (screenSurface.IsDisposed) return;
-
-                    if (globalScaledClippingRectangle is not null)
-                    {
-                        screenSurface.DrawingSurface.Canvas.Save();
-                        screenSurface.DrawingSurface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
-                    }
-
-                    var pos = chunkPos * resolution.PixelSize();
-                    screenSurface.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, resolution.PixelSize(),
-                        resolution.PixelSize(), ClearPaint);
-
-                    if (globalScaledClippingRectangle is not null)
-                        screenSurface.DrawingSurface.Canvas.Restore();
-                });
-    }*/
+        doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameTime, globalClippingRectangle);
+    }
 }

+ 8 - 5
src/PixiEditor/ViewModels/Document/DocumentViewModel.cs

@@ -533,13 +533,15 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
                 {
                     for (int j = 0; j < sizeInChunks.Y; j++)
                     {
-                        var maybeChunk = Renderer.RenderChunk(new(i, j), ChunkResolution.Full, frameTime);
-                        if (maybeChunk.IsT1)
-                            return;
+                        // TODO: Implement this
+                        /*
+                        Renderer.RenderChunk(new(i, j), ChunkResolution.Full, frameTime);
+                        
                         using Chunk chunk = maybeChunk.AsT0;
                         finalSurface.DrawingSurface.Canvas.DrawSurface(
                             chunk.Surface.DrawingSurface,
                             i * ChunkyImage.FullChunkSize, j * ChunkyImage.FullChunkSize);
+                    */
                     }
                 }
             });
@@ -708,7 +710,8 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
             if (scope == DocumentScope.AllLayers)
             {
                 VecI chunkPos = OperationHelper.GetChunkPos(pos, ChunkyImage.FullChunkSize);
-                return Renderer.RenderChunk(chunkPos, ChunkResolution.Full,
+                // TODO: Implement this
+                /*return Renderer.RenderChunk(chunkPos, ChunkResolution.Full,
                         frameTime)
                     .Match(
                         chunk =>
@@ -718,7 +721,7 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
                             chunk.Dispose();
                             return color;
                         },
-                        _ => Colors.Transparent);
+                        _ => Colors.Transparent);*/
             }
 
             if (SelectedStructureMember is not ILayerHandler layerVm)