瀏覽代碼

GPU nodes are working!

flabbet 1 年之前
父節點
當前提交
99d41e59c6
共有 45 個文件被更改,包括 347 次插入254 次删除
  1. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/IBackgroundInput.cs
  2. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/IReadOnlyFolderNode.cs
  3. 2 2
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/IReadOnlyNode.cs
  4. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/IReadOnlyNodeGraph.cs
  5. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/NodeGraph.cs
  6. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Animable/TimeNode.cs
  7. 12 12
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineChannelsNode.cs
  8. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineColorNode.cs
  9. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineVecD.cs
  10. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineVecI.cs
  11. 14 14
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateChannelsNode.cs
  12. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateColorNode.cs
  13. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateVecDNode.cs
  14. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateVecINode.cs
  15. 8 8
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/DebugBlendModeNode.cs
  16. 5 5
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/EllipseNode.cs
  17. 4 4
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/EmptyImageNode.cs
  18. 6 6
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/ApplyFilterNode.cs
  19. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/FilterNode.cs
  20. 4 4
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FolderNode.cs
  21. 7 7
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs
  22. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageSpaceNode.cs
  23. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LerpColorNode.cs
  24. 1 1
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/MathNode.cs
  25. 9 9
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/MergeNode.cs
  26. 6 6
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageLeftNode.cs
  27. 6 6
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageRightNode.cs
  28. 7 7
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Node.cs
  29. 4 4
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/NoiseNode.cs
  30. 4 4
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/OutputNode.cs
  31. 4 4
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/SampleImageNode.cs
  32. 18 17
      src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/StructureNode.cs
  33. 3 3
      src/PixiEditor.ChangeableDocument/Changes/NodeGraph/NodeOperations.cs
  34. 4 4
      src/PixiEditor.ChangeableDocument/Changes/Structure/CreateStructureMember_Change.cs
  35. 3 3
      src/PixiEditor.ChangeableDocument/Changes/Structure/DuplicateLayer_Change.cs
  36. 1 1
      src/PixiEditor.ChangeableDocument/Changes/Structure/MoveStructureMember_Change.cs
  37. 5 5
      src/PixiEditor.ChangeableDocument/Rendering/DocumentRenderer.cs
  38. 90 14
      src/PixiEditor.DrawingApi.Core/Texture.cs
  39. 47 31
      src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs
  40. 15 15
      src/PixiEditor/Models/Rendering/CanvasUpdater.cs
  41. 37 37
      src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs
  42. 1 1
      src/PixiEditor/Views/Overlays/ReferenceLayerOverlay.cs
  43. 3 3
      src/PixiEditor/Views/Rendering/Scene.cs
  44. 2 2
      src/PixiEditor/Views/Visuals/TextureControl.cs
  45. 1 1
      src/PixiEditor/Views/Visuals/TextureImage.cs

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

@@ -5,5 +5,5 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 
 public interface IBackgroundInput
 {
-    InputProperty<Surface?> Background { get; }
+    InputProperty<Texture?> Background { get; }
 }

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

@@ -5,5 +5,5 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 
 public interface IReadOnlyFolderNode : IReadOnlyStructureNode
 {
-    InputProperty<Surface?> Content { get; }
+    InputProperty<Texture?> Content { get; }
 }

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/IReadOnlyNode.cs

@@ -13,10 +13,10 @@ public interface IReadOnlyNode
     public IReadOnlyList<IOutputProperty> OutputProperties { get; }
     public IReadOnlyList<IReadOnlyKeyFrameData> KeyFrames { get; }
     public VecD Position { get; }
-    public Surface? CachedResult { get; }
+    public Texture? CachedResult { get; }
     string DisplayName { get; }
 
-    public Surface? Execute(RenderingContext context);
+    public Texture? Execute(RenderingContext context);
     
     /// <summary>
     ///     Checks if the inputs are legal. If they are not, the node should not be executed.

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

@@ -10,5 +10,5 @@ public interface IReadOnlyNodeGraph
     public void AddNode(IReadOnlyNode node);
     public void RemoveNode(IReadOnlyNode node);
     public bool TryTraverse(Action<IReadOnlyNode> action);
-    public Surface? Execute(RenderingContext context);
+    public Texture? Execute(RenderingContext context);
 }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/NodeGraph.cs

@@ -118,7 +118,7 @@ public class NodeGraph : IReadOnlyNodeGraph, IDisposable
         return true;
     }
 
-    public Surface? Execute(RenderingContext context)
+    public Texture? Execute(RenderingContext context)
     {
         if (OutputNode == null) return null;
 

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Animable/TimeNode.cs

@@ -19,7 +19,7 @@ public class TimeNode : Node
         NormalizedTime = CreateOutput("NormalizedTime", "NORMALIZED_TIME", 0.0);
     }
     
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         ActiveFrame.Value = context.FrameTime.Frame;
         NormalizedTime.Value = context.FrameTime.NormalizedTime;

+ 12 - 12
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineChannelsNode.cs

@@ -16,38 +16,38 @@ public class CombineChannelsNode : Node
     private readonly ColorFilter _greenFilter = ColorFilter.CreateColorMatrix(ColorMatrix.UseGreen + ColorMatrix.OpaqueAlphaOffset);
     private readonly ColorFilter _blueFilter = ColorFilter.CreateColorMatrix(ColorMatrix.UseBlue + ColorMatrix.OpaqueAlphaOffset);
 
-    public InputProperty<Surface> Red { get; }
+    public InputProperty<Texture> Red { get; }
     
-    public InputProperty<Surface> Green { get; }
+    public InputProperty<Texture> Green { get; }
     
-    public InputProperty<Surface> Blue { get; }
+    public InputProperty<Texture> Blue { get; }
     
-    public InputProperty<Surface> Alpha { get; }
+    public InputProperty<Texture> Alpha { get; }
 
-    public OutputProperty<Surface> Image { get; }
+    public OutputProperty<Texture> Image { get; }
     
     // TODO: Either use a shader to combine each, or find a way to automatically "detect" if alpha channel is grayscale or not, oooor find an even better solution
     public InputProperty<bool> Grayscale { get; }
 
     public CombineChannelsNode()
     {
-        Red = CreateInput<Surface>(nameof(Red), "RED", null);
-        Green = CreateInput<Surface>(nameof(Green), "GREEN", null);
-        Blue = CreateInput<Surface>(nameof(Blue), "BLUE", null);
-        Alpha = CreateInput<Surface>(nameof(Alpha), "ALPHA", null);
+        Red = CreateInput<Texture>(nameof(Red), "RED", null);
+        Green = CreateInput<Texture>(nameof(Green), "GREEN", null);
+        Blue = CreateInput<Texture>(nameof(Blue), "BLUE", null);
+        Alpha = CreateInput<Texture>(nameof(Alpha), "ALPHA", null);
         
-        Image = CreateOutput<Surface>(nameof(Image), "IMAGE", null);
+        Image = CreateOutput<Texture>(nameof(Image), "IMAGE", null);
         Grayscale = CreateInput(nameof(Grayscale), "GRAYSCALE", false);
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         var size = GetSize();
 
         if (size == VecI.Zero)
             return null;
         
-        var workingSurface = new Surface(size);
+        var workingSurface = new Texture(size);
 
         if (Red.Value is { } red)
         {

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineColorNode.cs

@@ -41,7 +41,7 @@ public class CombineColorNode : Node
     }
 
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineVecD.cs

@@ -34,7 +34,7 @@ public class CombineVecD : Node
         return new VecD(r, g);
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineVecI.cs

@@ -33,7 +33,7 @@ public class CombineVecI : Node
     }
 
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 14 - 14
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateChannelsNode.cs

@@ -20,33 +20,33 @@ public class SeparateChannelsNode : Node
     private readonly ColorFilter _blueGrayscaleFilter = ColorFilter.CreateColorMatrix(ColorMatrix.UseBlue + ColorMatrix.MapBlueToRedGreen + ColorMatrix.OpaqueAlphaOffset);
     private readonly ColorFilter _alphaGrayscaleFilter = ColorFilter.CreateColorMatrix(ColorMatrix.MapAlphaToRedGreenBlue + ColorMatrix.OpaqueAlphaOffset);
 
-    public OutputProperty<Surface?> Red { get; }
+    public OutputProperty<Texture?> Red { get; }
     
-    public OutputProperty<Surface?> Green { get; }
+    public OutputProperty<Texture?> Green { get; }
     
-    public OutputProperty<Surface?> Blue { get; }
+    public OutputProperty<Texture?> Blue { get; }
 
-    public OutputProperty<Surface?> Alpha { get; }
+    public OutputProperty<Texture?> Alpha { get; }
     
