Browse Source

Layer and folder preview is now gpu accelerated

flabbet 11 months ago
parent
commit
dcf9d3da31

+ 1 - 4
src/PixiEditor.Desktop/Program.cs

@@ -21,9 +21,6 @@ public class Program
                 RenderingMode = new Win32RenderingMode[] { Win32RenderingMode.Wgl, Win32RenderingMode.AngleEgl },
                 OverlayPopups = true
             })
-            .With(new SkiaOptions()
-            {
-                MaxGpuResourceSizeBytes = 1024 * 1024 * 1024,
-            })
+           
             .LogToTrace();
 }

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

@@ -21,5 +21,6 @@ namespace PixiEditor.DrawingApi.Core.Bridge
         public IColorFilterImplementation ColorFilterImplementation { get; }
         public IImageFilterImplementation ImageFilterImplementation { get; }
         public IShaderImplementation ShaderImplementation { get; set; }
+        public bool IsHardwareAccelerated { get; }
     }
 }

+ 41 - 19
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaSurfaceImplementation.cs

@@ -15,7 +15,7 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         private readonly SkiaCanvasImplementation _canvasImplementation;
         private readonly SkiaPaintImplementation _paintImplementation;
 
-        internal GRContext GrContext { get; set; }
+        internal GRContext? GrContext { get; set; }
 
         public SkiaSurfaceImplementation(GRContext context, SkiaPixmapImplementation pixmapImplementation,
             SkiaCanvasImplementation canvasImplementation, SkiaPaintImplementation paintImplementation)
@@ -55,41 +55,63 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
 
         public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixels, int rowBytes)
         {
-            SKSurface skSurface = CreateSkiaSurface(imageInfo.ToSkImageInfo(), imageInfo.GpuBacked);
-
-            using var image = SKImage.FromPixelCopy(imageInfo.ToSkImageInfo(), pixels, rowBytes);
-
-            var canvas = skSurface.Canvas;
-            canvas.DrawImage(image, new SKPoint(0, 0));
-
+            SKSurface skSurface = CreateSkiaSurface(imageInfo.ToSkImageInfo(), imageInfo.GpuBacked, pixels, rowBytes);
             return CreateDrawingSurface(skSurface);
         }
 
         public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixelBuffer)
         {
             SKImageInfo info = imageInfo.ToSkImageInfo();
-            SKSurface skSurface = CreateSkiaSurface(info, imageInfo.GpuBacked);
+            SKSurface skSurface = CreateSkiaSurface(info, imageInfo.GpuBacked, pixelBuffer);
+            return CreateDrawingSurface(skSurface);
+        }
 
-            using var image = SKImage.FromPixelCopy(info, pixelBuffer);
+        private SKSurface CreateSkiaSurface(SKImageInfo imageInfo, bool isGpuBacked, IntPtr pixels, int rowBytes)
+        {
+            if (isGpuBacked)
+            {
+                SKSurface skSurface = CreateSkiaSurface(imageInfo, true);
+                using var image = SKImage.FromPixelCopy(imageInfo, pixels, rowBytes);
 
-            var canvas = skSurface.Canvas;
-            canvas.DrawImage(image, new SKPoint(0, 0));
+                var canvas = skSurface.Canvas;
+                canvas.DrawImage(image, new SKPoint(0, 0));
 
-            return CreateDrawingSurface(skSurface);
+                return skSurface;
+            }
+
+            return SKSurface.Create(imageInfo, pixels, rowBytes);
+        }
+
+        private SKSurface CreateSkiaSurface(SKImageInfo imageInfo, bool isGpuBacked, IntPtr pixels)
+        {
+            if (isGpuBacked)
+            {
+                SKSurface skSurface = CreateSkiaSurface(imageInfo, true);
+                using var image = SKImage.FromPixelCopy(imageInfo, pixels);
+
+                var canvas = skSurface.Canvas;
+                canvas.DrawImage(image, new SKPoint(0, 0));
+
+                return skSurface;
+            }
+
+            return SKSurface.Create(imageInfo, pixels);
         }
 
         public DrawingSurface Create(Pixmap pixmap)
         {
             SKPixmap skPixmap = _pixmapImplementation[pixmap.ObjectPointer];
-            SKImageInfo info = skPixmap.Info;
-            SKSurface skSurface = CreateSkiaSurface(info, true);
-
-            var canvas = skSurface.Canvas;
-            canvas.DrawImage(SKImage.FromPixels(skPixmap), new SKPoint(0, 0));
+            var skSurface = CreateSkiaSurface(skPixmap);
 
             return CreateDrawingSurface(skSurface);
         }
 
