瀏覽代碼

benchmarks

flabbet 1 年之前
父節點
當前提交
e3e3011a56

+ 14 - 0
src/Avalonia.CustomTopLevel/Avalonia.CustomTopLevel.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net8.0</TargetFramework>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <PackageReference Include="Avalonia" Version="11.0.11" />
+    </ItemGroup>
+
+</Project>

+ 7 - 0
src/Avalonia.CustomTopLevel/Program.cs

@@ -0,0 +1,7 @@
+public static class Program
+{
+    public static void Main()
+    {
+        
+    }
+}

+ 70 - 0
src/Avalonia.CustomTopLevel/SilkTopLevel.cs

@@ -0,0 +1,70 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+using Avalonia.Rendering.Composition;
+
+namespace Avalonia.CustomTopLevel;
+
+public class SilkTopLevel : ITopLevelImpl
+{
+    
+    public Size ClientSize { get; }
+    public Size? FrameSize { get; }
+    public double RenderScaling { get; }
+    public IEnumerable<object> Surfaces { get; }
+    public Action<RawInputEventArgs>? Input { get; }
+    public Action<Rect>? Paint { get; }
+    public Action<Size, WindowResizeReason>? Resized { get; }
+    public Action<double>? ScalingChanged { get; }
+    public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; }
+    public Compositor Compositor { get; }
+    public Action? Closed { get; }
+    public Action? LostFocus { get; }
+    public WindowTransparencyLevel TransparencyLevel { get; }
+    public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; }
+    
+    public object? TryGetFeature(Type featureType)
+    {
+        
+    }
+
+    public void Dispose()
+    {
+    }
+
+    public void SetInputRoot(IInputRoot inputRoot)
+    {
+        
+    }
+
+    public Point PointToClient(PixelPoint point)
+    {
+        throw new NotImplementedException();
+    }
+
+    public PixelPoint PointToScreen(Point point)
+    {
+        throw new NotImplementedException();
+    }
+
+    public void SetCursor(ICursorImpl? cursor)
+    {
+        throw new NotImplementedException();
+    }
+
+    public IPopupImpl? CreatePopup()
+    {
+        throw new NotImplementedException();
+    }
+
+    public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
+    {
+        throw new NotImplementedException();
+    }
+
+    public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+    {
+        throw new NotImplementedException();
+    }
+}

+ 22 - 0
src/DrawingApi.Benchmarks/DrawingApi.Benchmarks.csproj

@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net8.0</TargetFramework>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+      <Optimize>true</Optimize>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <ProjectReference Include="..\PixiEditor.DrawingApi.Core\PixiEditor.DrawingApi.Core.csproj" />
+      <ProjectReference Include="..\PixiEditor.DrawingApi.Skia\PixiEditor.DrawingApi.Skia.csproj" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
+      <PackageReference Include="Silk.NET.OpenGL" Version="2.21.0" />
+      <PackageReference Include="Silk.NET.Windowing" Version="2.21.0" />
+    </ItemGroup>
+
+</Project>

+ 7 - 0
src/DrawingApi.Benchmarks/GraphicsContext.cs

@@ -0,0 +1,7 @@
+namespace DrawingApi.Benchmarks;
+
+public enum GraphicsContext
+{
+    CPU,
+    OpenGL
+}

+ 109 - 0
src/DrawingApi.Benchmarks/Program.cs