-    public InputProperty<Surface?> Image { get; }
+    public InputProperty<Texture?> Image { get; }
     
     public InputProperty<bool> Grayscale { get; }
 
     public SeparateChannelsNode()
     {
-        Red = CreateOutput<Surface>(nameof(Red), "RED", null);
-        Green = CreateOutput<Surface>(nameof(Green), "GREEN", null);
-        Blue = CreateOutput<Surface>(nameof(Blue), "BLUE", null);
-        Alpha = CreateOutput<Surface>(nameof(Alpha), "ALPHA", null);
+        Red = CreateOutput<Texture>(nameof(Red), "RED", null);
+        Green = CreateOutput<Texture>(nameof(Green), "GREEN", null);
+        Blue = CreateOutput<Texture>(nameof(Blue), "BLUE", null);
+        Alpha = CreateOutput<Texture>(nameof(Alpha), "ALPHA", null);
         
-        Image = CreateInput<Surface>(nameof(Image), "IMAGE", null);
+        Image = CreateInput<Texture>(nameof(Image), "IMAGE", null);
         Grayscale = CreateInput(nameof(Grayscale), "GRAYSCALE", false);
     }
 
 
     public override string DisplayName { get; set; } = "SEPARATE_CHANNELS_NODE";
     
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         var image = Image.Value;
 
@@ -65,7 +65,7 @@ public class SeparateChannelsNode : Node
         Blue.Value = GetImage(image, blue);
         Alpha.Value = GetImage(image, alpha);
 
-        var previewSurface = new Surface(image.Size * 2);
+        var previewSurface = new Texture(image.Size * 2);
 
         var size = image.Size;
         
@@ -82,9 +82,9 @@ public class SeparateChannelsNode : Node
         return previewSurface;
     }
 
-    private Surface GetImage(Surface image, ColorFilter filter)
+    private Texture GetImage(Texture image, ColorFilter filter)
     {
-        var imageSurface = new Surface(image.Size);
+        var imageSurface = new Texture(image.Size);
 
         _paint.ColorFilter = filter;
         imageSurface.DrawingSurface.Canvas.DrawSurface(image.DrawingSurface, 0, 0, _paint);

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateColorNode.cs

@@ -28,7 +28,7 @@ public class SeparateColorNode : Node
         A = CreateFuncOutput(nameof(A), "A", ctx => Color.Value(ctx).A / 255d);
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateVecDNode.cs

@@ -23,7 +23,7 @@ public class SeparateVecDNode : Node
     }
 
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateVecINode.cs

@@ -22,7 +22,7 @@ public class SeparateVecINode : Node
         Vector = CreateFuncInput("Vector", "VECTOR", new VecI(0, 0));
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 8 - 8
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/DebugBlendModeNode.cs