+        private SKSurface CreateSkiaSurface(SKPixmap skPixmap)
+        {
+            SKSurface skSurface = SKSurface.Create(skPixmap); 
+            return skSurface;
+        }
+
         public DrawingSurface Create(ImageInfo imageInfo)
         {
             SKSurface skSurface = CreateSkiaSurface(imageInfo.ToSkImageInfo(), imageInfo.GpuBacked);
@@ -98,7 +120,7 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
 
         private SKSurface CreateSkiaSurface(SKImageInfo info, bool gpu)
         {
-            if (!gpu)
+            if (!gpu || GrContext == null)
             {
                 return SKSurface.Create(info);
             }

+ 1 - 1
src/PixiEditor.DrawingApi.Skia/SkiaDrawingBackend.cs

@@ -23,7 +23,7 @@ namespace PixiEditor.DrawingApi.Skia
             }
         }
         
-        public bool IsGpuAccelerated => GraphicsContext != null;
+        public bool IsHardwareAccelerated => GraphicsContext != null;
         
         public IColorImplementation ColorImplementation { get; }
         public IImageImplementation ImageImplementation { get; }

+ 80 - 48
src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs

@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Threading.Tasks;
+using Avalonia.Threading;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
@@ -12,6 +13,7 @@ using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core;
+using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surfaces;
 using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
@@ -537,9 +539,9 @@ internal class MemberPreviewUpdater
         IReadOnlyStructureNode member, [DisallowNull] AffectedArea? affArea, VecI position, float scaling)
     {
         bool isEditingRootImage = !member.KeyFrames.Any(x => x.IsInFrame(doc.AnimationHandler.ActiveFrameBindable));
-        if(!isEditingRootImage)
+        if (!isEditingRootImage)
             return;
-        
+
         if (keyFrame.PreviewSurface == null ||
             keyFrame.PreviewSurface.Size != memberVM.PreviewSurface.Size)
         {
@@ -558,6 +560,10 @@ internal class MemberPreviewUpdater
         AffectedArea area,
         VecI position, float scaling)
     {
+        PostRender(() =>
+        {
+            
+        
         memberVM.PreviewSurface.Surface.Canvas.Save();
         memberVM.PreviewSurface.Surface.Canvas.Scale(scaling);
         memberVM.PreviewSurface.Surface.Canvas.Translate(-position);
@@ -595,6 +601,7 @@ internal class MemberPreviewUpdater
         }
 
         memberVM.PreviewSurface.Surface.Canvas.Restore();
+        });
     }
 
     /// <summary>
@@ -603,29 +610,31 @@ internal class MemberPreviewUpdater
     private void RenderLayerMainPreview(IReadOnlyLayerNode layer, Texture surface, AffectedArea area,
         VecI position, float scaling, int frame)
     {
-        surface.Surface.Canvas.Save();
-        surface.Surface.Canvas.Scale(scaling);
-        surface.Surface.Canvas.Translate(-position);
-        surface.Surface.Canvas.ClipRect((RectD)area.GlobalArea);
-
-        foreach (var chunk in area.Chunks)
+        PostRender(() =>
         {
-            var pos = chunk * ChunkResolution.Full.PixelSize();
-            if (layer is not IReadOnlyImageNode raster) return;
-            IReadOnlyChunkyImage? result = raster.GetLayerImageAtFrame(frame);
+            surface.Surface.Canvas.Save();
+            surface.Surface.Canvas.Scale(scaling);
+            surface.Surface.Canvas.Translate(-position);
+            surface.Surface.Canvas.ClipRect((RectD)area.GlobalArea);
 
-            if (!result.DrawCommittedChunkOn(
-                    chunk,
-                    ChunkResolution.Full, surface.Surface, pos,
-                    scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint))
+            foreach (var chunk in area.Chunks)
             {
-                surface.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
-                    ChunkyImage.FullChunkSize, ClearPaint);
+                var pos = chunk * ChunkResolution.Full.PixelSize();
+                if (layer is not IReadOnlyImageNode raster) return;
+                IReadOnlyChunkyImage? result = raster.GetLayerImageAtFrame(frame);
+
+                if (!result.DrawCommittedChunkOn(
+                        chunk,
+                        ChunkResolution.Full, surface.Surface, pos,
+                        scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint))
+                {
+                    surface.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
+                        ChunkyImage.FullChunkSize, ClearPaint);
+                }
             }
-        }
 
