Browse Source

Better render context switching

flabbet 1 year ago
parent
commit
fb789d4b51

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

@@ -1,4 +1,5 @@
-using PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+using System;
+using PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
 using PixiEditor.DrawingApi.Core.Bridge.Operations;
 
 namespace PixiEditor.DrawingApi.Core.Bridge

+ 8 - 8
src/PixiEditor.DrawingApi.Core/Texture.cs

@@ -11,12 +11,12 @@ namespace PixiEditor.DrawingApi.Core;
 public class Texture : IDisposable
 {
     public VecI Size { get; }
-    public DrawingSurface GpuSurface { get; }
+    public DrawingSurface Surface { get; }
 
     public Texture(VecI size)
     {
         Size = size;
-        GpuSurface =
+        Surface =
             DrawingSurface.Create(
                 new ImageInfo(Size.X, Size.Y, ColorType.RgbaF16, AlphaType.Premul, ColorSpace.CreateSrgb())
                 {
@@ -26,7 +26,7 @@ public class Texture : IDisposable
 
     public void Dispose()
     {
-        GpuSurface.Dispose();
+        Surface.Dispose();
     }
 
     public static Texture Load(string path)
@@ -38,7 +38,7 @@ public class Texture : IDisposable
             throw new ArgumentException($"The image with path {path} couldn't be loaded");
 
         Texture texture = new Texture(image.Size);
-        texture.GpuSurface.Canvas.DrawImage(image, 0, 0);
+        texture.Surface.Canvas.DrawImage(image, 0, 0);
         
         return texture;
     }
@@ -47,7 +47,7 @@ public class Texture : IDisposable
     {
         using Image image = Image.FromEncodedData(data);
         Texture texture = new Texture(image.Size);
-        texture.GpuSurface.Canvas.DrawImage(image, 0, 0);
+        texture.Surface.Canvas.DrawImage(image, 0, 0);
         
         return texture;
     }
@@ -59,14 +59,14 @@ public class Texture : IDisposable
             return null;
 
         var surface = new Texture(new VecI(image.Width, image.Height));
-        surface.GpuSurface.Canvas.DrawImage(image, 0, 0);
+        surface.Surface.Canvas.DrawImage(image, 0, 0);
 
         return surface;
     }
 
     public Texture CreateResized(VecI newSize, ResizeMethod method)
     {
-        using Image image = GpuSurface.Snapshot();
+        using Image image = Surface.Snapshot();
         Texture newTexture = new(newSize);
         using Paint paint = new();
 
@@ -80,7 +80,7 @@ public class Texture : IDisposable
 
         paint.FilterQuality = filterQuality;
 
-        newTexture.GpuSurface.Canvas.DrawImage(image, new RectD(0, 0, newSize.X, newSize.Y), paint);
+        newTexture.Surface.Canvas.DrawImage(image, new RectD(0, 0, newSize.X, newSize.Y), paint);
         
         return newTexture;
     }

+ 26 - 0
src/PixiEditor.DrawingApi.Skia/Extensions/DrawingBackendExtensions.cs

@@ -0,0 +1,26 @@
+using System;
+using PixiEditor.DrawingApi.Core.Bridge;
+using SkiaSharp;
+
+namespace PixiEditor.DrawingApi.Skia.Extensions;
+
+public static class DrawingBackendExtensions
+{
+    private static RenderGraphicsContext? _renderGraphicsContext;
+    public static IDisposable RenderOnDifferentGrContext(this IDrawingBackend drawingBackend, GRContext targetContext)
+    {
+        if (drawingBackend is not SkiaDrawingBackend skiaDrawingBackend)
+        {
+            throw new InvalidOperationException("This extension method can only be used with SkiaDrawingBackend.");
+        }
+
+        if (_renderGraphicsContext == null)
+        {
+            _renderGraphicsContext = new RenderGraphicsContext(skiaDrawingBackend.GraphicsContext, skiaDrawingBackend.SurfaceImplementation);
+        }
+        
+        _renderGraphicsContext.Target = targetContext;
+        
+        return _renderGraphicsContext;
+    }
+}

+ 1 - 1
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaSurfaceImplementation.cs

@@ -15,7 +15,7 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         private readonly SkiaCanvasImplementation _canvasImplementation;
         private readonly SkiaPaintImplementation _paintImplementation;
 
-        public GRContext GrContext { get; set; }
+        internal GRContext GrContext { get; set; }
 
         public SkiaSurfaceImplementation(GRContext context, SkiaPixmapImplementation pixmapImplementation,
             SkiaCanvasImplementation canvasImplementation, SkiaPaintImplementation paintImplementation)

+ 39 - 0
src/PixiEditor.DrawingApi.Skia/RenderGraphicsContext.cs

@@ -0,0 +1,39 @@
+using System;
+using PixiEditor.DrawingApi.Skia.Implementations;
+using SkiaSharp;
+
+namespace PixiEditor.DrawingApi.Skia;
+
+public class RenderGraphicsContext : IDisposable
+{
+    private GRContext? _target;
+    public GRContext Original { get; }
+
+    public GRContext Target
+    {
+        get => _target;
+        set
+        {
+            if (_target != null)
+            {
+                throw new InvalidOperationException("Target is already set.");
+            }
+            
+            _target = value;
+            SurfaceImplementation.GrContext = value;
+        }
+    }
+    public SkiaSurfaceImplementation SurfaceImplementation { get; }
+    
+    public RenderGraphicsContext(GRContext context, SkiaSurfaceImplementation surfaceImplementation)
+    {
+        Original = context;
+        SurfaceImplementation = surfaceImplementation;
+    }
+    
+    public void Dispose()
+    {
+        SurfaceImplementation.GrContext = Original;
+        _target = null;
+    }
+}

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

@@ -33,14 +33,14 @@ namespace PixiEditor.DrawingApi.Skia
         public IVectorPathImplementation PathImplementation { get; }
         public IMatrix3X3Implementation MatrixImplementation { get; }
         public IPixmapImplementation PixmapImplementation { get; }
-        public ISurfaceImplementation SurfaceImplementation => _surfaceImplementation;
+        ISurfaceImplementation IDrawingBackend.SurfaceImplementation => SurfaceImplementation;
+        public SkiaSurfaceImplementation SurfaceImplementation { get; }
         public IColorSpaceImplementation ColorSpaceImplementation { get; }
         public IBitmapImplementation BitmapImplementation { get; }
         public IColorFilterImplementation ColorFilterImplementation { get; }
         public IImageFilterImplementation ImageFilterImplementation { get; }
         public IShaderImplementation ShaderImplementation { get; set; }
 
-        private SkiaSurfaceImplementation _surfaceImplementation;
         private GRContext _grContext;
 
         public SkiaDrawingBackend()
@@ -80,17 +80,17 @@ namespace PixiEditor.DrawingApi.Skia
             
             SkiaCanvasImplementation canvasImpl = new SkiaCanvasImplementation(paintImpl, imgImpl, bitmapImpl, pathImpl);
             
-            _surfaceImplementation = new SkiaSurfaceImplementation(GraphicsContext, pixmapImpl, canvasImpl, paintImpl);
+            SurfaceImplementation = new SkiaSurfaceImplementation(GraphicsContext, pixmapImpl, canvasImpl, paintImpl);
 
-            canvasImpl.SetSurfaceImplementation(_surfaceImplementation);
-            imgImpl.SetSurfaceImplementation(_surfaceImplementation);
+            canvasImpl.SetSurfaceImplementation(SurfaceImplementation);
+            imgImpl.SetSurfaceImplementation(SurfaceImplementation);
 
             CanvasImplementation = canvasImpl;
         }
         
         public void Setup()
         {
-            _surfaceImplementation.GrContext = GraphicsContext;
+            SurfaceImplementation.GrContext = GraphicsContext;
         }
     }
 }