@@ -0,0 +1,109 @@
+using System.Diagnostics;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Running;
+using DrawingApi.Benchmarks;
+using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
+using PixiEditor.DrawingApi.Core.Surface.PaintImpl;
+using PixiEditor.DrawingApi.Skia;
+using PixiEditor.Numerics;
+using Silk.NET.OpenGL;
+using Silk.NET.Windowing;
+using SkiaSharp;
+
+public static class Program
+{
+    public static IWindow window;
+    public static void Main()
+    {
+        WindowOptions options = WindowOptions.Default with { IsVisible = false };
+
+        window = Window.Create(options);
+
+        GRContext GrContext;
+        GL gl;
+
+        window.Load += () =>
+        {
+            gl = GL.GetApi(window);
+            GrContext = GRContext.CreateGl();
+
+            DrawingBackendApi.SetupBackend(new SkiaDrawingBackend(GrContext));
+
+            Stopwatch stopwatch = new Stopwatch();
+            
+            SurfaceBenchmarks cpuBenchmarks = new SurfaceBenchmarks();
+            cpuBenchmarks.GraphicsContext = GraphicsContext.CPU;
+            
+            stopwatch.Start();
+            var cpuResult = cpuBenchmarks.MergeTwoSurfaces();
+            stopwatch.Stop();
+            
+            Console.WriteLine($"Merge CPU: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            SurfaceBenchmarks glBenchmarks = new SurfaceBenchmarks();
+            glBenchmarks.GraphicsContext = GraphicsContext.OpenGL;
+            
+            stopwatch.Restart();
+            var result = glBenchmarks.MergeTwoSurfaces();
+            stopwatch.Stop();
+            
+            Console.WriteLine($"Merge OpenGL: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            var toSnapshotCpu = cpuBenchmarks.CreateDrawingSurface(new VecI(10000, 10000));
+            toSnapshotCpu.Canvas.DrawRect(0, 0, 10000, 10000, new Paint() { Color = new Color(255, 0, 0) });
+
+            stopwatch.Restart();
+            var cpuSnapshot = cpuBenchmarks.Snapshot(toSnapshotCpu);
+            stopwatch.Stop();
+            
+            Console.WriteLine($"CPU Snapshot: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            var toSnapshotGl = glBenchmarks.CreateDrawingSurface(new VecI(10000, 10000));
+            toSnapshotGl.Canvas.DrawRect(0, 0, 10000, 10000, new Paint() { Color = new Color(255, 0, 0) });
+            
+            stopwatch.Restart();
+            var glSnapshot = glBenchmarks.Snapshot(toSnapshotGl);
+            stopwatch.Stop();
+            
+            Console.WriteLine($"OpenGL Snapshot: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            stopwatch.Restart();
+            var cpuPixmap = cpuSnapshot.PeekPixels();
+            stopwatch.Stop();
+            
+            Console.WriteLine($"CPU Peek Pixels: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            stopwatch.Restart();
+            var glPixmap = glSnapshot.PeekPixels();
+            stopwatch.Stop();
+            
+            Console.WriteLine($"OpenGL Peek Pixels: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            stopwatch.Restart();
+            cpuBenchmarks.PickColor(cpuPixmap, 5000, 5000);
+            stopwatch.Stop();
+            
+            Console.WriteLine($"CPU Pick Color: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            stopwatch.Restart();
+            glBenchmarks.PickColor(glPixmap, 5000, 5000);
+            stopwatch.Stop();
+            
+            Console.WriteLine($"OpenGL Pick Color: {stopwatch.Elapsed.TotalMicroseconds} micro seconds");
+            
+            window.Close();
+        };
+
+        window.Run();
+    }
+    
+    public static void SaveToDesktop(DrawingSurface surface, string fileName)
+    {
+        using Image img = surface.Snapshot();
+        using var data = img.Encode();
+        System.IO.File.WriteAllBytes(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName), data.AsSpan().ToArray());
+    }
+}

+ 61 - 0
src/DrawingApi.Benchmarks/SurfaceBenchmarks.cs

@@ -0,0 +1,61 @@
+using System.Diagnostics;
+using BenchmarkDotNet.Attributes;
+using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
+using PixiEditor.DrawingApi.Core.Surface.PaintImpl;
+using PixiEditor.DrawingApi.Skia;
+using PixiEditor.Numerics;
+using Silk.NET.OpenGL;
+using Silk.NET.Windowing;
+using SkiaSharp;
+
+namespace DrawingApi.Benchmarks;
+
+public class SurfaceBenchmarks
+{
+    public GraphicsContext GraphicsContext { get; set; }
+
+    public DrawingSurface CreateDrawingSurface(VecI size)
+    {
+        ImageInfo info = new(size.X, size.Y);
+        if (GraphicsContext == GraphicsContext.CPU)
+        {
+            return DrawingSurface.Create(info);
+        }
+
+        if (GraphicsContext == GraphicsContext.OpenGL)
+        {
+            return DrawingSurface.Create(info, true);
+        }
+
+        return null;
+    }
+    
+    public DrawingSurface MergeTwoSurfaces()
+    {
+        DrawingSurface surface1 = CreateDrawingSurface(new VecI(10000, 10000));
+        DrawingSurface surface2 = CreateDrawingSurface(new VecI(10000, 10000));
+        surface2.Canvas.DrawRect(0, 0, 10000, 10000, new Paint() { Color = new Color(255, 0, 0) });
+
+        surface1.Canvas.DrawSurface(surface2, 0, 0, new Paint());
+        
+        return surface1;
+    }
+
+    public Image Snapshot(DrawingSurface surface)
+    {
+        return surface.Snapshot();
+    }
+    
+    public void PeekPixels(Image image)
+    { 
+        image.PeekPixels();
+    }
+
+    public void PickColor(Pixmap pixmap, int x, int y)
+    {
+        pixmap.GetColor(x, y);
+    }
+}

+ 2 - 0
src/PixiEditor.DrawingApi.Core/Bridge/DrawingBackendApi.cs

@@ -18,6 +18,8 @@ namespace PixiEditor.DrawingApi.Core.Bridge
             }
             }
         }
         }
         
         
+        public static bool HasBackend => _current != null;
+        
         public static void SetupBackend(IDrawingBackend backend)
         public static void SetupBackend(IDrawingBackend backend)
         {
         {
             if (_current != null)
             if (_current != null)

+ 2 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPixmapImplementation.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 
 
@@ -21,4 +22,5 @@ public interface IPixmapImplementation
 
 
     public int GetBytesSize(Pixmap pixmap);
     public int GetBytesSize(Pixmap pixmap);
     public object GetNativePixmap(IntPtr objectPointer);
     public object GetNativePixmap(IntPtr objectPointer);
+    public Color GetColor(Pixmap pixmap, int x, int y);
 }
 }

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

@@ -20,5 +20,6 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
         public int GetWidth(IntPtr objectPointer);
         public int GetWidth(IntPtr objectPointer);
         public int GetHeight(IntPtr objectPointer);
         public int GetHeight(IntPtr objectPointer);
         public object GetNativeImage(IntPtr objectPointer);
         public object GetNativeImage(IntPtr objectPointer);
+        public Pixmap PeekPixels(Image image);
     }
     }
 }
 }

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