-        surface.Surface.Canvas.Restore();
-        surface.Surface.Flush();
+            surface.Surface.Canvas.Restore();
+        });
     }
 
     private void RenderAnimationFramePreview(IReadOnlyImageNode node, IKeyFrameHandler keyFrameVM, AffectedArea area)
@@ -636,21 +645,24 @@ internal class MemberPreviewUpdater
                 new Texture(StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size));
         }
 
-        keyFrameVM.PreviewSurface!.Surface.Canvas.Save();
-        float scaling = (float)keyFrameVM.PreviewSurface.Size.X / internals.Tracker.Document.Size.X;
-        keyFrameVM.PreviewSurface.Surface.Canvas.Scale(scaling);
-        foreach (var chunk in area.Chunks)
+        PostRender(() =>
         {
-            var pos = chunk * ChunkResolution.Full.PixelSize();
-            if (!node.GetLayerImageByKeyFrameGuid(keyFrameVM.Id).DrawCommittedChunkOn(chunk, ChunkResolution.Full,
-                    keyFrameVM.PreviewSurface!.Surface, pos, ReplacingPaint))
+            keyFrameVM.PreviewSurface!.Surface.Canvas.Save();
+            float scaling = (float)keyFrameVM.PreviewSurface.Size.X / internals.Tracker.Document.Size.X;
+            keyFrameVM.PreviewSurface.Surface.Canvas.Scale(scaling);
+            foreach (var chunk in area.Chunks)
             {
-                keyFrameVM.PreviewSurface!.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
-                    ChunkyImage.FullChunkSize, ClearPaint);
+                var pos = chunk * ChunkResolution.Full.PixelSize();
+                if (!node.GetLayerImageByKeyFrameGuid(keyFrameVM.Id).DrawCommittedChunkOn(chunk, ChunkResolution.Full,
+                        keyFrameVM.PreviewSurface!.Surface, pos, ReplacingPaint))
+                {
+                    keyFrameVM.PreviewSurface!.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
+                        ChunkyImage.FullChunkSize, ClearPaint);
+                }
             }
-        }
 
-        keyFrameVM.PreviewSurface!.Surface.Canvas.Restore();
+            keyFrameVM.PreviewSurface!.Surface.Canvas.Restore();
+        });
     }
 
     private void RenderMaskPreviews(
@@ -696,19 +708,23 @@ internal class MemberPreviewUpdater
 
             var member = internals.Tracker.Document.FindMemberOrThrow(guid);
 
-            memberVM.MaskPreviewSurface!.Surface.Canvas.Save();
-            memberVM.MaskPreviewSurface.Surface.Canvas.Scale(scaling);
-            memberVM.MaskPreviewSurface.Surface.Canvas.Translate(-position);
-            memberVM.MaskPreviewSurface.Surface.Canvas.ClipRect((RectD)affArea.Value.GlobalArea);
-            foreach (var chunk in affArea.Value.Chunks)
+            PostRender(() =>
             {
-                var pos = chunk * ChunkResolution.Full.PixelSize();
-                member.Mask!.Value.DrawMostUpToDateChunkOn
-                (chunk, ChunkResolution.Full, memberVM.MaskPreviewSurface.Surface, pos,
-                    scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint);
-            }
+                memberVM.MaskPreviewSurface!.Surface.Canvas.Save();
+                memberVM.MaskPreviewSurface.Surface.Canvas.Scale(scaling);
+                memberVM.MaskPreviewSurface.Surface.Canvas.Translate(-position);
+                memberVM.MaskPreviewSurface.Surface.Canvas.ClipRect((RectD)affArea.Value.GlobalArea);
+                foreach (var chunk in affArea.Value.Chunks)
+                {
+                    var pos = chunk * ChunkResolution.Full.PixelSize();
+                    member.Mask!.Value.DrawMostUpToDateChunkOn
+                    (chunk, ChunkResolution.Full, memberVM.MaskPreviewSurface.Surface, pos,
+                        scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint);
+                }
+
+                memberVM.MaskPreviewSurface.Surface.Canvas.Restore();
+            });
 