@@ -12,31 +12,31 @@ public class DebugBlendModeNode : Node
 {
     private Paint _paint = new();
     
-    public InputProperty<Surface?> Dst { get; }
+    public InputProperty<Texture?> Dst { get; }
 
-    public InputProperty<Surface?> Src { get; }
+    public InputProperty<Texture?> Src { get; }
 
     public InputProperty<DrawingApiBlendMode> BlendMode { get; }
 
-    public OutputProperty<Surface> Result { get; }
+    public OutputProperty<Texture> Result { get; }
 
     public override string DisplayName { get; set; } = "Debug Blend Mode";
     public DebugBlendModeNode()
     {
-        Dst = CreateInput<Surface?>(nameof(Dst), "Dst", null);
-        Src = CreateInput<Surface?>(nameof(Src), "Src", null);
+        Dst = CreateInput<Texture?>(nameof(Dst), "Dst", null);
+        Src = CreateInput<Texture?>(nameof(Src), "Src", null);
         BlendMode = CreateInput(nameof(BlendMode), "Blend Mode", DrawingApiBlendMode.SrcOver);
 
-        Result = CreateOutput<Surface>(nameof(Result), "Result", null);
+        Result = CreateOutput<Texture>(nameof(Result), "Result", null);
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         if (Dst.Value is not { } dst || Src.Value is not { } src)
             return null;
 
         var size = new VecI(Math.Max(src.Size.X, dst.Size.X), int.Max(src.Size.Y, dst.Size.Y));
-        var workingSurface = new Surface(size);
+        var workingSurface = new Texture(size);
 
         workingSurface.DrawingSurface.Canvas.DrawSurface(dst.DrawingSurface, 0, 0, context.BlendModeOpacityPaint);
 

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

@@ -14,10 +14,10 @@ public class EllipseNode : Node
     public InputProperty<Color> StrokeColor { get; }
     public InputProperty<Color> FillColor { get; }
     public InputProperty<int> StrokeWidth { get; }
-    public OutputProperty<Surface> Output { get; }
+    public OutputProperty<Texture> Output { get; }
 
     private ChunkyImage? workingImage;
-    private Surface? targetSurface;
+    private Texture? targetSurface;
 
     private VecI _lastRadius = new VecI(-1, -1);
     private Color _lastStrokeColor = new Color(0, 0, 0, 0);
@@ -31,10 +31,10 @@ public class EllipseNode : Node
         StrokeColor = CreateInput<Color>("StrokeColor", "STROKE_COLOR", new Color(0, 0, 0, 255));
         FillColor = CreateInput<Color>("FillColor", "FILL_COLOR", new Color(0, 0, 0, 255));
         StrokeWidth = CreateInput<int>("StrokeWidth", "STROKE_WIDTH", 1);
-        Output = CreateOutput<Surface?>("Output", "OUTPUT", null);
+        Output = CreateOutput<Texture?>("Output", "OUTPUT", null);
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         var radius = Radius.Value;
         VecI targetDimensions = radius * 2;
@@ -52,7 +52,7 @@ public class EllipseNode : Node
             
             workingImage = new ChunkyImage(targetDimensions);
 
-            targetSurface = new Surface(targetDimensions);
+            targetSurface = new Texture(targetDimensions);
         }
 
         if (radius != _lastRadius || StrokeColor.Value != _lastStrokeColor || FillColor.Value != _lastFillColor ||

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/EmptyImageNode.cs

@@ -12,7 +12,7 @@ public class CreateImageNode : Node
 {
     private Paint _paint = new();
     
-    public OutputProperty<Surface> Output { get; }
+    public OutputProperty<Texture> Output { get; }
 
     public InputProperty<VecI> Size { get; }
     
@@ -20,14 +20,14 @@ public class CreateImageNode : Node
 
     public CreateImageNode()
     {
-        Output = CreateOutput<Surface>(nameof(Output), "EMPTY_IMAGE", null);
+        Output = CreateOutput<Texture>(nameof(Output), "EMPTY_IMAGE", null);
         Size = CreateInput(nameof(Size), "SIZE", new VecI(32, 32));
         Fill = CreateInput(nameof(Fill), "FILL", new Color(0, 0, 0, 255));
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
-        var surface = new Surface(Size.Value);
+        var surface = new Texture(Size.Value);
 
         _paint.Color = Fill.Value;
         surface.DrawingSurface.Canvas.DrawPaint(_paint);

+ 6 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/ApplyFilterNode.cs

@@ -12,20 +12,20 @@ public class ApplyFilterNode : Node
     
     public override string DisplayName { get; set; } = "APPLY_FILTER_NODE";
     
-    public OutputProperty<Surface?> Output { get; }
+    public OutputProperty<Texture?> Output { get; }
 
-    public InputProperty<Surface?> Input { get; }
+    public InputProperty<Texture?> Input { get; }
     
     public InputProperty<Filter?> Filter { get; }
 
     public ApplyFilterNode()
     {
-        Output = CreateOutput<Surface>(nameof(Output), "IMAGE", null);
-        Input = CreateInput<Surface>(nameof(Input), "IMAGE", null);
+        Output = CreateOutput<Texture>(nameof(Output), "IMAGE", null);
+        Input = CreateInput<Texture>(nameof(Input), "IMAGE", null);
         Filter = CreateInput<Filter>(nameof(Filter), "FILTER", null);
     }
     
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         if (Input.Value is not { } input)
         {
@@ -34,7 +34,7 @@ public class ApplyFilterNode : Node
         
         _paint.SetFilters(Filter.Value);
 
-        var workingSurface = new Surface(input.Size);
+        var workingSurface = new Texture(input.Size);
         
         workingSurface.DrawingSurface.Canvas.DrawSurface(input.DrawingSurface, 0, 0, _paint);
 

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/FilterNode.cs

@@ -16,7 +16,7 @@ public abstract class FilterNode : Node
         Input = CreateInput<Filter>(nameof(Input), "PREVIOUS", null);
     }
     
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         var colorFilter = GetColorFilter();
         var imageFilter = GetImageFilter();

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FolderNode.cs

@@ -10,17 +10,17 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 [NodeInfo("Folder")]
 public class FolderNode : StructureNode, IReadOnlyFolderNode
 {
-    public InputProperty<Surface?> Content { get; }
+    public InputProperty<Texture?> Content { get; }
 
     public FolderNode()
     {
-        Content = CreateInput<Surface?>("Content", "CONTENT", null);
+        Content = CreateInput<Texture?>("Content", "CONTENT", null);
     }
 
     public override Node CreateCopy() => new FolderNode { MemberName = MemberName };
 
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         if(Background.Value == null && Content.Value == null)
         {
@@ -87,7 +87,7 @@ public class FolderNode : StructureNode, IReadOnlyFolderNode
         
         if (Background.Value != null)
         {
-            Surface tempSurface = new Surface(outputWorkingSurface.Size);
+            Texture tempSurface = new Texture(outputWorkingSurface.Size);
             DrawBackground(tempSurface, context);
             
             blendPaint.Color = blendPaint.Color.WithAlpha((byte)Math.Round(Opacity.Value * 255));

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

@@ -16,7 +16,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     public const string ImageFramesKey = "Frames";
     public const string ImageLayerKey = "LayerImage";
 
-    public OutputProperty<Surface> RawOutput { get; }
+    public OutputProperty<Texture> RawOutput { get; }
 
     public InputProperty<bool> LockTransparency { get; }
 
@@ -38,7 +38,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
     public ImageLayerNode(VecI size)
     {
-        RawOutput = CreateOutput<Surface>(nameof(RawOutput), "RAW_LAYER_OUTPUT", null);
+        RawOutput = CreateOutput<Texture>(nameof(RawOutput), "RAW_LAYER_OUTPUT", null);
 
         LockTransparency = CreateInput<bool>("LockTransparency", "LOCK_TRANSPARENCY", false);
 
@@ -55,7 +55,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         return GetLayerImageAtFrame(frameTime.Frame).FindTightCommittedBounds();
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         if (!IsVisible.Value || Opacity.Value <= 0 || IsEmptyMask())
         {
@@ -75,7 +75,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         return Output.Value;
     }
 
-    private Surface RenderImage(ChunkyImage frameImage, RenderingContext context)
+    private Texture RenderImage(ChunkyImage frameImage, RenderingContext context)
     {
         var outputWorkingSurface = TryInitWorkingSurface(frameImage.LatestSize, context, 0);
         var filterlessWorkingSurface = TryInitWorkingSurface(frameImage.LatestSize, context, 1);
@@ -123,7 +123,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
         if (Background.Value != null)
         {
-            Surface tempSurface = new Surface(outputWorkingSurface.Size);
+            Texture tempSurface = new Texture(outputWorkingSurface.Size);
             DrawBackground(tempSurface, context);
             blendPaint.BlendMode = RenderingContext.GetDrawingBlendMode(BlendMode.Value);
             tempSurface.DrawingSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0, blendPaint);
@@ -137,7 +137,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         return outputWorkingSurface;
     }
 
-    private void DrawLayer(ChunkyImage frameImage, RenderingContext context, Surface workingSurface, bool shouldClear,
+    private void DrawLayer(ChunkyImage frameImage, RenderingContext context, Texture workingSurface, bool shouldClear,
         bool useFilters = true)
     {
         blendPaint.Color = blendPaint.Color.WithAlpha((byte)Math.Round(Opacity.Value * 255));
@@ -164,7 +164,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
     // Draw with filters is a bit tricky since some filters sample data from chunks surrounding the chunk being drawn,
     // this is why we need to do intermediate drawing to a temporary surface and then apply filters to that surface
-    private void DrawWithFilters(ChunkyImage frameImage, RenderingContext context, Surface workingSurface,
+    private void DrawWithFilters(ChunkyImage frameImage, RenderingContext context, Texture workingSurface,
         bool shouldClear)
     {
         VecI imageChunksSize = frameImage.LatestSize / context.ChunkResolution.PixelSize();

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageSpaceNode.cs

@@ -21,7 +21,7 @@ public class ImageSpaceNode : Node
     }
 
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LerpColorNode.cs

@@ -34,7 +34,7 @@ public class LerpColorNode : Node // TODO: ILerpable as inputs?
         return Color.Lerp(from, to, time); 
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/MathNode.cs

@@ -58,7 +58,7 @@ public class MathNode : Node
     private (double x, double y) GetValues(FuncContext context) => (X.Value(context), Y.Value(context));
 
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return null;
     }

+ 9 - 9
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/MergeNode.cs

@@ -9,15 +9,15 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 [NodeInfo("Merge")]
 public class MergeNode : Node, IBackgroundInput
 {
-    public InputProperty<Surface?> Top { get; }
-    public InputProperty<Surface?> Bottom { get; }
-    public OutputProperty<Surface?> Output { get; }
+    public InputProperty<Texture?> Top { get; }
+    public InputProperty<Texture?> Bottom { get; }
+    public OutputProperty<Texture?> Output { get; }
     
     public MergeNode() 
     {
-        Top = CreateInput<Surface?>("Top", "TOP", null);
-        Bottom = CreateInput<Surface?>("Bottom", "BOTTOM", null);
-        Output = CreateOutput<Surface?>("Output", "OUTPUT", null);
+        Top = CreateInput<Texture?>("Top", "TOP", null);
+        Bottom = CreateInput<Texture?>("Bottom", "BOTTOM", null);
+        Output = CreateOutput<Texture?>("Output", "OUTPUT", null);
     }
 
     public override string DisplayName { get; set; } = "MERGE_NODE";
@@ -28,7 +28,7 @@ public class MergeNode : Node, IBackgroundInput
     }
 
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         if(Top.Value == null && Bottom.Value == null)
         {
@@ -39,7 +39,7 @@ public class MergeNode : Node, IBackgroundInput
         int width = Top.Value?.Size.X ?? Bottom.Value.Size.X;
         int height = Top.Value?.Size.Y ?? Bottom.Value.Size.Y;
         
-        Surface workingSurface = new Surface(new VecI(width, height));
+        Texture workingSurface = new Texture(new VecI(width, height));
         
         if(Bottom.Value != null)
         {
@@ -56,5 +56,5 @@ public class MergeNode : Node, IBackgroundInput
         return Output.Value;
     }
 
-    InputProperty<Surface> IBackgroundInput.Background => Bottom;
+    InputProperty<Texture> IBackgroundInput.Background => Bottom;
 }

+ 6 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageLeftNode.cs

@@ -14,7 +14,7 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 [PairNode(typeof(ModifyImageRightNode), "ModifyImageZone", true)]
 public class ModifyImageLeftNode : Node
 {
-    public InputProperty<Surface?> Image { get; }
+    public InputProperty<Texture?> Image { get; }
     
     public FuncOutputProperty<VecD> Coordinate { get; }
     
@@ -26,9 +26,9 @@ public class ModifyImageLeftNode : Node
 
     public ModifyImageLeftNode()
     {
-        Image = CreateInput<Surface>(nameof(Surface), "IMAGE", null);
-        Coordinate = CreateFuncOutput(nameof(Coordinate), "UV", ctx => ctx.Position);
-        Color = CreateFuncOutput(nameof(Color), "COLOR", GetColor);
+        Image = CreateInput<Texture>("Surface", "IMAGE", null);
+        Coordinate = CreateFuncOutput("Coordinate", "UV", ctx => ctx.Position);
+        Color = CreateFuncOutput("Color", "COLOR", GetColor);
     }
 
     private Color GetColor(FuncContext context)
@@ -48,7 +48,7 @@ public class ModifyImageLeftNode : Node
 
     internal void PreparePixmap(RenderingContext forContext)
     {
-        pixmapCache[forContext] = Image.Value?.DrawingSurface.Snapshot().PeekPixels();
+        pixmapCache[forContext] = Image.Value?.PeekReadOnlyPixels();
     }
     
     internal void DisposePixmap(RenderingContext forContext)
@@ -59,7 +59,7 @@ public class ModifyImageLeftNode : Node
         }
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return Image.Value;
     }

+ 6 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageRightNode.cs

@@ -22,20 +22,20 @@ public class ModifyImageRightNode : Node, IPairNodeEnd
     public FuncInputProperty<VecD> Coordinate { get; }
     public FuncInputProperty<Color> Color { get; }
 
-    public OutputProperty<Surface> Output { get; }
+    public OutputProperty<Texture> Output { get; }
 
     public override string DisplayName { get; set; } = "MODIFY_IMAGE_RIGHT_NODE";
 
-    private Surface surface;
+    private Texture surface;
 
     public ModifyImageRightNode()
     {
         Coordinate = CreateFuncInput(nameof(Coordinate), "UV", new VecD());
         Color = CreateFuncInput(nameof(Color), "COLOR", new Color());
-        Output = CreateOutput<Surface>(nameof(Output), "OUTPUT", null);
+        Output = CreateOutput<Texture>(nameof(Output), "OUTPUT", null);
     }
 
-    protected override Surface? OnExecute(RenderingContext renderingContext)
+    protected override Texture? OnExecute(RenderingContext renderingContext)
     {
         if (StartNode == null)
         {
@@ -55,11 +55,11 @@ public class ModifyImageRightNode : Node, IPairNodeEnd
         var width = size.X;
         var height = size.Y;
         
-        surface = new Surface(size);
+        surface = new Texture(size);
 
         startNode.PreparePixmap(renderingContext);
         
-        using Pixmap targetPixmap = surface.PeekPixels();
+        using Pixmap targetPixmap = surface.PeekReadOnlyPixels();
 
         ModifyImageInParallel(renderingContext, targetPixmap, width, height);
         

+ 7 - 7
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Node.cs

@@ -23,7 +23,7 @@ public abstract class Node : IReadOnlyNode, IDisposable
     public IReadOnlyList<OutputProperty> OutputProperties => outputs;
     public IReadOnlyList<KeyFrameData> KeyFrames => keyFrames;
 
-    public Surface? CachedResult
+    public Texture? CachedResult
     {
         get
         {
@@ -56,18 +56,18 @@ public abstract class Node : IReadOnlyNode, IDisposable
     private ChunkResolution? _lastResolution;
     private VecI? _lastChunkPos;
     private bool _keyFramesDirty;
-    private Surface? _lastCachedResult;
+    private Texture? _lastCachedResult;
     private bool _isDisposed;
 
-    public Surface? Execute(RenderingContext context)
+    public Texture? Execute(RenderingContext context)
     {
         var result = ExecuteInternal(context);
 
-        var copy = new Surface(result);
+        var copy = new Texture(result);
         return copy;
     }
 
-    internal Surface ExecuteInternal(RenderingContext context)
+    internal Texture ExecuteInternal(RenderingContext context)
     {
         if(_isDisposed) throw new ObjectDisposedException("Node was disposed before execution.");
         
@@ -76,14 +76,14 @@ public abstract class Node : IReadOnlyNode, IDisposable
         CachedResult = OnExecute(context);
         if (CachedResult is { IsDisposed: true })
         {
-            throw new ObjectDisposedException("Surface was disposed after execution.");
+            throw new ObjectDisposedException("Texture was disposed after execution.");
         }
 
         UpdateCache(context);
         return CachedResult;
     }
 
-    protected abstract Surface? OnExecute(RenderingContext context);
+    protected abstract Texture? OnExecute(RenderingContext context);
 
     protected virtual bool CacheChanged(RenderingContext context)
     {

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/NoiseNode.cs

@@ -20,7 +20,7 @@ public class NoiseNode : Node
     private static readonly ColorFilter grayscaleFilter = ColorFilter.CreateColorMatrix(
         ColorMatrix.MapAlphaToRedGreenBlue + ColorMatrix.OpaqueAlphaOffset);
     
-    public OutputProperty<Surface> Noise { get; }
+    public OutputProperty<Texture> Noise { get; }
     
     public InputProperty<NoiseType> NoiseType { get; }
     public InputProperty<VecI> Size { get; }
@@ -33,7 +33,7 @@ public class NoiseNode : Node
 
     public NoiseNode()
     {
-        Noise = CreateOutput<Surface>(nameof(Noise), "NOISE", null);
+        Noise = CreateOutput<Texture>(nameof(Noise), "NOISE", null);
         NoiseType = CreateInput(nameof(NoiseType), "NOISE_TYPE", Nodes.NoiseType.TurbulencePerlin);
         Size = CreateInput(nameof(Size), "SIZE", new VecI(64, 64));
         Scale = CreateInput(nameof(Scale), "SCALE", 10d);
@@ -41,7 +41,7 @@ public class NoiseNode : Node
         Seed = CreateInput(nameof(Seed), "SEED", 0d);
     }
 
-    protected override Surface OnExecute(RenderingContext context)
+    protected override Texture OnExecute(RenderingContext context)
     {
         if (Math.Abs(previousScale - Scale.Value) > 0.000001
             || previousSeed != Seed.Value
@@ -81,7 +81,7 @@ public class NoiseNode : Node
             return null;
         }
         
-        var workingSurface = new Surface(size);
+        var workingSurface = new Texture(size);
        
         workingSurface.DrawingSurface.Canvas.DrawPaint(paint);
 

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/OutputNode.cs

@@ -11,10 +11,10 @@ public class OutputNode : Node, IBackgroundInput
     public const string InputPropertyName = "Background";
 
     public override string DisplayName { get; set; } = "OUTPUT_NODE";
-    public InputProperty<Surface?> Input { get; } 
+    public InputProperty<Texture?> Input { get; } 
     public OutputNode()
     {
-        Input = CreateInput<Surface>(InputPropertyName, "INPUT", null);
+        Input = CreateInput<Texture>(InputPropertyName, "INPUT", null);
     }
 
     public override Node CreateCopy()
@@ -22,10 +22,10 @@ public class OutputNode : Node, IBackgroundInput
         return new OutputNode();
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         return Input.Value;
     }
 
-    InputProperty<Surface?> IBackgroundInput.Background => Input;
+    InputProperty<Texture?> IBackgroundInput.Background => Input;
 }

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/SampleImageNode.cs

@@ -12,7 +12,7 @@ public class SampleImageNode : Node
 {
     private Pixmap? pixmap;
 
-    public InputProperty<Surface?> Image { get; }
+    public InputProperty<Texture?> Image { get; }
 
     public FuncOutputProperty<VecD> Coordinate { get; }
 
@@ -22,7 +22,7 @@ public class SampleImageNode : Node
 
     public SampleImageNode()
     {
-        Image = CreateInput<Surface>(nameof(Surface), "IMAGE", null);
+        Image = CreateInput<Texture>(nameof(Texture), "IMAGE", null);
         Coordinate = CreateFuncOutput(nameof(Coordinate), "UV", ctx => ctx.Position);
         Color = CreateFuncOutput(nameof(Color), "COLOR", GetColor);
     }
@@ -42,10 +42,10 @@ public class SampleImageNode : Node
 
     internal void PreparePixmap()
     {
-        pixmap = Image.Value?.PeekPixels();
+        pixmap = Image.Value?.PeekReadOnlyPixels();
     }
 
-    protected override Surface? OnExecute(RenderingContext context)
+    protected override Texture? OnExecute(RenderingContext context)
     {
         PreparePixmap();
         return Image.Value;

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

@@ -13,7 +13,7 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 
 public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundInput
 {
-    public InputProperty<Surface?> Background { get; }
+    public InputProperty<Texture?> Background { get; }
     public InputProperty<float> Opacity { get; }
     public InputProperty<bool> IsVisible { get; }
     public InputProperty<bool> ClipToPreviousMember { get; }
@@ -22,9 +22,9 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
     public InputProperty<bool> MaskIsVisible { get; }
     public InputProperty<Filter> Filters { get; }
 
-    public OutputProperty<Surface?> Output { get; }
+    public OutputProperty<Texture?> Output { get; }
 
-    public OutputProperty<Surface?> FilterlessOutput { get; }
+    public OutputProperty<Texture?> FilterlessOutput { get; }
 
     public string MemberName { get; set; } = "New Element"; // would be good to add localization here, it is set if node is created via node graph
     
@@ -34,13 +34,13 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         set => MemberName = value;
     }
 
-    protected Dictionary<(ChunkResolution, int), Surface> workingSurfaces = new Dictionary<(ChunkResolution, int), Surface>();
+    protected Dictionary<(ChunkResolution, int), Texture> workingSurfaces = new Dictionary<(ChunkResolution, int), Texture>();
     private Paint maskPaint = new Paint() { BlendMode = DrawingApi.Core.Surfaces.BlendMode.DstIn };
     protected Paint blendPaint = new Paint();
 
     protected StructureNode()
     {
-        Background = CreateInput<Surface?>("Background", "BACKGROUND", null);
+        Background = CreateInput<Texture?>("Background", "BACKGROUND", null);
         Opacity = CreateInput<float>("Opacity", "OPACITY", 1);
         IsVisible = CreateInput<bool>("IsVisible", "IS_VISIBLE", true);
         ClipToPreviousMember = CreateInput<bool>("ClipToMemberBelow", "CLIP_TO_MEMBER_BELOW", false);
@@ -49,28 +49,28 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         MaskIsVisible = CreateInput<bool>("MaskIsVisible", "MASK_IS_VISIBLE", true);
         Filters = CreateInput<Filter>(nameof(Filters), "FILTERS", null);
 
-        Output = CreateOutput<Surface?>("Output", "OUTPUT", null);
-        FilterlessOutput = CreateOutput<Surface?>(nameof(FilterlessOutput), "WITHOUT_FILTERS", null);
+        Output = CreateOutput<Texture?>("Output", "OUTPUT", null);
+        FilterlessOutput = CreateOutput<Texture?>(nameof(FilterlessOutput), "WITHOUT_FILTERS", null);
     }
 
-    protected abstract override Surface? OnExecute(RenderingContext context);
+    protected abstract override Texture? OnExecute(RenderingContext context);
 
-    protected Surface TryInitWorkingSurface(VecI imageSize, RenderingContext context, int id)
+    protected Texture TryInitWorkingSurface(VecI imageSize, RenderingContext context, int id)
     {
         ChunkResolution targetResolution = context.ChunkResolution;
-        bool hasSurface = workingSurfaces.TryGetValue((targetResolution, id), out Surface workingSurface);
+        bool hasSurface = workingSurfaces.TryGetValue((targetResolution, id), out Texture workingSurface);
         VecI targetSize = (VecI)(imageSize * targetResolution.Multiplier());
 
         if (!hasSurface || workingSurface.Size != targetSize || workingSurface.IsDisposed)
         {
-            workingSurfaces[(targetResolution, id)] = new Surface(targetSize);
+            workingSurfaces[(targetResolution, id)] = new Texture(targetSize);
             workingSurface = workingSurfaces[(targetResolution, id)];
         }
 
         return workingSurface;
     }
 
-    protected void ApplyMaskIfPresent(Surface surface, RenderingContext context)
+    protected void ApplyMaskIfPresent(Texture surface, RenderingContext context)
     {
         if (Mask.Value != null && MaskIsVisible.Value)
         {
@@ -83,7 +83,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         }
     }
 
-    protected void ApplyRasterClip(Surface surface, RenderingContext context)
+    protected void ApplyRasterClip(Texture surface, RenderingContext context)
     {
         if (ClipToPreviousMember.Value && Background.Value != null)
         {
@@ -92,7 +92,8 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
             VecI targetSize = new VecI(context.ChunkResolution.PixelSize());
             clippingRect = new RectI(chunkStart, targetSize);
 
-            OperationHelper.ClampAlpha(surface.DrawingSurface, Background.Value, clippingRect);
+            //TODO: Fix
+            //OperationHelper.ClampAlpha(surface.DrawingSurface, Background.Value, clippingRect);
         }
     }
 
@@ -107,13 +108,13 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         return (MaskIsVisible.Value && Mask.Value != null) || ClipToPreviousMember.Value;
     }
 
-    protected void DrawBackground(Surface workingSurface, RenderingContext context)
+    protected void DrawBackground(Texture workingSurface, RenderingContext context)
     {
         blendPaint.Color = Colors.White;
         DrawSurface(workingSurface, Background.Value, context, null); 
     }
 
-    protected void DrawSurface(Surface workingSurface, Surface source, RenderingContext context, Filter? filter)
+    protected void DrawSurface(Texture workingSurface, Texture source, RenderingContext context, Filter? filter)
     {
         // Maybe clip rect will allow to avoid snapshotting? Idk if it will be faster
         RectI sourceRect = CalculateSourceRect(source, workingSurface.Size, context);
@@ -124,7 +125,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         workingSurface.DrawingSurface.Canvas.DrawImage(snapshot, targetRect.X, targetRect.Y, blendPaint);
     }
 
-    protected RectI CalculateSourceRect(Surface image, VecI targetSize, RenderingContext context)
+    protected RectI CalculateSourceRect(Texture image, VecI targetSize, RenderingContext context)
     {
         float multiplierToFit = image.Size.X / (float)targetSize.X;
         int chunkSize = context.ChunkResolution.PixelSize();

+ 3 - 3
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/NodeOperations.cs

@@ -68,9 +68,9 @@ public static class NodeOperations
         return node;
     }
 
-    public static List<ConnectProperty_ChangeInfo> AppendMember(InputProperty<Surface?> parentInput,
-        OutputProperty<Surface> toAddOutput,
-        InputProperty<Surface> toAddInput, Guid memberId)
+    public static List<ConnectProperty_ChangeInfo> AppendMember(InputProperty<Texture?> parentInput,
+        OutputProperty<Texture> toAddOutput,
+        InputProperty<Texture> toAddInput, Guid memberId)
     {
         List<ConnectProperty_ChangeInfo> changes = new();
         IOutputProperty? previouslyConnected = null;

+ 4 - 4
src/PixiEditor.ChangeableDocument/Changes/Structure/CreateStructureMember_Change.cs

@@ -46,9 +46,9 @@ internal class CreateStructureMember_Change : Change
 
         List<IChangeInfo> changes = new() { CreateChangeInfo(member) };
         
-        InputProperty<Surface> targetInput = parentNode.InputProperties.FirstOrDefault(x => 
-            x.ValueType == typeof(Surface) && 
-            x.Connection.Node is StructureNode) as InputProperty<Surface>;
+        InputProperty<Texture> targetInput = parentNode.InputProperties.FirstOrDefault(x => 
+            x.ValueType == typeof(Texture) && 
+            x.Connection.Node is StructureNode) as InputProperty<Texture>;
         
         
         
@@ -109,7 +109,7 @@ internal class CreateStructureMember_Change : Change
         return changes;
     }
 
-    private static void AppendFolder(InputProperty<Surface> backgroundInput, FolderNode folder, List<IChangeInfo> changes)
+    private static void AppendFolder(InputProperty<Texture> backgroundInput, FolderNode folder, List<IChangeInfo> changes)
     {
         var appened = NodeOperations.AppendMember(backgroundInput, folder.Output, folder.Background, folder.Id);
         changes.AddRange(appened);

+ 3 - 3
src/PixiEditor.ChangeableDocument/Changes/Structure/DuplicateLayer_Change.cs

@@ -40,9 +40,9 @@ internal class DuplicateLayer_Change : Change
         LayerNode clone = (LayerNode)existingLayer.Clone();
         clone.Id = duplicateGuid;
 
-        InputProperty<Surface?> targetInput = parent.InputProperties.FirstOrDefault(x =>
-            x.ValueType == typeof(Surface) &&
-            x.Connection.Node is StructureNode) as InputProperty<Surface?>;
+        InputProperty<Texture?> targetInput = parent.InputProperties.FirstOrDefault(x =>
+            x.ValueType == typeof(Texture) &&
+            x.Connection.Node is StructureNode) as InputProperty<Texture?>;
 
         List<IChangeInfo> operations = new();
 

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changes/Structure/MoveStructureMember_Change.cs

@@ -51,7 +51,7 @@ internal class MoveStructureMember_Change : Change
         
         Guid oldBackgroundId = sourceNode.Background.Node.Id;
 
-        InputProperty<Surface?> inputProperty = backgroundInput.Background;
+        InputProperty<Texture?> inputProperty = backgroundInput.Background;
 
         if (targetNode is FolderNode folder && putInsideFolder)
         {

+ 5 - 5
src/PixiEditor.ChangeableDocument/Rendering/DocumentRenderer.cs

@@ -25,7 +25,7 @@ public class DocumentRenderer
         {
             RectI? transformedClippingRect = TransformClipRect(globalClippingRect, resolution, chunkPos);
 
-            Surface? evaluated = Document.NodeGraph.Execute(context);
+            Texture? evaluated = Document.NodeGraph.Execute(context);
             if (evaluated is null)
             {
                 return new EmptyChunk();
@@ -87,7 +87,7 @@ public class DocumentRenderer
         {
             RectI? transformedClippingRect = TransformClipRect(globalClippingRect, resolution, chunkPos);
 
-            Surface? evaluated = node.Execute(context);
+            Texture? evaluated = node.Execute(context);
             if (evaluated is null)
             {
                 return new EmptyChunk();
@@ -118,7 +118,7 @@ public class DocumentRenderer
         NodeGraph membersOnlyGraph = ConstructMembersOnlyGraph(layersToCombine, Document.NodeGraph);
         try
         {
-            Surface? evaluated = membersOnlyGraph.Execute(context);
+            Texture? evaluated = membersOnlyGraph.Execute(context);
             if (evaluated is null)
             {
                 return new EmptyChunk();
@@ -153,7 +153,7 @@ public class DocumentRenderer
             }
         });
 
-        IInputProperty<Surface> lastInput = outputNode.Input;
+        IInputProperty<Texture> lastInput = outputNode.Input;
 
         foreach (var layer in layersInOrder)
         {
@@ -168,7 +168,7 @@ public class DocumentRenderer
     }
 
     private static OneOf<Chunk, EmptyChunk> ChunkFromResult(ChunkResolution resolution,
-        RectI? transformedClippingRect, Surface evaluated,
+        RectI? transformedClippingRect, Texture evaluated,
         RenderingContext context)
     {
         Chunk chunk = Chunk.Create(resolution);

+ 90 - 14
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 DrawingSurface { get; private set; }
 
     public event SurfaceChangedEventHandler? Changed;
 
@@ -20,20 +20,39 @@ public class Texture : IDisposable
     private bool pixmapUpToDate;
     private Pixmap pixmap;
 
+    private Paint nearestNeighborReplacingPaint =
+        new() { BlendMode = BlendMode.Src, FilterQuality = FilterQuality.None };
+
     public Texture(VecI size)
     {
         Size = size;
-        Surface =
+        DrawingSurface =
             DrawingSurface.Create(
                 new ImageInfo(Size.X, Size.Y, ColorType.RgbaF16, AlphaType.Premul, ColorSpace.CreateSrgb())
                 {
                     GpuBacked = true
                 });
 
-        Surface.Changed += SurfaceOnChanged;
+        DrawingSurface.Changed += DrawingSurfaceOnChanged;
+    }
+
+    public Texture(Texture other) : this(other.Size)
+    {
+        DrawingSurface.Canvas.DrawSurface(other.DrawingSurface, 0, 0);
+    }
+
+    internal Texture(DrawingSurface drawingSurface)
+    {
+        DrawingSurface = drawingSurface;
+        DrawingSurface.Changed += DrawingSurfaceOnChanged;
+    }
+
+    ~Texture()
+    {
+        DrawingSurface.Changed -= DrawingSurfaceOnChanged;
     }
 
-    private void SurfaceOnChanged(RectD? changedRect)
+    private void DrawingSurfaceOnChanged(RectD? changedRect)
     {
         Changed?.Invoke(changedRect);
     }
@@ -48,7 +67,7 @@ public class Texture : IDisposable
             throw new ArgumentException($"The image with path {path} couldn't be loaded");
 
         Texture texture = new Texture(image.Size);
-        texture.Surface.Canvas.DrawImage(image, 0, 0);
+        texture.DrawingSurface.Canvas.DrawImage(image, 0, 0);
 
         return texture;
     }
@@ -57,7 +76,7 @@ public class Texture : IDisposable
     {
         using Image image = Image.FromEncodedData(data);
         Texture texture = new Texture(image.Size);
-        texture.Surface.Canvas.DrawImage(image, 0, 0);
+        texture.DrawingSurface.Canvas.DrawImage(image, 0, 0);
 
         return texture;
     }
@@ -69,14 +88,14 @@ public class Texture : IDisposable
             return null;
 
         var surface = new Texture(new VecI(image.Width, image.Height));
-        surface.Surface.Canvas.DrawImage(image, 0, 0);
+        surface.DrawingSurface.Canvas.DrawImage(image, 0, 0);
 
         return surface;
     }
 
     public Texture CreateResized(VecI newSize, ResizeMethod method)
     {
-        using Image image = Surface.Snapshot();
+        using Image image = DrawingSurface.Snapshot();
         Texture newTexture = new(newSize);
         using Paint paint = new();
 
@@ -90,20 +109,71 @@ public class Texture : IDisposable
 
         paint.FilterQuality = filterQuality;
 
-        newTexture.Surface.Canvas.DrawImage(image, new RectD(0, 0, newSize.X, newSize.Y), paint);
+        newTexture.DrawingSurface.Canvas.DrawImage(image, new RectD(0, 0, newSize.X, newSize.Y), paint);
 
         return newTexture;
     }
 
-    public Color? GetSRGBPixel(VecI vecI)
+    public Pixmap? PeekReadOnlyPixels()
+    {
+        if (pixmapUpToDate)
+        {
+            return pixmap;
+        }
+
+        pixmap = DrawingSurface.PeekPixels();
+        pixmapUpToDate = true;
+
+        return pixmap;
+    }
+
+    public void CopyTo(Texture destination)
+    {
+        destination.DrawingSurface.Canvas.DrawSurface(DrawingSurface, 0, 0);
+    }
+
+    public unsafe bool IsFullyTransparent()
+    {
+        ulong* ptr = (ulong*)PeekReadOnlyPixels().GetPixels();
+        for (int i = 0; i < Size.X * Size.Y; i++)
+        {
+            // ptr[i] actually contains 4 16-bit floats. We only care about the first one which is alpha.
+            // An empty pixel can have alpha of 0 or -0 (not sure if -0 actually ever comes up). 0 in hex is 0x0, -0 in hex is 0x8000
+            if ((ptr[i] & 0x1111_0000_0000_0000) != 0 && (ptr[i] & 0x1111_0000_0000_0000) != 0x8000_0000_0000_0000)
+                return false;
+        }
+
+        return true;
+    }
+
+    public void DrawBytes(VecI surfaceSize, byte[] pixels, ColorType color, AlphaType alphaType)
+    {
+        if (surfaceSize != Size)
+            throw new ArgumentException("Surface size must match the size of the byte array");
+
+        using Image image = Image.FromPixels(new ImageInfo(Size.X, Size.Y, color, alphaType, ColorSpace.CreateSrgb()),
+            pixels);
+        DrawingSurface.Canvas.DrawImage(image, 0, 0);
+    }
+
+    public Texture ResizeNearestNeighbor(VecI newSize)
+    {
+        using Image image = DrawingSurface.Snapshot();
+        Texture newSurface = new(newSize);
+        newSurface.DrawingSurface.Canvas.DrawImage(image, new RectD(0, 0, newSize.X, newSize.Y),
+            nearestNeighborReplacingPaint);
+        return newSurface;
+    }
+
+    public Color GetSRGBPixel(VecI vecI)
     {
         if (vecI.X < 0 || vecI.X >= Size.X || vecI.Y < 0 || vecI.Y >= Size.Y)
-            return null;
+            return Color.Empty;
 
         if (!pixmapUpToDate)
         {
             pixmapUpToDate = true;
-            pixmap = Surface.PeekPixels();
+            pixmap = DrawingSurface.PeekPixels();
         }
 
         return pixmap.GetPixelColor(vecI);
@@ -120,7 +190,13 @@ public class Texture : IDisposable
             return;
 
         IsDisposed = true;
-        Surface.Changed -= SurfaceOnChanged;
-        Surface.Dispose();
+        DrawingSurface.Changed -= DrawingSurfaceOnChanged;
+        DrawingSurface.Dispose();
+    }
+
+    public static Texture FromExisting(DrawingSurface drawingSurface)
+    {
+        Texture texture = new(drawingSurface);
+        return texture;
     }
 }

+ 47 - 31
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -5,6 +5,7 @@ using Avalonia.Threading;
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.ChangeInfos;
+using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DocumentPassthroughActions;
@@ -80,20 +81,32 @@ internal class ActionAccumulator
 
             // update viewmodels based on changes
             List<IChangeInfo> optimizedChanges = ChangeInfoListOptimizer.Optimize(changes);
-            bool undoBoundaryPassed = toExecute.Any(static action => action is ChangeBoundary_Action or Redo_Action or Undo_Action);
+            bool undoBoundaryPassed =
+                toExecute.Any(static action => action is ChangeBoundary_Action or Redo_Action or Undo_Action);
             bool viewportRefreshRequest = toExecute.Any(static action => action is RefreshViewport_PassthroughAction);
             foreach (IChangeInfo info in optimizedChanges)
             {
                 internals.Updater.ApplyChangeFromChangeInfo(info);
             }
+
             if (undoBoundaryPassed)
                 internals.Updater.AfterUndoBoundaryPassed();
 
             // update the contents of the bitmaps
-            var affectedAreas = new AffectedAreasGatherer(document.AnimationHandler.ActiveFrameTime, internals.Tracker, optimizedChanges);
+            var affectedAreas = new AffectedAreasGatherer(document.AnimationHandler.ActiveFrameTime, internals.Tracker,
+                optimizedChanges);
             List<IRenderInfo> renderResult = new();
-            renderResult.AddRange(await canvasUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed || viewportRefreshRequest));
-            renderResult.AddRange(await previewUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed));
+            if (DrawingBackendApi.Current.IsHardwareAccelerated)
+            {
+                renderResult.AddRange(canvasUpdater.UpdateGatheredChunksSync(affectedAreas, undoBoundaryPassed || viewportRefreshRequest));
+                renderResult.AddRange(previewUpdater.UpdateGatheredChunksSync(affectedAreas, undoBoundaryPassed));
+            }
+            else
+            {
+                renderResult.AddRange(await canvasUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed || viewportRefreshRequest));
+                renderResult.AddRange(await previewUpdater.UpdateGatheredChunks(affectedAreas, undoBoundaryPassed));
+            }
+
 
             if (undoBoundaryPassed)
             {
@@ -124,6 +137,7 @@ internal class ActionAccumulator
             if (action is not IChangeInfo)
                 return false;
         }
+
         return true;
     }
 
@@ -134,42 +148,44 @@ internal class ActionAccumulator
             switch (renderInfo)
             {
                 case DirtyRect_RenderInfo info:
-                    {
-                        var bitmap = document.Surfaces[info.Resolution];
-                        RectI finalRect = new RectI(VecI.Zero, new(bitmap.Size.X, bitmap.Size.Y));
+                {
+                    var bitmap = document.Surfaces[info.Resolution];
+                    RectI finalRect = new RectI(VecI.Zero, new(bitmap.Size.X, bitmap.Size.Y));
 
-                        RectI dirtyRect = new RectI(info.Pos, info.Size).Intersect(finalRect);
-                        bitmap.AddDirtyRect(dirtyRect);
-                    }
+                    RectI dirtyRect = new RectI(info.Pos, info.Size).Intersect(finalRect);
+                    bitmap.AddDirtyRect(dirtyRect);
+                }
                     break;
                 case PreviewDirty_RenderInfo info:
-                    {
-                        var bitmap = document.StructureHelper.Find(info.GuidValue)?.PreviewSurface;
-                        if (bitmap is null)
-                            continue;
-                        bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
-                    }
+                {
+                    var bitmap = document.StructureHelper.Find(info.GuidValue)?.PreviewSurface;
+                    if (bitmap is null)
+                        continue;
+                    bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
+                }
                     break;
                 case MaskPreviewDirty_RenderInfo info:
-                    {
-                        var bitmap = document.StructureHelper.Find(info.GuidValue)?.MaskPreviewSurface;
-                        if (bitmap is null)
-                            continue;
-                        bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
-                    }
+                {
+                    var bitmap = document.StructureHelper.Find(info.GuidValue)?.MaskPreviewSurface;
+                    if (bitmap is null)
+                        continue;
+                    bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
+                }
                     break;
                 case CanvasPreviewDirty_RenderInfo:
-                    {
-                        document.PreviewSurface.AddDirtyRect(new RectI(0, 0, document.PreviewSurface.Size.X, document.PreviewSurface.Size.Y));
-                    }
+                {
+                    document.PreviewSurface.AddDirtyRect(new RectI(0, 0, document.PreviewSurface.Size.X,
+                        document.PreviewSurface.Size.Y));
+                }
                     break;
                 case NodePreviewDirty_RenderInfo info:
-                    {
-                        var node = document.StructureHelper.Find(info.NodeId);
-                        if (node is null || node.PreviewSurface is null)
-                            continue;
-                        node.PreviewSurface.AddDirtyRect(new RectI(0, 0, node.PreviewSurface.Size.X, node.PreviewSurface.Size.Y));
-                    }
+                {
+                    var node = document.StructureHelper.Find(info.NodeId);
+                    if (node is null || node.PreviewSurface is null)
+                        continue;
+                    node.PreviewSurface.AddDirtyRect(new RectI(0, 0, node.PreviewSurface.Size.X,
+                        node.PreviewSurface.Size.Y));
+                }
                     break;
             }
         }

+ 15 - 15
src/PixiEditor/Models/Rendering/CanvasUpdater.cs

@@ -226,45 +226,45 @@ internal class CanvasUpdater
             .Switch(
                 (Chunk chunk) =>
                 {
-                    Dispatcher.UIThread.Post(() =>
-                    {
+                    /*Dispatcher.UIThread.Post(() =>
+                    {*/
                         if (screenSurface.IsDisposed) return;
 
                         if (globalScaledClippingRectangle is not null)
                         {
-                            screenSurface.Surface.Canvas.Save();
-                            screenSurface.Surface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
+                            screenSurface.DrawingSurface.Canvas.Save();
+                            screenSurface.DrawingSurface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
                         }
-
-                        screenSurface.Surface.Canvas.DrawSurface(
+                        
+                        screenSurface.DrawingSurface.Canvas.DrawSurface(
                             chunk.Surface.DrawingSurface,
                             chunkPos.Multiply(chunk.PixelSize), ReplacingPaint);
                         chunk.Dispose();
 
 
                         if (globalScaledClippingRectangle is not null)
-                            screenSurface.Surface.Canvas.Restore();
-                    });
+                            screenSurface.DrawingSurface.Canvas.Restore();
+                    /*});*/
                 },
                 (EmptyChunk _) =>
                 {
-                    Dispatcher.UIThread.Post(() =>
-                    {
+                    /*Dispatcher.UIThread.Post(() =>
+                    {*/
                         if (screenSurface.IsDisposed) return;
 
                         if (globalScaledClippingRectangle is not null)
                         {
-                            screenSurface.Surface.Canvas.Save();
-                            screenSurface.Surface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
+                            screenSurface.DrawingSurface.Canvas.Save();
+                            screenSurface.DrawingSurface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
                         }
 
                         var pos = chunkPos * resolution.PixelSize();
-                        screenSurface.Surface.Canvas.DrawRect(pos.X, pos.Y, resolution.PixelSize(),
+                        screenSurface.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, resolution.PixelSize(),
                             resolution.PixelSize(), ClearPaint);
                         
                         if (globalScaledClippingRectangle is not null)
-                            screenSurface.Surface.Canvas.Restore();
-                    });
+                            screenSurface.DrawingSurface.Canvas.Restore();
+                    /*});*/
                 });
     }
 }

+ 37 - 37
src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs

@@ -239,7 +239,7 @@ internal class MemberPreviewUpdater
                 if (member.PreviewSurface is not null && member.PreviewSurface.Size.X == newSize.Value.previewSize.X &&
                     member.PreviewSurface.Size.Y == newSize.Value.previewSize.Y)
                 {
-                    member.PreviewSurface!.Surface.Canvas.Clear();
+                    member.PreviewSurface!.DrawingSurface.Canvas.Clear();
                 }
                 else
                 {
@@ -436,22 +436,22 @@ internal class MemberPreviewUpdater
             };
             var pos = chunkPos * resolution.PixelSize();
             var rendered = doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameTime);
-            doc.PreviewSurface.Surface.Canvas.Save();
-            doc.PreviewSurface.Surface.Canvas.Scale(scaling);
-            doc.PreviewSurface.Surface.Canvas.ClipRect((RectD)cumulative.GlobalArea);
-            doc.PreviewSurface.Surface.Canvas.Scale(1 / (float)resolution.Multiplier());
+            doc.PreviewSurface.DrawingSurface.Canvas.Save();
+            doc.PreviewSurface.DrawingSurface.Canvas.Scale(scaling);
+            doc.PreviewSurface.DrawingSurface.Canvas.ClipRect((RectD)cumulative.GlobalArea);
+            doc.PreviewSurface.DrawingSurface.Canvas.Scale(1 / (float)resolution.Multiplier());
             if (rendered.IsT1)
             {
-                doc.PreviewSurface.Surface.Canvas.DrawRect(pos.X, pos.Y, resolution.PixelSize(),
+                doc.PreviewSurface.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, resolution.PixelSize(),
                     resolution.PixelSize(), ClearPaint);
             }
             else if (rendered.IsT0)
             {
                 using var renderedChunk = rendered.AsT0;
-                renderedChunk.DrawChunkOn(doc.PreviewSurface.Surface, pos, SmoothReplacingPaint);
+                renderedChunk.DrawChunkOn(doc.PreviewSurface.DrawingSurface, pos, SmoothReplacingPaint);
             }
 
-            doc.PreviewSurface.Surface.Canvas.Restore();
+            doc.PreviewSurface.DrawingSurface.Canvas.Restore();
         }
 
         if (somethingChanged)
@@ -562,10 +562,10 @@ internal class MemberPreviewUpdater
     {
         QueueRender(() =>
         {
-            memberVM.PreviewSurface.Surface.Canvas.Save();
-            memberVM.PreviewSurface.Surface.Canvas.Scale(scaling);
-            memberVM.PreviewSurface.Surface.Canvas.Translate(-position);
-            memberVM.PreviewSurface.Surface.Canvas.ClipRect((RectD)area.GlobalArea);
+            memberVM.PreviewSurface.DrawingSurface.Canvas.Save();
+            memberVM.PreviewSurface.DrawingSurface.Canvas.Scale(scaling);
+            memberVM.PreviewSurface.DrawingSurface.Canvas.Translate(-position);
+            memberVM.PreviewSurface.DrawingSurface.Canvas.ClipRect((RectD)area.GlobalArea);
             foreach (var chunk in area.Chunks)
             {
                 var pos = chunk * ChunkResolution.Full.PixelSize();
@@ -587,18 +587,18 @@ internal class MemberPreviewUpdater
 
                 if (rendered.IsT0)
                 {
-                    memberVM.PreviewSurface.Surface.Canvas.DrawSurface(rendered.AsT0.Surface.DrawingSurface, pos,
+                    memberVM.PreviewSurface.DrawingSurface.Canvas.DrawSurface(rendered.AsT0.Surface.DrawingSurface, pos,
                         scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint);
                     rendered.AsT0.Dispose();
                 }
                 else
                 {
-                    memberVM.PreviewSurface.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkResolution.Full.PixelSize(),
+                    memberVM.PreviewSurface.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, ChunkResolution.Full.PixelSize(),
                         ChunkResolution.Full.PixelSize(), ClearPaint);
                 }
             }
 
-            memberVM.PreviewSurface.Surface.Canvas.Restore();
+            memberVM.PreviewSurface.DrawingSurface.Canvas.Restore();
         });
     }
 
@@ -610,10 +610,10 @@ internal class MemberPreviewUpdater
     {
         QueueRender(() =>
         {
-            surface.Surface.Canvas.Save();
-            surface.Surface.Canvas.Scale(scaling);
-            surface.Surface.Canvas.Translate(-position);
-            surface.Surface.Canvas.ClipRect((RectD)area.GlobalArea);
+            surface.DrawingSurface.Canvas.Save();
+            surface.DrawingSurface.Canvas.Scale(scaling);
+            surface.DrawingSurface.Canvas.Translate(-position);
+            surface.DrawingSurface.Canvas.ClipRect((RectD)area.GlobalArea);
 
             foreach (var chunk in area.Chunks)
             {
@@ -623,15 +623,15 @@ internal class MemberPreviewUpdater
 
                 if (!result.DrawCommittedChunkOn(
                         chunk,
-                        ChunkResolution.Full, surface.Surface, pos,
+                        ChunkResolution.Full, surface.DrawingSurface, pos,
                         scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint))
                 {
-                    surface.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
+                    surface.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
                         ChunkyImage.FullChunkSize, ClearPaint);
                 }
             }
 
-            surface.Surface.Canvas.Restore();
+            surface.DrawingSurface.Canvas.Restore();
         });
     }
 
@@ -645,21 +645,21 @@ internal class MemberPreviewUpdater
 
         QueueRender(() =>
         {
-            keyFrameVM.PreviewSurface!.Surface.Canvas.Save();
+            keyFrameVM.PreviewSurface!.DrawingSurface.Canvas.Save();
             float scaling = (float)keyFrameVM.PreviewSurface.Size.X / internals.Tracker.Document.Size.X;
-            keyFrameVM.PreviewSurface.Surface.Canvas.Scale(scaling);
+            keyFrameVM.PreviewSurface.DrawingSurface.Canvas.Scale(scaling);
             foreach (var chunk in area.Chunks)
             {
                 var pos = chunk * ChunkResolution.Full.PixelSize();
                 if (!node.GetLayerImageByKeyFrameGuid(keyFrameVM.Id).DrawCommittedChunkOn(chunk, ChunkResolution.Full,
-                        keyFrameVM.PreviewSurface!.Surface, pos, ReplacingPaint))
+                        keyFrameVM.PreviewSurface!.DrawingSurface, pos, ReplacingPaint))
                 {
-                    keyFrameVM.PreviewSurface!.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
+                    keyFrameVM.PreviewSurface!.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
                         ChunkyImage.FullChunkSize, ClearPaint);
                 }
             }
 
-            keyFrameVM.PreviewSurface!.Surface.Canvas.Restore();
+            keyFrameVM.PreviewSurface!.DrawingSurface.Canvas.Restore();
         });
     }
 
@@ -708,19 +708,19 @@ internal class MemberPreviewUpdater
 
             QueueRender(() =>
             {
-                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);
+                memberVM.MaskPreviewSurface!.DrawingSurface.Canvas.Save();
+                memberVM.MaskPreviewSurface.DrawingSurface.Canvas.Scale(scaling);
+                memberVM.MaskPreviewSurface.DrawingSurface.Canvas.Translate(-position);
+                memberVM.MaskPreviewSurface.DrawingSurface.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,
+                    (chunk, ChunkResolution.Full, memberVM.MaskPreviewSurface.DrawingSurface, pos,
                         scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint);
                 }
 
-                memberVM.MaskPreviewSurface.Surface.Canvas.Restore();
+                memberVM.MaskPreviewSurface.DrawingSurface.Canvas.Restore();
             });
 
             infos.Add(new MaskPreviewDirty_RenderInfo(guid));
@@ -756,15 +756,15 @@ internal class MemberPreviewUpdater
 
             QueueRender(() =>
             {
-                nodeVm.ResultPreview.Surface.Canvas.Save();
-                nodeVm.ResultPreview.Surface.Canvas.Scale(scalingX, scalingY);
+                nodeVm.ResultPreview.DrawingSurface.Canvas.Save();
+                nodeVm.ResultPreview.DrawingSurface.Canvas.Scale(scalingX, scalingY);
 
                 RectI region = new RectI(0, 0, node.CachedResult.Size.X, node.CachedResult.Size.Y);
 
-                nodeVm.ResultPreview.Surface.Canvas.DrawSurface(node.CachedResult.DrawingSurface, 0, 0,
+                nodeVm.ResultPreview.DrawingSurface.Canvas.DrawSurface(node.CachedResult.DrawingSurface, 0, 0,
                     ReplacingPaint);
 
-                nodeVm.ResultPreview.Surface.Canvas.Restore();
+                nodeVm.ResultPreview.DrawingSurface.Canvas.Restore();
             });
 
             infos.Add(new NodePreviewDirty_RenderInfo(node.Id));

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

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

+ 3 - 3
src/PixiEditor/Views/Rendering/Scene.cs

@@ -147,7 +147,7 @@ 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();
+        Surface.DrawingSurface.Flush();
         using var operation = new DrawSceneOperation(Surface, Document, CanvasPos, Scale * resolutionScale, angle,
             FlipX, FlipY,
             dirtyRect,
@@ -537,12 +537,12 @@ internal class DrawSceneOperation : SkiaDrawOperation
         {
             // snapshotting wanted region on CPU is faster than rendering whole surface on CPU,
             // but slower than rendering whole surface on GPU
-            using Image snapshot = Surface.Surface.Snapshot(SurfaceRectToRender);
+            using Image snapshot = Surface.DrawingSurface.Snapshot(SurfaceRectToRender);
             canvas.DrawImage((SKImage)snapshot.Native, SurfaceRectToRender.X, SurfaceRectToRender.Y, _paint);
         }
         else
         {
-            canvas.DrawSurface(Surface.Surface.Native as SKSurface, 0, 0, _paint);
+            canvas.DrawSurface(Surface.DrawingSurface.Native as SKSurface, 0, 0, _paint);
         }
 
         canvas.Restore();

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

@@ -107,7 +107,7 @@ public class TextureControl : Control
         }
         
         Texture texture = Texture;
-        texture.Surface.Flush();
+        texture.DrawingSurface.Flush();
         ICustomDrawOperation drawOperation = new DrawTextureOperation(
             new Rect(0, 0, Bounds.Width, Bounds.Height),
             Stretch,
@@ -164,7 +164,7 @@ internal class DrawTextureOperation : SkiaDrawOperation
 
         canvas.Save();
         ScaleCanvas(canvas);
-        canvas.DrawSurface(Texture.Surface.Native as SKSurface, 0, 0, Paint?.Native as SKPaint ?? null);
+        canvas.DrawSurface(Texture.DrawingSurface.Native as SKSurface, 0, 0, Paint?.Native as SKPaint ?? null);
         canvas.Restore();
     }
 

+ 1 - 1
src/PixiEditor/Views/Visuals/TextureImage.cs

@@ -20,7 +20,7 @@ public class TextureImage : IImage
 
     public void Draw(DrawingContext context, Rect sourceRect, Rect destRect)
     {
-        Texture.Surface.Flush();
+        Texture.DrawingSurface.Flush();
         context.Custom(new DrawTextureOperation(destRect, Stretch, Texture));
     }
 }