@@ -15,6 +15,7 @@ public interface ISurfaceImplementation
     public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixelBuffer);
     public DrawingSurface Create(ImageInfo imageInfo, IntPtr pixelBuffer);
     public DrawingSurface Create(Pixmap pixmap);
     public DrawingSurface Create(Pixmap pixmap);
     public DrawingSurface Create(ImageInfo imageInfo);
     public DrawingSurface Create(ImageInfo imageInfo);
+    public DrawingSurface Create(ImageInfo imageInfo, bool isGpuBacked);
     public void Dispose(DrawingSurface drawingSurface);
     public void Dispose(DrawingSurface drawingSurface);
     public object GetNativeSurface(IntPtr objectPointer);
     public object GetNativeSurface(IntPtr objectPointer);
 }
 }

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

@@ -65,6 +65,11 @@ namespace PixiEditor.DrawingApi.Core.Surface
             return DrawingBackendApi.Current.SurfaceImplementation.Create(imageInfo, pixelBuffer);
             return DrawingBackendApi.Current.SurfaceImplementation.Create(imageInfo, pixelBuffer);
         }
         }
 
 
+        public static DrawingSurface Create(ImageInfo info, bool isGpuBacked)
+        {
+            return DrawingBackendApi.Current.SurfaceImplementation.Create(info, isGpuBacked);
+        }
+
         public override void Dispose()
         public override void Dispose()
         {
         {
             Canvas.Changed -= OnCanvasChanged;
             Canvas.Changed -= OnCanvasChanged;

+ 5 - 0
src/PixiEditor.DrawingApi.Core/Surface/ImageData/Image.cs

@@ -47,6 +47,11 @@ namespace PixiEditor.DrawingApi.Core.Surface.ImageData
         {
         {
             return DrawingBackendApi.Current.ImageImplementation.Encode(this);
             return DrawingBackendApi.Current.ImageImplementation.Encode(this);
         }
         }
+        
+        public Pixmap PeekPixels()
+        {
+            return DrawingBackendApi.Current.ImageImplementation.PeekPixels(this);
+        }
 
 
         public ImgData Encode(EncodedImageFormat format, int quality = 100)
         public ImgData Encode(EncodedImageFormat format, int quality = 100)
         {
         {

+ 6 - 0
src/PixiEditor.DrawingApi.Core/Surface/Pixmap.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 
 
 namespace PixiEditor.DrawingApi.Core.Surface;
 namespace PixiEditor.DrawingApi.Core.Surface;
@@ -43,6 +44,11 @@ public class Pixmap : NativeObject
     {
     {
         return DrawingBackendApi.Current.PixmapImplementation.GetPixels(ObjectPointer);
         return DrawingBackendApi.Current.PixmapImplementation.GetPixels(ObjectPointer);
     }
     }
+    
+    public Color GetColor(int x, int y)
+    {
+        return DrawingBackendApi.Current.PixmapImplementation.GetColor(this, x, y);
+    }
 
 
     public Span<T> GetPixelSpan<T>() where T : unmanaged
     public Span<T> GetPixelSpan<T>() where T : unmanaged
     {
     {

+ 18 - 1
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaImageImplementation.cs

@@ -13,10 +13,12 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
     {
     {
         private readonly SkObjectImplementation<SKData> _imgImplementation;
         private readonly SkObjectImplementation<SKData> _imgImplementation;
         private SkObjectImplementation<SKSurface>? _surfaceImplementation;
         private SkObjectImplementation<SKSurface>? _surfaceImplementation;
+        private SkiaPixmapImplementation pixmapImpl;
         
         
-        public SkiaImageImplementation(SkObjectImplementation<SKData> imgDataImplementation)
+        public SkiaImageImplementation(SkObjectImplementation<SKData> imgDataImplementation, SkiaPixmapImplementation pixmapImplementation)
         {
         {
             _imgImplementation = imgDataImplementation;
             _imgImplementation = imgDataImplementation;
+            pixmapImpl = pixmapImplementation;
         }
         }
         
         
         public void SetSurfaceImplementation(SkObjectImplementation<SKSurface> surfaceImplementation)
         public void SetSurfaceImplementation(SkObjectImplementation<SKSurface> surfaceImplementation)
@@ -110,6 +112,21 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         {
         {
             return ManagedInstances[objectPointer].Height;
             return ManagedInstances[objectPointer].Height;
         }
         }
+        
+        public Pixmap PeekPixels(Image image)
+        {
+            var native = ManagedInstances[image.ObjectPointer];
+            var pixmap = native.PeekPixels();
+            if (pixmap is null)
+            {
+                ImageInfo info = new ImageInfo(image.Width, image.Height);
+                SKBitmap skBitmap = new SKBitmap(info.ToSkImageInfo());
+                pixmap = skBitmap.PeekPixels();
+                native.ReadPixels(skBitmap.PeekPixels());
+            }
+            
+            return pixmapImpl.CreateFrom(pixmap);
+        }
 
 
         public object GetNativeImage(IntPtr objectPointer)
         public object GetNativeImage(IntPtr objectPointer)
         {
         {

+ 7 - 0
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaPixmapImplementation.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
 using PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using SkiaSharp;
 using SkiaSharp;
@@ -58,6 +59,12 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         {
         {
             return ManagedInstances[objectPointer];
             return ManagedInstances[objectPointer];
         }
         }
+        
+        public Color GetColor(Pixmap pixmap, int x, int y)
+        {
+            SKColor color = ManagedInstances[pixmap.ObjectPointer].GetPixelColor(x, y);
+            return new Color(color.Red, color.Green, color.Blue, color.Alpha);
+        }
 
 
         public Pixmap CreateFrom(SKPixmap pixmap)
         public Pixmap CreateFrom(SKPixmap pixmap)
         {
         {

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

@@ -83,7 +83,13 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
 
 
         public DrawingSurface Create(ImageInfo imageInfo)
         public DrawingSurface Create(ImageInfo imageInfo)
         {
         {
-            SKSurface skSurface = SKSurface.Create(grContext, false, imageInfo.ToSkImageInfo());
+            SKSurface skSurface = SKSurface.Create(imageInfo.ToSkImageInfo());
+            return CreateDrawingSurface(skSurface);
+        }
+
+        public DrawingSurface Create(ImageInfo imageInfo, bool isGpuBacked)
+        {
+            SKSurface skSurface = SKSurface.Create(grContext, isGpuBacked, imageInfo.ToSkImageInfo());
             return CreateDrawingSurface(skSurface);
             return CreateDrawingSurface(skSurface);
         }
         }
 
 

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

@@ -29,7 +29,13 @@ namespace PixiEditor.DrawingApi.Skia
             SkiaImgDataImplementation dataImpl = new SkiaImgDataImplementation();
             SkiaImgDataImplementation dataImpl = new SkiaImgDataImplementation();
             ImgDataImplementation = dataImpl;
             ImgDataImplementation = dataImpl;
             
             
-            SkiaImageImplementation imgImpl = new SkiaImageImplementation(dataImpl);
+            SkiaColorSpaceImplementation colorSpaceImpl = new SkiaColorSpaceImplementation();
+            ColorSpaceImplementation = colorSpaceImpl;
+
+            SkiaPixmapImplementation pixmapImpl = new SkiaPixmapImplementation(colorSpaceImpl);
+            PixmapImplementation = pixmapImpl;
+            
+            SkiaImageImplementation imgImpl = new SkiaImageImplementation(dataImpl, pixmapImpl);
             ImageImplementation = imgImpl;
             ImageImplementation = imgImpl;
             
             
             SkiaColorFilterImplementation colorFilterImpl = new SkiaColorFilterImplementation();
             SkiaColorFilterImplementation colorFilterImpl = new SkiaColorFilterImplementation();
@@ -46,12 +52,6 @@ namespace PixiEditor.DrawingApi.Skia
             
             
             MatrixImplementation = new SkiaMatrixImplementation();
             MatrixImplementation = new SkiaMatrixImplementation();
             
             
-            SkiaColorSpaceImplementation colorSpaceImpl = new SkiaColorSpaceImplementation();
-            ColorSpaceImplementation = colorSpaceImpl;
-
-            SkiaPixmapImplementation pixmapImpl = new SkiaPixmapImplementation(colorSpaceImpl);
-            PixmapImplementation = pixmapImpl;
-            
             SkiaBitmapImplementation bitmapImpl = new SkiaBitmapImplementation(imgImpl);
             SkiaBitmapImplementation bitmapImpl = new SkiaBitmapImplementation(imgImpl);
             BitmapImplementation = bitmapImpl;
             BitmapImplementation = bitmapImpl;
             
             

+ 62 - 0
src/PixiEditor.sln

@@ -102,6 +102,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.AnimationRendere
 EndProject
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AnimationRendering", "AnimationRendering", "{2BA72059-FFD7-4887-AE88-269017198933}"
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AnimationRendering", "AnimationRendering", "{2BA72059-FFD7-4887-AE88-269017198933}"
 EndProject
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DrawingApi.Benchmarks", "DrawingApi.Benchmarks\DrawingApi.Benchmarks.csproj", "{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.CustomTopLevel", "Avalonia.CustomTopLevel\Avalonia.CustomTopLevel.csproj", "{030B4397-B53A-4F5E-94FF-603AA0004997}"
+EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x64 = Debug|x64
 		Debug|x64 = Debug|x64
@@ -1500,6 +1504,62 @@ Global
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|x64.Build.0 = Debug|Any CPU
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|x64.Build.0 = Debug|Any CPU
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|ARM64.ActiveCfg = Debug|Any CPU
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|ARM64.ActiveCfg = Debug|Any CPU
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|ARM64.Build.0 = Debug|Any CPU
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|ARM64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Debug|x64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Debug|ARM64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevRelease|x64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevRelease|x64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevRelease|ARM64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevRelease|ARM64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevSteam|x64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevSteam|x64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevSteam|ARM64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.DevSteam|ARM64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX Debug|x64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX Debug|x64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX Debug|ARM64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX|x64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX|x64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX|ARM64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.MSIX|ARM64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Release|x64.ActiveCfg = Release|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Release|x64.Build.0 = Release|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Release|ARM64.ActiveCfg = Release|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Release|ARM64.Build.0 = Release|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Steam|x64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Steam|x64.Build.0 = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Steam|ARM64.ActiveCfg = Debug|Any CPU
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A}.Steam|ARM64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Debug|x64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Debug|ARM64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevRelease|x64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevRelease|x64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevRelease|ARM64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevRelease|ARM64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevSteam|x64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevSteam|x64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevSteam|ARM64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.DevSteam|ARM64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX Debug|x64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX Debug|x64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX Debug|ARM64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX|x64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX|x64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX|ARM64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.MSIX|ARM64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Release|x64.ActiveCfg = Release|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Release|x64.Build.0 = Release|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Release|ARM64.ActiveCfg = Release|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Release|ARM64.Build.0 = Release|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Steam|x64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Steam|x64.Build.0 = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Steam|ARM64.ActiveCfg = Debug|Any CPU
+		{030B4397-B53A-4F5E-94FF-603AA0004997}.Steam|ARM64.Build.0 = Debug|Any CPU
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE
@@ -1546,6 +1606,8 @@ Global
 		{2BA72059-FFD7-4887-AE88-269017198933} = {1E816135-76C1-4255-BE3C-BF17895A65AA}
 		{2BA72059-FFD7-4887-AE88-269017198933} = {1E816135-76C1-4255-BE3C-BF17895A65AA}
 		{9B552A44-9587-4410-8673-254B31E2E4F7} = {2BA72059-FFD7-4887-AE88-269017198933}
 		{9B552A44-9587-4410-8673-254B31E2E4F7} = {2BA72059-FFD7-4887-AE88-269017198933}
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C} = {2BA72059-FFD7-4887-AE88-269017198933}
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C} = {2BA72059-FFD7-4887-AE88-269017198933}
+		{34B1472E-EE1B-46C7-B5ED-29CD13457C7A} = {5AFBF881-C054-4CE4-8159-8D4017FFD27A}
+		{030B4397-B53A-4F5E-94FF-603AA0004997} = {5AFBF881-C054-4CE4-8159-8D4017FFD27A}
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {D04B4AB0-CA33-42FD-A909-79966F9255C5}
 		SolutionGuid = {D04B4AB0-CA33-42FD-A909-79966F9255C5}