Просмотр исходного кода

Layer and folder preview is now gpu accelerated

flabbet 11 месяцев назад
Родитель
Сommit
dcf9d3da31

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

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

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

@@ -21,5 +21,6 @@ namespace PixiEditor.DrawingApi.Core.Bridge
         public IColorFilterImplementation ColorFilterImplementation { get; }
         public IColorFilterImplementation ColorFilterImplementation { get; }
         public IImageFilterImplementation ImageFilterImplementation { get; }
         public IImageFilterImplementation ImageFilterImplementation { get; }
         public IShaderImplementation ShaderImplementation { get; set; }
         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 SkiaCanvasImplementation _canvasImplementation;
         private readonly SkiaPaintImplementation _paintImplementation;
         private readonly SkiaPaintImplementation _paintImplementation;
 
 
-        internal GRContext GrContext { get; set; }
+        internal GRContext? GrContext { get; set; }
 
 
         public SkiaSurfaceImplementation(GRContext context, SkiaPixmapImplementation pixmapImplementation,
         public SkiaSurfaceImplementation(GRContext context, SkiaPixmapImplementation pixmapImplementation,
             SkiaCanvasImplementation canvasImplementation, SkiaPaintImplementation paintImplementation)
             SkiaCanvasImplementation canvasImplementation, SkiaPaintImplementation paintImplementation)
@@ -55,41 +55,63 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
 
 
         public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixels, int rowBytes)
         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);
             return CreateDrawingSurface(skSurface);
         }
         }
 
 
         public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixelBuffer)
         public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixelBuffer)
         {
         {
             SKImageInfo info = imageInfo.ToSkImageInfo();
             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)
         public DrawingSurface Create(Pixmap pixmap)
         {
         {
             SKPixmap skPixmap = _pixmapImplementation[pixmap.ObjectPointer];
             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);
             return CreateDrawingSurface(skSurface);
         }
         }
 
 
+        private SKSurface CreateSkiaSurface(SKPixmap skPixmap)
+        {
+            SKSurface skSurface = SKSurface.Create(skPixmap); 
+            return skSurface;
+        }
+
         public DrawingSurface Create(ImageInfo imageInfo)
         public DrawingSurface Create(ImageInfo imageInfo)
         {
         {
             SKSurface skSurface = CreateSkiaSurface(imageInfo.ToSkImageInfo(), imageInfo.GpuBacked);
             SKSurface skSurface = CreateSkiaSurface(imageInfo.ToSkImageInfo(), imageInfo.GpuBacked);
@@ -98,7 +120,7 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
 
 
         private SKSurface CreateSkiaSurface(SKImageInfo info, bool gpu)
         private SKSurface CreateSkiaSurface(SKImageInfo info, bool gpu)
         {
         {
-            if (!gpu)
+            if (!gpu || GrContext == null)
             {
             {
                 return SKSurface.Create(info);
                 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 IColorImplementation ColorImplementation { get; }
         public IImageImplementation ImageImplementation { 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.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using Avalonia.Threading;
 using ChunkyImageLib;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
 using ChunkyImageLib.Operations;
@@ -12,6 +13,7 @@ using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core;
+using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surfaces;
 using PixiEditor.DrawingApi.Core.Surfaces;
 using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
 using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
@@ -537,9 +539,9 @@ internal class MemberPreviewUpdater
         IReadOnlyStructureNode member, [DisallowNull] AffectedArea? affArea, VecI position, float scaling)
         IReadOnlyStructureNode member, [DisallowNull] AffectedArea? affArea, VecI position, float scaling)
     {
     {
         bool isEditingRootImage = !member.KeyFrames.Any(x => x.IsInFrame(doc.AnimationHandler.ActiveFrameBindable));
         bool isEditingRootImage = !member.KeyFrames.Any(x => x.IsInFrame(doc.AnimationHandler.ActiveFrameBindable));
-        if(!isEditingRootImage)
+        if (!isEditingRootImage)
             return;
             return;
-        
+
         if (keyFrame.PreviewSurface == null ||
         if (keyFrame.PreviewSurface == null ||
             keyFrame.PreviewSurface.Size != memberVM.PreviewSurface.Size)
             keyFrame.PreviewSurface.Size != memberVM.PreviewSurface.Size)
         {
         {
@@ -558,6 +560,10 @@ internal class MemberPreviewUpdater
         AffectedArea area,
         AffectedArea area,
         VecI position, float scaling)
         VecI position, float scaling)
     {
     {
+        PostRender(() =>
+        {
+            
+        
         memberVM.PreviewSurface.Surface.Canvas.Save();
         memberVM.PreviewSurface.Surface.Canvas.Save();
         memberVM.PreviewSurface.Surface.Canvas.Scale(scaling);
         memberVM.PreviewSurface.Surface.Canvas.Scale(scaling);
         memberVM.PreviewSurface.Surface.Canvas.Translate(-position);
         memberVM.PreviewSurface.Surface.Canvas.Translate(-position);
@@ -595,6 +601,7 @@ internal class MemberPreviewUpdater
         }
         }
 
 
         memberVM.PreviewSurface.Surface.Canvas.Restore();
         memberVM.PreviewSurface.Surface.Canvas.Restore();
+        });
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -603,29 +610,31 @@ internal class MemberPreviewUpdater
     private void RenderLayerMainPreview(IReadOnlyLayerNode layer, Texture surface, AffectedArea area,
     private void RenderLayerMainPreview(IReadOnlyLayerNode layer, Texture surface, AffectedArea area,
         VecI position, float scaling, int frame)
         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)
     private void RenderAnimationFramePreview(IReadOnlyImageNode node, IKeyFrameHandler keyFrameVM, AffectedArea area)
@@ -636,21 +645,24 @@ internal class MemberPreviewUpdater
                 new Texture(StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size));
                 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(
     private void RenderMaskPreviews(
@@ -696,19 +708,23 @@ internal class MemberPreviewUpdater
 
 
             var member = internals.Tracker.Document.FindMemberOrThrow(guid);
             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));
             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 scalingX = (float)nodeVm.ResultPreview.Size.X / node.CachedResult.Size.X;
             float scalingY = (float)nodeVm.ResultPreview.Size.Y / node.CachedResult.Size.Y;
             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));
             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 Stretch Stretch { get; }
     public VecD TargetSize { get; }
     public VecD TargetSize { get; }
-    public Texture Texture { get; }
+    public Texture? Texture { get; }
     public Paint? Paint { 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)
         base(dirtyBounds)
     {
     {
         Stretch = stretch;
         Stretch = stretch;
@@ -121,6 +121,11 @@ internal class DrawTextureOperation : SkiaDrawOperation
 
 
     public override void Render(ISkiaSharpApiLease lease)
     public override void Render(ISkiaSharpApiLease lease)
     {
     {
+        if (Texture == null || Texture.IsDisposed)
+        {
+            return;
+        }
+        
         SKCanvas canvas = lease.SkCanvas;
         SKCanvas canvas = lease.SkCanvas;
 
 
         using var ctx = DrawingBackendApi.Current.RenderOnDifferentGrContext(lease.GrContext);
         using var ctx = DrawingBackendApi.Current.RenderOnDifferentGrContext(lease.GrContext);