Browse Source

Direct rendering is working

flabbet 1 year ago
parent
commit
7ff5029f36

+ 1 - 0
src/PixiEditor.DrawingApi.Core/Bridge/Operations/ISurfaceImplementation.cs

@@ -17,5 +17,6 @@ public interface ISurfaceImplementation
     public void Dispose(DrawingSurface drawingSurface);
     public object GetNativeSurface(IntPtr objectPointer);
     public void Flush(DrawingSurface drawingSurface);
+    public DrawingSurface CreateFromNative(object native);
 }
 

+ 5 - 0
src/PixiEditor.DrawingApi.Core/Surfaces/DrawingSurface.cs

@@ -80,5 +80,10 @@ namespace PixiEditor.DrawingApi.Core.Surfaces
         {
             DrawingBackendApi.Current.SurfaceImplementation.Flush(this);
         }
+
+        public static DrawingSurface CreateFromNative(object native)
+        {
+            return DrawingBackendApi.Current.SurfaceImplementation.CreateFromNative(native);
+        }
     }
 }

+ 18 - 1
src/PixiEditor.DrawingApi.Core/Texture.cs

@@ -11,7 +11,7 @@ namespace PixiEditor.DrawingApi.Core;
 public class Texture : IDisposable
 {
     public VecI Size { get; }
-    public DrawingSurface Surface { get; }
+    public DrawingSurface Surface { get; private set; }
 
     public event SurfaceChangedEventHandler? Changed;
 
@@ -33,6 +33,17 @@ public class Texture : IDisposable
         Surface.Changed += SurfaceOnChanged;
     }
 
+    internal Texture(DrawingSurface surface)
+    {
+        Surface = surface;
+        Surface.Changed += SurfaceOnChanged;
+    }
+    
+    ~Texture()
+    {
+       Surface.Changed -= SurfaceOnChanged;
+    }
+
     private void SurfaceOnChanged(RectD? changedRect)
     {
         Changed?.Invoke(changedRect);
@@ -123,4 +134,10 @@ public class Texture : IDisposable
         Surface.Changed -= SurfaceOnChanged;
         Surface.Dispose();
     }
+
+    public static Texture FromExisting(DrawingSurface drawingSurface)
+    {
+        Texture texture = new(drawingSurface);
+        return texture;
+    }
 }

+ 10 - 0
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaSurfaceImplementation.cs

@@ -156,5 +156,15 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         {
             ManagedInstances[drawingSurface.ObjectPointer].Flush(true, true);
         }
+
+        public DrawingSurface CreateFromNative(object native)
+        {
+            if (native is not SKSurface skSurface)
+            {
+                throw new ArgumentException("Native object is not of type SKSurface");
+            }
+
+            return CreateDrawingSurface(skSurface);
+        }
     }
 }

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

@@ -2,9 +2,11 @@
 using System.Linq;
 using Avalonia.Platform;
 using Avalonia.Threading;
+using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.ChangeInfos;
+using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DocumentPassthroughActions;
@@ -12,6 +14,7 @@ using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Rendering;
 using PixiEditor.Models.Rendering.RenderInfos;
 using PixiEditor.Numerics;
+using PixiEditor.Views.Rendering;
 
 namespace PixiEditor.Models.DocumentModels;
 #nullable enable
@@ -33,6 +36,12 @@ internal class ActionAccumulator
 
         canvasUpdater = new(doc, internals);
         previewUpdater = new(doc, internals);
+        Scene.Paint += SceneOnPaint;
+    }
+
+    private void SceneOnPaint(Texture obj)
+    {
+        canvasUpdater.Render(obj, ChunkResolution.Full); 
     }
 
     public void AddFinishedActions(params IAction[] actions)
@@ -89,10 +98,9 @@ internal class ActionAccumulator
             if (undoBoundaryPassed)
                 internals.Updater.AfterUndoBoundaryPassed();
 
-            // update the contents of the bitmaps
             var affectedAreas = new AffectedAreasGatherer(document.AnimationHandler.ActiveFrameTime, internals.Tracker, optimizedChanges);
             List<IRenderInfo> renderResult = new();
-            renderResult.AddRange(await canvasUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed || viewportRefreshRequest));
+            //await canvasUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed || viewportRefreshRequest);
             renderResult.AddRange(await previewUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed));
 
             if (undoBoundaryPassed)