+ 1 - 1
src/PixiEditor/Views/Layers/ReferenceLayer.axaml

@@ -80,7 +80,7 @@
                             BorderBrush="Black"
                             Background="{DynamicResource ThemeBackgroundBrush}"
                             Margin="5, 0, 10, 0">
-                            <visuals:SurfaceControl Surface="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap,ElementName=uc}"
+                            <visuals:TextureControl Texture="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap,ElementName=uc}"
                                    Stretch="Uniform" Width="26" Height="26"
                                    RenderOptions.BitmapInterpolationMode="HighQuality" IsHitTestVisible="False" />
                         </Border>

+ 1 - 1
src/PixiEditor/Views/Overlays/ReferenceLayerOverlay.cs

@@ -94,7 +94,7 @@ internal class ReferenceLayerOverlay : Overlay
             double opacity = Opacity;
             var referenceBitmap = ReferenceLayer.ReferenceBitmap;
 
-            referenceBitmap.GpuSurface.Flush();
+            referenceBitmap.Surface.Flush();
             overlayPaint.Color = new Color(255, 255, 255, (byte)(opacity * 255)); 
             
             DrawTextureOperation drawOperation =

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

@@ -7,6 +7,7 @@ using Avalonia.Threading;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
+using PixiEditor.DrawingApi.Skia.Extensions;
 using PixiEditor.DrawingApi.Skia.Implementations;
 using PixiEditor.Numerics;
 
@@ -85,8 +86,13 @@ public class TextureControl : Control
 
     public override void Render(DrawingContext context)
     {
+        if (Texture == null)
+        {
+            return;
+        }
+        
         Texture texture = Texture;
-        texture.GpuSurface.Flush();
+        texture.Surface.Flush();
         ICustomDrawOperation drawOperation = new DrawTextureOperation(
             new Rect(0, 0, Bounds.Width, Bounds.Height),
             Stretch,
@@ -117,16 +123,12 @@ internal class DrawTextureOperation : SkiaDrawOperation
     {
         SKCanvas canvas = lease.SkCanvas;
 
-        GRContext original = (DrawingBackendApi.Current.SurfaceImplementation as SkiaSurfaceImplementation).GrContext;
-        
-        (DrawingBackendApi.Current.SurfaceImplementation as SkiaSurfaceImplementation).GrContext = lease.GrContext;
+        using var ctx = DrawingBackendApi.Current.RenderOnDifferentGrContext(lease.GrContext);
 
         canvas.Save();
         ScaleCanvas(canvas);
-        canvas.DrawSurface(Texture.GpuSurface.Native as SKSurface, 0, 0, Paint?.Native as SKPaint ?? null);
+        canvas.DrawSurface(Texture.Surface.Native as SKSurface, 0, 0, Paint?.Native as SKPaint ?? null);
         canvas.Restore();
-        
-        (DrawingBackendApi.Current.SurfaceImplementation as SkiaSurfaceImplementation).GrContext = original;
     }
 
     private void ScaleCanvas(SKCanvas canvas)