-            memberVM.MaskPreviewSurface.Surface.Canvas.Restore();
             infos.Add(new MaskPreviewDirty_RenderInfo(guid));
         }
     }
@@ -740,16 +756,32 @@ internal class MemberPreviewUpdater
             float scalingX = (float)nodeVm.ResultPreview.Size.X / node.CachedResult.Size.X;
             float scalingY = (float)nodeVm.ResultPreview.Size.Y / node.CachedResult.Size.Y;
 
-            nodeVm.ResultPreview.Surface.Canvas.Save();
-            nodeVm.ResultPreview.Surface.Canvas.Scale(scalingX, scalingY);
+            PostRender(() =>
+            {
+                nodeVm.ResultPreview.Surface.Canvas.Save();
+                nodeVm.ResultPreview.Surface.Canvas.Scale(scalingX, scalingY);
 
-            RectI region = new RectI(0, 0, node.CachedResult.Size.X, node.CachedResult.Size.Y);
+                RectI region = new RectI(0, 0, node.CachedResult.Size.X, node.CachedResult.Size.Y);
 
-            nodeVm.ResultPreview.Surface.Canvas.DrawSurface(node.CachedResult.DrawingSurface, 0, 0,
-                ReplacingPaint);
+                nodeVm.ResultPreview.Surface.Canvas.DrawSurface(node.CachedResult.DrawingSurface, 0, 0,
+                    ReplacingPaint);
+
+                nodeVm.ResultPreview.Surface.Canvas.Restore();
+            });
 
-            nodeVm.ResultPreview.Surface.Canvas.Restore();
             infos.Add(new NodePreviewDirty_RenderInfo(node.Id));
         }
     }
+
+    private void PostRender(Action action)
+    {
+        if (!DrawingBackendApi.Current.IsHardwareAccelerated)
+        {
+            action();
+        }
+        else
+        {
+            Dispatcher.UIThread.Post(action, DispatcherPriority.Render);
+        }
+    }
 }

+ 7 - 2
src/PixiEditor/Views/Visuals/TextureControl.cs

@@ -106,11 +106,11 @@ internal class DrawTextureOperation : SkiaDrawOperation
 {
     public Stretch Stretch { get; }
     public VecD TargetSize { get; }
-    public Texture Texture { get; }
+    public Texture? Texture { get; }
     public Paint? Paint { get; }
     
 
-    public DrawTextureOperation(Rect dirtyBounds, Stretch stretch, Texture texture, Paint paint = null) :
+    public DrawTextureOperation(Rect dirtyBounds, Stretch stretch, Texture? texture, Paint paint = null) :
         base(dirtyBounds)
     {
         Stretch = stretch;
@@ -121,6 +121,11 @@ internal class DrawTextureOperation : SkiaDrawOperation
 
     public override void Render(ISkiaSharpApiLease lease)
     {
+        if (Texture == null || Texture.IsDisposed)
+        {
+            return;
+        }
+        
         SKCanvas canvas = lease.SkCanvas;
 
         using var ctx = DrawingBackendApi.Current.RenderOnDifferentGrContext(lease.GrContext);