+ 74 - 47
src/PixiEditor/Models/Rendering/CanvasUpdater.cs

@@ -13,6 +13,7 @@ using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Rendering.RenderInfos;
 using PixiEditor.Numerics;
+using PixiEditor.Views.Rendering;
 
 namespace PixiEditor.Models.Rendering;
 #nullable enable
@@ -21,7 +22,7 @@ internal class CanvasUpdater
     private readonly IDocument doc;
     private readonly DocumentInternalParts internals;
 
-    private static readonly Paint ReplacingPaint = new() { BlendMode = BlendMode.Src };
+    private static readonly Paint ReplacingPaint = new() { BlendMode = BlendMode.SrcOver };
 
     private static readonly Paint ClearPaint = new()
     {
@@ -52,6 +53,15 @@ internal class CanvasUpdater
             [ChunkResolution.Eighth] = new()
         };
 
+    private Dictionary<ChunkResolution, HashSet<VecI>> nextRepaint =
+        new()
+        {
+            [ChunkResolution.Full] = new(),
+            [ChunkResolution.Half] = new(),
+            [ChunkResolution.Quarter] = new(),
+            [ChunkResolution.Eighth] = new()
+        };
+
 
     public CanvasUpdater(IDocument doc, DocumentInternalParts internals)
     {
@@ -62,19 +72,44 @@ internal class CanvasUpdater
     /// <summary>
     /// Don't call this outside ActionAccumulator
     /// </summary>
-    public async Task<List<IRenderInfo>> UpdateGatheredChunks
+    public async Task UpdateGatheredChunks
         (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
     {
-        return await Task.Run(() => Render(chunkGatherer, rerenderDelayed)).ConfigureAwait(true);
+        await Task.Run(() => QueueChunksToRender(chunkGatherer, rerenderDelayed)).ConfigureAwait(true);
     }
 
     /// <summary>
     /// Don't call this outside ActionAccumulator
     /// </summary>
-    public List<IRenderInfo> UpdateGatheredChunksSync
+    public void UpdateGatheredChunksSync
         (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
     {
-        return Render(chunkGatherer, rerenderDelayed);
+        QueueChunksToRender(chunkGatherer, rerenderDelayed);
+    }
+
+    public void Render(Texture screenSurface, RectI? globalClippingRectangle)
+    {
+        UpdateMainImage(screenSurface, nextRepaint, globalClippingRectangle,
+            null);
+        
+        nextRepaint.Clear();
+    }
+
+    public void Render(Texture screenSurface, ChunkResolution resolution)
+    {
+        VecI chunks = new VecI(
+            (int)Math.Ceiling(doc.SizeBindable.X / (float)resolution.PixelSize()),
+            (int)Math.Ceiling(doc.SizeBindable.Y / (float)resolution.PixelSize()));
+        
+        RectI globalClippingRectangle = new RectI(new VecI(0, 0), doc.SizeBindable);
+        
+        for (int x = 0; x < chunks.X; x++)
+        {
+            for (int y = 0; y < chunks.Y; y++)
+            {
+                RenderChunk(new VecI(x, y), screenSurface, resolution, globalClippingRectangle, null);
+            }
+        }
     }
 
     private Dictionary<ChunkResolution, HashSet<VecI>> FindChunksVisibleOnViewports(bool onDelayed, bool all)
@@ -152,7 +187,7 @@ internal class CanvasUpdater
         }
     }
 
-    private List<IRenderInfo> Render(AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
+    private void QueueChunksToRender(AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
     {
         Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender =
             FindGlobalChunksToRerender(chunkGatherer, rerenderDelayed);
@@ -178,15 +213,14 @@ internal class CanvasUpdater
         }
 
         if (!anythingToUpdate)
-            return new();
+            return;
 
-        List<IRenderInfo> infos = new();
-        UpdateMainImage(chunksToRerender, updatingStoredChunks ? null : chunkGatherer.MainImageArea.GlobalArea.Value,
-            infos);
-        return infos;
+        nextRepaint = chunksToRerender;
     }
 
-    private void UpdateMainImage(Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender,
+    private void UpdateMainImage(
+        Texture screenSurface,
+        Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender,
         RectI? globalClippingRectangle, List<IRenderInfo> infos)
     {
         foreach (var (resolution, chunks) in chunksToRerender)
@@ -197,7 +231,7 @@ internal class CanvasUpdater
                 globalScaledClippingRectangle =
                     (RectI?)((RectI)globalClippingRectangle).Scale(resolution.Multiplier()).RoundOutwards();
 
-            Texture screenSurface = doc.Surfaces[resolution];
+            //Texture screenSurface = doc.Surfaces[resolution];
             foreach (var chunkPos in chunks)
             {
                 RenderChunk(chunkPos, screenSurface, resolution, globalClippingRectangle,
@@ -206,11 +240,11 @@ internal class CanvasUpdater
                 if (globalScaledClippingRectangle is RectI rect)
                     chunkRect = chunkRect.Intersect(rect);
 
-                infos.Add(new DirtyRect_RenderInfo(
+                /*infos.Add(new DirtyRect_RenderInfo(
                     chunkRect.Pos,
                     chunkRect.Size,
                     resolution
-                ));
+                ));*/
             }
         }
     }
@@ -221,50 +255,43 @@ internal class CanvasUpdater
         if (screenSurface is null || screenSurface.IsDisposed)
             return;
 
-
         doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameTime, globalClippingRectangle)
             .Switch(
                 (Chunk chunk) =>
                 {
-                    Dispatcher.UIThread.Post(() =>
-                    {
-                        if (screenSurface.IsDisposed) return;
+                    if (screenSurface.IsDisposed) return;
 
-                        if (globalScaledClippingRectangle is not null)
-                        {
-                            screenSurface.Surface.Canvas.Save();
-                            screenSurface.Surface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
-                        }
+                    if (globalScaledClippingRectangle is not null)
+                    {
+                        screenSurface.Surface.Canvas.Save();
+                        screenSurface.Surface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
+                    }
 
-                        screenSurface.Surface.Canvas.DrawSurface(
-                            chunk.Surface.DrawingSurface,
-                            chunkPos.Multiply(chunk.PixelSize), ReplacingPaint);
-                        chunk.Dispose();
+                    screenSurface.Surface.Canvas.DrawSurface(
+                        chunk.Surface.DrawingSurface,
+                        chunkPos.Multiply(chunk.PixelSize), ReplacingPaint);
+                    chunk.Dispose();
 
 
-                        if (globalScaledClippingRectangle is not null)
-                            screenSurface.Surface.Canvas.Restore();
-                    });
+                    if (globalScaledClippingRectangle is not null)
+                        screenSurface.Surface.Canvas.Restore();
                 },
                 (EmptyChunk _) =>
                 {
-                    Dispatcher.UIThread.Post(() =>
+                    if (screenSurface.IsDisposed) return;
+
+                    /*if (globalScaledClippingRectangle is not null)
                     {
-                        if (screenSurface.IsDisposed) return;
-
-                        if (globalScaledClippingRectangle is not null)
-                        {
-                            screenSurface.Surface.Canvas.Save();
-                            screenSurface.Surface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
-                        }
-
-                        var pos = chunkPos * resolution.PixelSize();
-                        screenSurface.Surface.Canvas.DrawRect(pos.X, pos.Y, resolution.PixelSize(),
-                            resolution.PixelSize(), ClearPaint);
-                        
-                        if (globalScaledClippingRectangle is not null)
-                            screenSurface.Surface.Canvas.Restore();
-                    });
+                        screenSurface.Surface.Canvas.Save();
+                        screenSurface.Surface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
+                    }*/
+
+                    var pos = chunkPos * resolution.PixelSize();
+                    screenSurface.Surface.Canvas.DrawRect(pos.X, pos.Y, resolution.PixelSize(),
+                        resolution.PixelSize(), ClearPaint);
+
+                    /*if (globalScaledClippingRectangle is not null)
+                        screenSurface.Surface.Canvas.Restore();*/
                 });
     }
 }

+ 30 - 12
src/PixiEditor/Views/Rendering/Scene.cs

@@ -15,6 +15,7 @@ using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surfaces;
 using PixiEditor.DrawingApi.Skia;
 using PixiEditor.DrawingApi.Skia.Extensions;
 using PixiEditor.Extensions.UI.Overlays;
@@ -107,6 +108,8 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
     private List<Overlay> mouseOverOverlays = new();
 
     private double sceneOpacity = 1;
+    
+    private static Scene instance;
 
     static Scene()
     {
@@ -136,9 +139,16 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
         };
     }
 
+    public static event Action<Texture> Paint;
+
+    public static void RequestRender()
+    {
+        instance.QueueRender();
+    }
+
     public override void Render(DrawingContext context)
     {
-        if (Surface == null || Document == null) return;
+        //if (Surface == null || Document == null) return;
 
         float angle = (float)MathUtil.RadiansToDegrees(AngleRadians);
 
@@ -147,8 +157,8 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
         RectD dirtyBounds = new RectD(0, 0, Document.Width / resolutionScale, Document.Height / resolutionScale);
         Rect dirtyRect = new Rect(0, 0, Document.Width / resolutionScale, Document.Height / resolutionScale);
 
-        Surface.Surface.Flush();
-        using var operation = new DrawSceneOperation(Surface, Document, CanvasPos, Scale * resolutionScale, angle,
+        //Surface.Surface.Flush();
+        using var operation = new DrawSceneOperation(Paint, Document, CanvasPos, Scale * resolutionScale, angle,
             FlipX, FlipY,
             dirtyRect,
             Bounds,
@@ -490,15 +500,18 @@ internal class DrawSceneOperation : SkiaDrawOperation
 
     public RectI SurfaceRectToRender { get; }
 
+    public event Action<Texture> Paint;
+
     private SKPaint _paint = new SKPaint();
 
     private bool hardwareAccelerationAvailable = DrawingBackendApi.Current.IsHardwareAccelerated;
 
-    public DrawSceneOperation(Texture surface, DocumentViewModel document, VecD contentPosition, double scale,
+    public DrawSceneOperation(Action<Texture> paint, DocumentViewModel document, VecD contentPosition, double scale,
         double angle, bool flipX, bool flipY, Rect dirtyBounds, Rect viewportBounds, double opacity,
         ColorMatrix colorMatrix) : base(dirtyBounds)
     {
-        Surface = surface;
+        //Surface = surface;
+        Paint += paint;
         Document = document;
         ContentPosition = contentPosition;
         Scale = scale;
@@ -508,30 +521,35 @@ internal class DrawSceneOperation : SkiaDrawOperation
         ColorMatrix = colorMatrix;
         ViewportBounds = viewportBounds;
         _paint.Color = _paint.Color.WithAlpha((byte)(opacity * 255));
-        SurfaceRectToRender = FindRectToRender((float)scale);
+        //SurfaceRectToRender = FindRectToRender((float)scale);
+        SurfaceRectToRender = new RectI(VecI.Zero, Document.SizeBindable);
     }
 
     public override void Render(ISkiaSharpApiLease lease)
     {
-        if (Surface == null || Surface.IsDisposed || Document == null) return;
+        //if (Surface == null || Surface.IsDisposed || Document == null) return;
 
         SKCanvas canvas = lease.SkCanvas;
 
         canvas.Save();
 
-        if (SurfaceRectToRender.IsZeroOrNegativeArea)
+        /*if (SurfaceRectToRender.IsZeroOrNegativeArea)
         {
             canvas.Restore();
             return;
-        }
+        }*/
 
         using var ctx = DrawingBackendApi.Current.RenderOnDifferentGrContext(lease.GrContext);
 
-
         var matrixValues = new float[ColorMatrix.Width * ColorMatrix.Height];
         ColorMatrix.TryGetMembers(matrixValues);
 
-        _paint.ColorFilter = SKColorFilter.CreateColorMatrix(matrixValues);
+        DrawingSurface drawingSurface = DrawingSurface.CreateFromNative(lease.SkSurface);
+        Texture texture = Texture.FromExisting(drawingSurface);
+        
+        Paint?.Invoke(texture);
+        
+        /*_paint.ColorFilter = SKColorFilter.CreateColorMatrix(matrixValues);
 
         if (!hardwareAccelerationAvailable)
         {
@@ -543,7 +561,7 @@ internal class DrawSceneOperation : SkiaDrawOperation
         else
         {
             canvas.DrawSurface(Surface.Surface.Native as SKSurface, 0, 0, _paint);
-        }
+        }*/
 
         canvas.Restore();
     }