]> O.S.I.I.S - jp/crow.git/commitdiff
update backend system, create first backend found in backend directory
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 23 Dec 2021 02:33:41 +0000 (03:33 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 23 Dec 2021 02:33:41 +0000 (03:33 +0100)
21 files changed:
Backends/CairoBackend/src/CairoBackendBase.cs
Backends/CairoBackend/src/DefaultBackend.cs [deleted file]
Backends/CairoBackend/src/EglBackend.cs
Backends/CairoBackend/src/ImageBackend.cs
Backends/Directory.Build.props [new file with mode: 0644]
Backends/SkiaBackend/src/DefaultBackend.cs
Backends/SkiaBackend/src/EglBackend.cs
Backends/SkiaBackend/src/VulkanBackend.cs [deleted file]
Backends/VkvgBackend/src/DefaultBackend.cs
Backends/VkvgBackend/src/Device.cs
Backends/VkvgBackend/src/NativeMethods.cs
Backends/VkvgBackend/src/SvgHandle.cs
Backends/VkvgBackend/src/VulkanContext.cs
Crow/Crow.csproj
Crow/src/Interface.cs
Drawing2D/Drawing2D.csproj
Drawing2D/src/CrowBackend.cs [new file with mode: 0644]
Drawing2D/src/Enums.cs
Drawing2D/src/IBackend.cs [deleted file]
Samples/Directory.Build.props
Samples/PerfTests/Program.cs

index db6895c2f0d42fe5b048eb2597c9c66e608f5aee..c7821ee34e2bc48e56cbe9f6f50f006e97af59aa 100644 (file)
@@ -5,14 +5,19 @@ using Glfw;
 
 namespace Crow.CairoBackend
 {
-       public abstract class CairoBackendBase : IBackend {
-               protected IntPtr hWin;
+       public abstract class CairoBackendBase : CrowBackend {
+               /// <summary>
+               /// Main rendering surface, usualy an accelerated window surface
+               /// </summary>
                protected Surface surf;
+               protected IRegion clipping;
                /// <summary> Global font rendering settings for Cairo </summary>
                FontOptions FontRenderingOptions;
                /// <summary> Global font rendering settings for Cairo </summary>
                Antialias Antialias = Antialias.Subpixel;
-               protected CairoBackendBase ()
+               bool disposeContextOnFlush;
+               protected CairoBackendBase (int width, int height, IntPtr nativeWindow)
+               : base (width, height, nativeWindow)
                {
                        FontRenderingOptions = new FontOptions ();
                        FontRenderingOptions.Antialias = Antialias.Subpixel;
@@ -24,11 +29,11 @@ namespace Crow.CairoBackend
                {
                        Dispose (false);
                }
-               public abstract ISurface CreateSurface(int width, int height);
-               public abstract ISurface CreateSurface(byte[] data, int width, int height);
-               public ISurface MainSurface => surf;
-               public IRegion CreateRegion () => new Region ();
-               public IContext CreateContext (ISurface surf)
+               public override abstract ISurface CreateSurface(int width, int height);
+               public override abstract ISurface CreateSurface(byte[] data, int width, int height);
+               public override ISurface MainSurface => surf;
+               public override IRegion CreateRegion () => new Region ();
+               public override IContext CreateContext (ISurface surf)
                {
                        Context gr = new Context (surf as Surface);
                        gr.FontOptions = FontRenderingOptions;
@@ -36,7 +41,7 @@ namespace Crow.CairoBackend
                        return gr;
                }
                //IPattern CreatePattern (PatternType patternType);
-               public IGradient CreateGradient (GradientType gradientType, Rectangle bounds)
+               public override IGradient CreateGradient (GradientType gradientType, Rectangle bounds)
                {
                        switch (gradientType) {
                        case GradientType.Vertical:
@@ -50,7 +55,7 @@ namespace Crow.CairoBackend
                        }
                        return null;
                }
-               public byte[] LoadBitmap (Stream stream, out Size dimensions)
+               public override byte[] LoadBitmap (Stream stream, out Size dimensions)
                {
                        byte[] image;
 #if STB_SHARP
@@ -79,15 +84,13 @@ namespace Crow.CairoBackend
 #endif
                        return image;
                }
-               public ISvgHandle LoadSvg(Stream stream)
+               public override ISvgHandle LoadSvg(Stream stream)
                {
                        using (BinaryReader sr = new BinaryReader (stream))
                                return new SvgHandle (sr.ReadBytes ((int)stream.Length));
                }
-               public ISvgHandle LoadSvg(string svgFragment) =>
+               public override ISvgHandle LoadSvg(string svgFragment) =>
                        new SvgHandle (System.Text.Encoding.Unicode.GetBytes (svgFragment));
-               bool disposeContextOnFlush;
-               protected IRegion clipping;
                protected void clear(IContext ctx) {
                        for (int i = 0; i < clipping.NumRectangles; i++)
                                ctx.Rectangle (clipping.GetRectangle (i));
@@ -97,7 +100,7 @@ namespace Crow.CairoBackend
                        ctx.Fill ();
                        ctx.Operator = Operator.Over;
                }
-               public virtual IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
+               public override IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
                {
                        this.clipping = clipping;
                        IContext ctx = existingContext;
@@ -108,20 +111,19 @@ namespace Crow.CairoBackend
                                disposeContextOnFlush = false;
                        return ctx;
                }
-               public virtual void FlushUIFrame(IContext ctx)
+               public override void FlushUIFrame(IContext ctx)
                {
                        if (disposeContextOnFlush)
                                ctx.Dispose ();
                        clipping = null;
                }
-               public virtual void ResizeMainSurface (int width, int height)
+               public override void ResizeMainSurface (int width, int height)
                {
                        surf.Resize (width, height);
                }
 
                #region IDispose implementation
-               bool isDisposed;
-               public void Dispose ()
+               public override void Dispose ()
                {
                        Dispose (true);
                        GC.SuppressFinalize (this);
diff --git a/Backends/CairoBackend/src/DefaultBackend.cs b/Backends/CairoBackend/src/DefaultBackend.cs
deleted file mode 100644 (file)
index 24d719d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using Crow.CairoBackend;
-
-namespace Crow.Backends
-{
-       public class DefaultBackend : ImageBackend {
-               /// <summary>
-               /// Create a new generic backend bound to the application surface
-               /// </summary>
-               /// <param name="width">backend surface width</param>
-               /// <param name="height">backend surface height</param>
-               public DefaultBackend (ref IntPtr nativeWindoPointer, out bool ownGlfwWinHandle, int width, int height)
-               : base (ref nativeWindoPointer, out ownGlfwWinHandle, width, height) { }
-               public DefaultBackend (int width, int height) : base (width, height) {
-
-               }
-       }
-}
-
index 38f13a2edc5a5052b72be459f450508b45baef6a..909c3cd9fc679e53dd8439489d7d43c2a9d6ca4d 100644 (file)
@@ -12,7 +12,8 @@ namespace Crow.CairoBackend
                /// </summary>
                /// <param name="width">backend surface width</param>
                /// <param name="height">backend surface height</param>
-               public EglBackend (ref IntPtr nativeWindoPointer, out bool ownGlfwWinHandle, int width, int height) : base () {
+               public EglBackend (int width, int height, IntPtr nativeWindoPointer)
+               : base (width, height, nativeWindoPointer) {
                        if (nativeWindoPointer == IntPtr.Zero) {
                                Glfw3.Init ();
                                Glfw3.WindowHint (WindowAttribute.ClientApi, Constants.OpenglEsApi);
@@ -25,12 +26,6 @@ namespace Crow.CairoBackend
                                hWin = Glfw3.CreateWindow (width, height, "win name", MonitorHandle.Zero, IntPtr.Zero);
                                if (hWin == IntPtr.Zero)
                                        throw new Exception ("[GLFW3] Unable to create Window");
-
-                               nativeWindoPointer = hWin;
-                               ownGlfwWinHandle = true;
-                       } else {
-                               hWin = nativeWindoPointer;
-                               ownGlfwWinHandle = false;
                        }
 
                        Glfw3.MakeContextCurrent (hWin);
@@ -44,7 +39,8 @@ namespace Crow.CairoBackend
                /// </summary>
                /// <param name="width">backend surface width</param>
                /// <param name="height">backend surface height</param>
-               public EglBackend (int width, int height) : base () {
+               public EglBackend (int width, int height)
+               : base (width, height, IntPtr.Zero) {
                        device = new EGLDevice (Glfw3.GetEGLDisplay (), IntPtr.Zero);
                        surf = new GLTextureSurface (device, width, height);
                }
index 67512fd9f3f67b348031de75d247638828dc89d7..96899dbde87cd2db6d35b14158702a79b307b9ad 100644 (file)
@@ -5,13 +5,15 @@ using Glfw;
 
 namespace Crow.CairoBackend
 {
-       public class ImageBackend : CairoBackendBase {
+       public class DefaultBackend : CairoBackendBase {
                /// <summary>
                /// Create a new generic backend bound to the application surface
                /// </summary>
                /// <param name="width">backend surface width</param>
                /// <param name="height">backend surface height</param>
-               public ImageBackend (ref IntPtr nativeWindoPointer, out bool ownGlfwWinHandle, int width, int height) : base () {
+               /// <param name="nativeWindoPointer"></param>
+               public DefaultBackend (int width, int height, IntPtr nativeWindoPointer)
+               : base (width, height, nativeWindoPointer) {
                        if (nativeWindoPointer == IntPtr.Zero) {
                                Glfw3.Init ();
                                Glfw3.WindowHint (WindowAttribute.ClientApi, 0);
@@ -21,18 +23,11 @@ namespace Crow.CairoBackend
                                hWin = Glfw3.CreateWindow (width, height, "win name", MonitorHandle.Zero, IntPtr.Zero);
                                if (hWin == IntPtr.Zero)
                                        throw new Exception ("[GLFW3] Unable to create Window");
-
-                               nativeWindoPointer = hWin;
-                               ownGlfwWinHandle = true;
-                       } else {
-                               hWin = nativeWindoPointer;
-                               ownGlfwWinHandle = false;
                        }
-
                        switch (Environment.OSVersion.Platform) {
                        case PlatformID.Unix:
                                IntPtr disp = Glfw3.GetX11Display ();
-                               IntPtr nativeWin = Glfw3.GetX11Window (nativeWindoPointer);
+                               IntPtr nativeWin = Glfw3.GetX11Window (hWin);
                                Int32 scr = Glfw3.GetX11DefaultScreen (disp);
                                IntPtr visual = Glfw3.GetX11DefaultVisual (disp, scr);
                                surf = new XlibSurface (disp, nativeWin, visual, width, height);
@@ -40,7 +35,7 @@ namespace Crow.CairoBackend
                        case PlatformID.Win32NT:
                        case PlatformID.Win32S:
                        case PlatformID.Win32Windows:
-                               IntPtr hWin32 = Glfw3.GetWin32Window (nativeWindoPointer);
+                               IntPtr hWin32 = Glfw3.GetWin32Window (hWin);
                                IntPtr hdc = Glfw3.GetWin32DC (hWin32);
                                surf = new Win32Surface (hdc);
                                break;
@@ -53,10 +48,12 @@ namespace Crow.CairoBackend
                /// </summary>
                /// <param name="width">backend surface width</param>
                /// <param name="height">backend surface height</param>
-               public ImageBackend (int width, int height) : base () {
+               public DefaultBackend (int width, int height)
+               : base (width, height, IntPtr.Zero) {
                        surf = new ImageSurface (Format.ARGB32, width, height);
                }
-               public ImageBackend (IntPtr surfaceBitmapData, int width, int height, int stride) : base () {
+               public DefaultBackend (IntPtr surfaceBitmapData, int width, int height, int stride)
+                : base (width, height, IntPtr.Zero) {
                        surf = new ImageSurface (surfaceBitmapData, Format.ARGB32, width, height, stride);
                }
 
diff --git a/Backends/Directory.Build.props b/Backends/Directory.Build.props
new file mode 100644 (file)
index 0000000..b78ea8c
--- /dev/null
@@ -0,0 +1,29 @@
+<Project>
+       <PropertyGroup>
+               <OutputPath>$(SolutionDir)build\backends\$(Configuration)\</OutputPath>
+               <License>MIT</License>
+               <Authors>Jean-Philippe Bruyère</Authors>
+               <LangVersion>7.3</LangVersion>
+
+               <CrowVersion>0.9.9</CrowVersion>
+               <CrowPackageVersion>$(CrowVersion)-beta</CrowPackageVersion>
+
+               <!-- If you dont have a native libstb on your system, enable the managed version of stb here
+                               TODO: this could be detected on startup or install automatically-->
+               <CrowStbSharp>true</CrowStbSharp>
+
+               <!-- Compile with logging enabled, this will slow down apps, use this only
+                        for debugging purpose-->
+               <CrowDebugLogEnabled>false</CrowDebugLogEnabled>
+
+               <!-- Collect several statistics on widgets-->
+               <CrowDebugStatsEnabled>false</CrowDebugStatsEnabled>
+
+               <!-- Used only by CrowIDE and CrowEdit-->
+               <CrowDesignModeEnabled>false</CrowDesignModeEnabled>
+
+               <GlfwSharpVersion>0.2.14</GlfwSharpVersion>
+
+               <NoWarn>$(NoWarn);1591</NoWarn>
+       </PropertyGroup>
+</Project>
index 21f7e4da4f287f5229ff58f8147b18d5a4f1d265..7d86f1fbce353126d369648c30d3180b738c98a4 100644 (file)
 // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 
 using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
 using Crow.SkiaBackend;
+using Drawing2D;
+using Glfw;
+using SkiaSharp;
 
-namespace Crow.Backends
+using vke;
+using Vulkan;
+using static Vulkan.Vk;
+
+namespace Crow.SkiaBackend
 {
-       public class DefaultBackend : VulkanBackend
+       public class DefaultBackend : CrowBackend
        {
-               public DefaultBackend (ref IntPtr nativeWindoPointer, out bool ownGlfwWinHandle, int width, int height)
-               : base (ref nativeWindoPointer, out ownGlfwWinHandle, width, height) {}
+               protected Instance instance;
+               protected PhysicalDevice phy;
+               protected vke.Device dev;
+               protected Queue graphicQueue;   //for vkvg, we must have at least a graphic queue
+               protected VkSurfaceKHR hSurf;   //Vulkan Surface
+               protected SwapChain swapChain;
+               protected CommandPool cmdPool;
+               protected PrimaryCommandBuffer[] cmds;
+               protected VkSemaphore[] drawComplete;
+               protected Fence drawFence;
+               VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;
+               bool vsync = false;
+
+               GRContext gr;
+               VkSurface surf;
+               public override ISurface MainSurface => surf;
+
+               bool tryGetPhy (vke.PhysicalDeviceCollection physicalDevices, VkPhysicalDeviceType phyType, out PhysicalDevice phy, bool swapchainSupport) {
+                       phy = physicalDevices.FirstOrDefault (p => p.Properties.deviceType == phyType && p.HasSwapChainSupport == swapchainSupport);
+                       return phy != null;
+               }
+
+               IntPtr getVkProcAddress(string name, IntPtr instance, IntPtr device) {
+                       using (FixedUtf8String n = new FixedUtf8String (name))
+                       {
+                               return device == IntPtr.Zero ?
+                                       Vk.vkGetInstanceProcAddr (instance, n) :
+                                       Vk.vkGetDeviceProcAddr (device, n);
+                       }
+               }
+               #region  CTOR
+               /// <summary>
+               /// Create a new offscreen backend, used in perfTests
+               /// </summary>
+               /// <param name="width">backend surface width</param>
+               /// <param name="height">backend surface height</param>
                public DefaultBackend (int width, int height)
-               : base (width, height) {}
+               : base (width, height, IntPtr.Zero) {
+#if DEBUG
+                       instance = new Instance (Ext.I.VK_EXT_debug_utils);
+#else
+                       instance = new Instance ();
+#endif
+                       vke.PhysicalDeviceCollection phys = instance.GetAvailablePhysicalDevice ();
+                       if (phys.Count() == 0)
+                               throw new Exception ("[Crow.VkvgBackend] No vulkan hardware found.");
+
+                       if (!tryGetPhy (phys, VkPhysicalDeviceType.DiscreteGpu, out phy, false))
+                               if (!tryGetPhy (phys, VkPhysicalDeviceType.IntegratedGpu, out phy, false))
+                                       phy = phys[0];
+
+                       VkPhysicalDeviceFeatures enabledFeatures = default;
+                       dev = new vke.Device (phy);
+                       graphicQueue = new Queue (dev, VkQueueFlags.Graphics);
+                       dev.Activate (enabledFeatures);
+
+               }
+               public DefaultBackend (int width, int height, IntPtr nativeWindoPointer)
+               : base (width, height, nativeWindoPointer)
+               {
+                       if (nativeWindoPointer == IntPtr.Zero) {
+                               Glfw3.Init ();
+                               Glfw3.WindowHint (WindowAttribute.ClientApi, 0);
+                               Glfw3.WindowHint (WindowAttribute.Resizable, 1);
+                               Glfw3.WindowHint (WindowAttribute.Decorated, 1);
+
+                               hWin = Glfw3.CreateWindow (width, height, "win name", MonitorHandle.Zero, IntPtr.Zero);
+                               if (hWin == IntPtr.Zero)
+                                       throw new Exception ("[GLFW3] Unable to create Window");
+                       }
+
+                       SwapChain.IMAGES_USAGE = VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst;
+                       SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb;
+
+                       List<string> instExts = new List<string> (Glfw3.GetRequiredInstanceExtensions ());
+#if DEBUG
+                       instExts.Add (Ext.I.VK_EXT_debug_utils);
+#endif
+                       instance = new Instance (instExts.ToArray());
+                       hSurf = instance.CreateSurface (hWin);
+
+                       vke.PhysicalDeviceCollection phys = instance.GetAvailablePhysicalDevice ();
+                       if (phys.Count() == 0)
+                               throw new Exception ("[Crow.VkvgBackend] No vulkan hardware found.");
+
+                       if (!tryGetPhy (phys, VkPhysicalDeviceType.DiscreteGpu, out phy, true))
+                               if (!tryGetPhy (phys, VkPhysicalDeviceType.IntegratedGpu, out phy, true))
+                                       phy = phys[0];
+
+                       VkPhysicalDeviceFeatures enabledFeatures = default;
+
+                       dev = new vke.Device (phy);
+                       graphicQueue = new PresentQueue (dev, VkQueueFlags.Graphics, hSurf);
+
+                       dev.Activate (enabledFeatures, Ext.D.VK_KHR_swapchain);
+
+                       swapChain = new SwapChain (graphicQueue as PresentQueue, (uint)width, (uint)height, SwapChain.PREFERED_FORMAT,
+                               vsync ? VkPresentModeKHR.FifoKHR : VkPresentModeKHR.ImmediateKHR);
+                       swapChain.Activate ();
+
+                       cmdPool = new CommandPool (dev, graphicQueue.qFamIndex, VkCommandPoolCreateFlags.ResetCommandBuffer);
+                       cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount);
+
+                       drawComplete = new VkSemaphore[swapChain.ImageCount];
+                       drawFence = new Fence (dev, true, "draw fence");
+
+                       for (int i = 0; i < swapChain.ImageCount; i++) {
+                               drawComplete[i] = dev.CreateSemaphore ();
+                               drawComplete[i].SetDebugMarkerName (dev, "Semaphore DrawComplete" + i);
+                       }
+
+                       cmdPool.SetName ("main CmdPool");
+                       GRVkBackendContext grVkCtx = new GRVkBackendContext {
+                               VkInstance = instance.Handle,
+                               VkPhysicalDevice = phy.Handle,
+                               VkQueue = graphicQueue.Handle.Handle,
+                               VkDevice = dev.Handle.Handle,
+                               GraphicsQueueIndex = 0,
+                               GetProcedureAddress = getVkProcAddress
+                       };
+                       gr = GRContext.CreateVulkan (grVkCtx);
+
+                       createMainSurface ((uint)width, (uint)height);
+               }
+               ~DefaultBackend ()
+               {
+                       Dispose (false);
+               }
+               #endregion
+
+               public override IContext CreateContext(ISurface surf) => new Context (surf as VkSurface);
+               public override IGradient CreateGradient(GradientType gradientType, Rectangle bounds)
+               {
+                       switch (gradientType) {
+                       case GradientType.Vertical:
+                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
+                       case GradientType.Horizontal:
+                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Top);
+                       case GradientType.Oblic:
+                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
+                       case GradientType.Radial:
+                               throw new NotImplementedException ();
+                       }
+                       return null;
+               }
+
+               public override IRegion CreateRegion () => new Crow.SkiaBackend.Region ();
+               public override ISurface CreateSurface(int width, int height)
+                       => new VkSurface (dev, graphicQueue, gr, (int)width, (int)height, samples);
+               public override ISurface CreateSurface(byte[] data, int width, int height)
+               {
+                       throw new NotImplementedException();
+               }
+
+               public override byte[] LoadBitmap(Stream stream, out Size dimensions)
+               {
+                       throw new NotImplementedException();
+               }
+
+               public override ISvgHandle LoadSvg(Stream stream)
+                       => new SvgHandle (stream);
+
+               public override ISvgHandle LoadSvg(string svgFragment)
+               {
+                       throw new NotImplementedException();
+               }
+
+               bool disposeContextOnFlush;
+               IRegion clipping;
+               protected void clear(IContext ctx) {
+                       for (int i = 0; i < clipping.NumRectangles; i++)
+                               ctx.Rectangle (clipping.GetRectangle (i));
+
+                       ctx.ClipPreserve ();
+                       ctx.Operator = Operator.Clear;
+                       ctx.Fill ();
+                       ctx.Operator = Operator.Over;
+               }
+               public override IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
+               {
+                       this.clipping = clipping;
+                       IContext ctx = existingContext;
+                       if (ctx == null) {
+                               disposeContextOnFlush = true;
+                               ctx = new Context (surf);
+                       } else
+                               disposeContextOnFlush = false;
+
+                       clear (ctx);
+
+                       return ctx;
+               }
+               public override void FlushUIFrame(IContext ctx)
+               {
+                       //surf.Canvas.Flush ();
+                       surf.Flush();
+
+                       if (disposeContextOnFlush)
+                               ctx.Dispose ();
+                       clipping = null;
+
+                       dev.WaitIdle();
+
+                       int idx = swapChain.GetNextImage ();
+                       if (idx < 0) {
+                               createMainSurface (swapChain.Width, swapChain.Height);
+                               return;
+                       }
+
+                       drawFence.Wait ();
+                       drawFence.Reset ();
+
+                       graphicQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence);
+                       (graphicQueue as PresentQueue).Present (swapChain, drawComplete[idx]);
+
+                       dev.WaitIdle();
+               }
+               public override void ResizeMainSurface (int width, int height) {
+                       //resize is done on swapchain image aquisition failure
+               }
+               void createMainSurface (uint width, uint height) {
+                       dev.WaitIdle();
+
+                       surf?.Dispose ();
+                       surf = new VkSurface (dev, graphicQueue, gr, (int)width, (int)height, samples);
+
+                       cmdPool.Reset();
+
+                       vke.Image blitSource = surf.Img;
+
+                       for (int i = 0; i < swapChain.ImageCount; i++) {
+                               vke.Image blitDest = swapChain.images[i];
+                               vke.PrimaryCommandBuffer cmd = cmds[i];
+                               cmd.Start();
+
+                               blitDest.SetLayout (cmd, VkImageAspectFlags.Color,
+                                       VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal,
+                                       VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.Transfer);
+
+                               blitSource.SetLayout (cmd, VkImageAspectFlags.Color,
+                                       VkImageLayout.ColorAttachmentOptimal, VkImageLayout.TransferSrcOptimal,
+                                       VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.Transfer);
+
+                               blitSource.BlitTo (cmd, blitDest, VkFilter.Nearest);
+
+                               blitDest.SetLayout (cmd, VkImageAspectFlags.Color,
+                                       VkImageLayout.TransferDstOptimal, VkImageLayout.PresentSrcKHR,
+                                       VkPipelineStageFlags.Transfer, VkPipelineStageFlags.BottomOfPipe);
+
+                               blitSource.SetLayout (cmd, VkImageAspectFlags.Color,
+                                       VkImageLayout.TransferSrcOptimal, VkImageLayout.ColorAttachmentOptimal,
+                                       VkPipelineStageFlags.Transfer, VkPipelineStageFlags.ColorAttachmentOutput);
+
+                               cmd.End ();
+                       }
+                       dev.WaitIdle ();
+               }
+               #region IDisposable implementation
+               public override void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+
+               protected virtual void Dispose (bool disposing)
+               {
+                       if (!isDisposed && disposing) {
+                               dev.WaitIdle ();
+
+                               surf.Dispose ();
+                               gr.Dispose ();
+
+                               for (int i = 0; i < swapChain.ImageCount; i++) {
+                                       dev.DestroySemaphore (drawComplete[i]);
+                                       cmds[i].Free ();
+                               }
+                               drawFence.Dispose ();
+                               swapChain.Dispose ();
+                               cmdPool.Dispose ();
+
+                               vkDestroySurfaceKHR (instance.Handle, hSurf, IntPtr.Zero);
+
+                               dev.Dispose ();
+                               instance.Dispose ();
+                       }
+                       isDisposed = true;
+               }
+               #endregion
        }
 }
\ No newline at end of file
index 96be7280b7515283a991019e21d409025c00c4a0..599a7c2bd378b1b87475ff45965b6c55507c2ba5 100644 (file)
@@ -10,15 +10,15 @@ using SkiaSharp;
 
 namespace Crow.SkiaBackend
 {
-       public class EglBackend : IBackend
+       public class EglBackend : CrowBackend
        {
                [DllImport("libEGL")]
                extern static IntPtr eglGetProcAddress(string procname);
-
                int sampleCount = 1;
                Surface surf;
-               public ISurface MainSurface => surf;
-               public EglBackend (IntPtr nativeWindoPointer, int width, int height) : base () {
+               public override ISurface MainSurface => surf;
+               public EglBackend (int width, int height, IntPtr nativeWindoPointer)
+               : base (width, height, nativeWindoPointer) {
 
                }
                /// <summary>
@@ -26,7 +26,8 @@ namespace Crow.SkiaBackend
                /// </summary>
                /// <param name="width">backend surface width</param>
                /// <param name="height">backend surface height</param>
-               public EglBackend (int width, int height) : base ()
+               public EglBackend (int width, int height)
+               : base (width, height, IntPtr.Zero)
                {
                        /*GRGlGetProcedureAddressDelegate del = new GRGlGetProcedureAddressDelegate (eglGetProcAddress);
                        GRGlInterface iface = GRGlInterface.CreateGles (del);
@@ -37,62 +38,62 @@ namespace Crow.SkiaBackend
                        SKSurface.CreateAsRenderTarget (gr,)
                        surf = new Surface (width, height);*/
                }
-               public IContext CreateContext(ISurface surf)
+               public override ISurface CreateSurface(int width, int height)
                {
                        throw new NotImplementedException();
                }
 
-               public IGradient CreateGradient(GradientType gradientType, Rectangle bounds)
+               public override ISurface CreateSurface(byte[] data, int width, int height)
                {
                        throw new NotImplementedException();
                }
 
-               public IRegion CreateRegion()
+               public override IRegion CreateRegion()
                {
                        throw new NotImplementedException();
                }
 
-               public ISurface CreateSurface(int width, int height)
+               public override IContext CreateContext(ISurface surf)
                {
                        throw new NotImplementedException();
                }
 
-               public ISurface CreateSurface(byte[] data, int width, int height)
+               public override IGradient CreateGradient(GradientType gradientType, Rectangle bounds)
                {
                        throw new NotImplementedException();
                }
 
-               public void Dispose()
+               public override byte[] LoadBitmap(Stream stream, out Size dimensions)
                {
                        throw new NotImplementedException();
                }
 
-               public void FlushUIFrame(IContext ctx)
+               public override ISvgHandle LoadSvg(Stream stream)
                {
                        throw new NotImplementedException();
                }
 
-               public byte[] LoadBitmap(Stream stream, out Size dimensions)
+               public override ISvgHandle LoadSvg(string svgFragment)
                {
                        throw new NotImplementedException();
                }
 
-               public ISvgHandle LoadSvg(Stream stream)
+               public override IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
                {
                        throw new NotImplementedException();
                }
 
-               public ISvgHandle LoadSvg(string svgFragment)
+               public override void FlushUIFrame(IContext ctx)
                {
                        throw new NotImplementedException();
                }
 
-               public IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
+               public override void ResizeMainSurface(int width, int height)
                {
                        throw new NotImplementedException();
                }
 
-               public void ResizeMainSurface(int width, int height)
+               public override void Dispose()
                {
                        throw new NotImplementedException();
                }
diff --git a/Backends/SkiaBackend/src/VulkanBackend.cs b/Backends/SkiaBackend/src/VulkanBackend.cs
deleted file mode 100644 (file)
index 09069b7..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright (c) 2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using Crow.SkiaBackend;
-using Drawing2D;
-using Glfw;
-using SkiaSharp;
-
-using vke;
-using Vulkan;
-using static Vulkan.Vk;
-
-namespace Crow.SkiaBackend
-{
-       public class VulkanBackend : IBackend
-       {
-               protected Instance instance;
-               protected PhysicalDevice phy;
-               protected vke.Device dev;
-               protected Queue graphicQueue;   //for vkvg, we must have at least a graphic queue
-               protected IntPtr hWin;                  //GLFW window native pointer.
-               protected VkSurfaceKHR hSurf;   //Vulkan Surface
-               protected SwapChain swapChain;
-               protected CommandPool cmdPool;
-               protected PrimaryCommandBuffer[] cmds;
-               protected VkSemaphore[] drawComplete;
-               protected Fence drawFence;
-               VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;
-               bool vsync = false;
-
-               GRContext gr;
-               VkSurface surf;
-               public ISurface MainSurface => surf;
-
-               bool tryGetPhy (vke.PhysicalDeviceCollection physicalDevices, VkPhysicalDeviceType phyType, out PhysicalDevice phy, bool swapchainSupport) {
-                       phy = physicalDevices.FirstOrDefault (p => p.Properties.deviceType == phyType && p.HasSwapChainSupport == swapchainSupport);
-                       return phy != null;
-               }
-
-               IntPtr getVkProcAddress(string name, IntPtr instance, IntPtr device) {
-                       using (FixedUtf8String n = new FixedUtf8String (name))
-                       {
-                               return device == IntPtr.Zero ?
-                                       Vk.vkGetInstanceProcAddr (instance, n) :
-                                       Vk.vkGetDeviceProcAddr (device, n);
-                       }
-               }
-               #region  CTOR
-               /// <summary>
-               /// Create a new offscreen backend, used in perfTests
-               /// </summary>
-               /// <param name="width">backend surface width</param>
-               /// <param name="height">backend surface height</param>
-               public VulkanBackend (int width, int height) : base () {
-#if DEBUG
-                       instance = new Instance (Ext.I.VK_EXT_debug_utils);
-#else
-                       instance = new Instance ();
-#endif
-                       vke.PhysicalDeviceCollection phys = instance.GetAvailablePhysicalDevice ();
-                       if (phys.Count() == 0)
-                               throw new Exception ("[Crow.VkvgBackend] No vulkan hardware found.");
-
-                       if (!tryGetPhy (phys, VkPhysicalDeviceType.DiscreteGpu, out phy, false))
-                               if (!tryGetPhy (phys, VkPhysicalDeviceType.IntegratedGpu, out phy, false))
-                                       phy = phys[0];
-
-                       VkPhysicalDeviceFeatures enabledFeatures = default;
-                       dev = new vke.Device (phy);
-                       graphicQueue = new Queue (dev, VkQueueFlags.Graphics);
-                       dev.Activate (enabledFeatures);
-
-               }
-               public VulkanBackend (ref IntPtr nativeWindoPointer, out bool ownGlfwWinHandle, int width, int height)
-               : base ()
-               {
-                       if (nativeWindoPointer == IntPtr.Zero) {
-                               Glfw3.Init ();
-                               Glfw3.WindowHint (WindowAttribute.ClientApi, 0);
-                               Glfw3.WindowHint (WindowAttribute.Resizable, 1);
-                               Glfw3.WindowHint (WindowAttribute.Decorated, 1);
-
-                               hWin = Glfw3.CreateWindow (width, height, "win name", MonitorHandle.Zero, IntPtr.Zero);
-                               if (hWin == IntPtr.Zero)
-                                       throw new Exception ("[GLFW3] Unable to create Window");
-
-                               nativeWindoPointer = hWin;
-                               ownGlfwWinHandle = true;
-                       } else {
-                               hWin = nativeWindoPointer;
-                               ownGlfwWinHandle = false;
-                       }
-
-                       SwapChain.IMAGES_USAGE = VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst;
-                       SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb;
-
-                       List<string> instExts = new List<string> (Glfw3.GetRequiredInstanceExtensions ());
-#if DEBUG
-                       instExts.Add (Ext.I.VK_EXT_debug_utils);
-#endif
-                       instance = new Instance (instExts.ToArray());
-                       hSurf = instance.CreateSurface (hWin);
-
-                       vke.PhysicalDeviceCollection phys = instance.GetAvailablePhysicalDevice ();
-                       if (phys.Count() == 0)
-                               throw new Exception ("[Crow.VkvgBackend] No vulkan hardware found.");
-
-                       if (!tryGetPhy (phys, VkPhysicalDeviceType.DiscreteGpu, out phy, true))
-                               if (!tryGetPhy (phys, VkPhysicalDeviceType.IntegratedGpu, out phy, true))
-                                       phy = phys[0];
-
-                       VkPhysicalDeviceFeatures enabledFeatures = default;
-
-                       dev = new vke.Device (phy);
-                       graphicQueue = new PresentQueue (dev, VkQueueFlags.Graphics, hSurf);
-
-                       dev.Activate (enabledFeatures, Ext.D.VK_KHR_swapchain);
-
-                       swapChain = new SwapChain (graphicQueue as PresentQueue, (uint)width, (uint)height, SwapChain.PREFERED_FORMAT,
-                               vsync ? VkPresentModeKHR.FifoKHR : VkPresentModeKHR.ImmediateKHR);
-                       swapChain.Activate ();
-
-                       cmdPool = new CommandPool (dev, graphicQueue.qFamIndex, VkCommandPoolCreateFlags.ResetCommandBuffer);
-                       cmds = cmdPool.AllocateCommandBuffer (swapChain.ImageCount);
-
-                       drawComplete = new VkSemaphore[swapChain.ImageCount];
-                       drawFence = new Fence (dev, true, "draw fence");
-
-                       for (int i = 0; i < swapChain.ImageCount; i++) {
-                               drawComplete[i] = dev.CreateSemaphore ();
-                               drawComplete[i].SetDebugMarkerName (dev, "Semaphore DrawComplete" + i);
-                       }
-
-                       cmdPool.SetName ("main CmdPool");
-                       GRVkBackendContext grVkCtx = new GRVkBackendContext {
-                               VkInstance = instance.Handle,
-                               VkPhysicalDevice = phy.Handle,
-                               VkQueue = graphicQueue.Handle.Handle,
-                               VkDevice = dev.VkDev.Handle,
-                               GraphicsQueueIndex = 0,
-                               GetProcedureAddress = getVkProcAddress
-                       };
-                       gr = GRContext.CreateVulkan (grVkCtx);
-
-                       createMainSurface ((uint)width, (uint)height);
-               }
-               ~VulkanBackend ()
-               {
-                       Dispose (false);
-               }
-               #endregion
-
-               public IContext CreateContext(ISurface surf) => new Context (surf as VkSurface);
-               public IGradient CreateGradient(GradientType gradientType, Rectangle bounds)
-               {
-                       switch (gradientType) {
-                       case GradientType.Vertical:
-                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
-                       case GradientType.Horizontal:
-                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Top);
-                       case GradientType.Oblic:
-                               return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
-                       case GradientType.Radial:
-                               throw new NotImplementedException ();
-                       }
-                       return null;
-               }
-
-               public IRegion CreateRegion () => new Crow.SkiaBackend.Region ();
-               public ISurface CreateSurface(int width, int height)
-                       => new VkSurface (dev, graphicQueue, gr, (int)width, (int)height, samples);
-               public ISurface CreateSurface(byte[] data, int width, int height)
-               {
-                       throw new NotImplementedException();
-               }
-
-               public byte[] LoadBitmap(Stream stream, out Size dimensions)
-               {
-                       throw new NotImplementedException();
-               }
-
-               public ISvgHandle LoadSvg(Stream stream)
-                       => new SvgHandle (stream);
-
-               public ISvgHandle LoadSvg(string svgFragment)
-               {
-                       throw new NotImplementedException();
-               }
-
-               bool disposeContextOnFlush;
-               IRegion clipping;
-               protected void clear(IContext ctx) {
-                       for (int i = 0; i < clipping.NumRectangles; i++)
-                               ctx.Rectangle (clipping.GetRectangle (i));
-
-                       ctx.ClipPreserve ();
-                       ctx.Operator = Operator.Clear;
-                       ctx.Fill ();
-                       ctx.Operator = Operator.Over;
-               }
-               public IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
-               {
-                       this.clipping = clipping;
-                       IContext ctx = existingContext;
-                       if (ctx == null) {
-                               disposeContextOnFlush = true;
-                               ctx = new Context (surf);
-                       } else
-                               disposeContextOnFlush = false;
-
-                       clear (ctx);
-
-                       return ctx;
-               }
-               public void FlushUIFrame(IContext ctx)
-               {
-                       //surf.Canvas.Flush ();
-                       surf.Flush();
-
-                       if (disposeContextOnFlush)
-                               ctx.Dispose ();
-                       clipping = null;
-
-                       dev.WaitIdle();
-
-                       int idx = swapChain.GetNextImage ();
-                       if (idx < 0) {
-                               createMainSurface (swapChain.Width, swapChain.Height);
-                               return;
-                       }
-
-                       drawFence.Wait ();
-                       drawFence.Reset ();
-
-                       graphicQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence);
-                       (graphicQueue as PresentQueue).Present (swapChain, drawComplete[idx]);
-
-                       dev.WaitIdle();
-               }
-               public void ResizeMainSurface (int width, int height) {
-                       //resize is done on swapchain image aquisition failure
-               }
-               void createMainSurface (uint width, uint height) {
-                       dev.WaitIdle();
-
-                       surf?.Dispose ();
-                       surf = new VkSurface (dev, graphicQueue, gr, (int)width, (int)height, samples);
-
-                       cmdPool.Reset();
-
-                       vke.Image blitSource = surf.Img;
-
-                       for (int i = 0; i < swapChain.ImageCount; i++) {
-                               vke.Image blitDest = swapChain.images[i];
-                               vke.PrimaryCommandBuffer cmd = cmds[i];
-                               cmd.Start();
-
-                               blitDest.SetLayout (cmd, VkImageAspectFlags.Color,
-                                       VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal,
-                                       VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.Transfer);
-
-                               blitSource.SetLayout (cmd, VkImageAspectFlags.Color,
-                                       VkImageLayout.ColorAttachmentOptimal, VkImageLayout.TransferSrcOptimal,
-                                       VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.Transfer);
-
-                               blitSource.BlitTo (cmd, blitDest, VkFilter.Nearest);
-
-                               blitDest.SetLayout (cmd, VkImageAspectFlags.Color,
-                                       VkImageLayout.TransferDstOptimal, VkImageLayout.PresentSrcKHR,
-                                       VkPipelineStageFlags.Transfer, VkPipelineStageFlags.BottomOfPipe);
-
-                               blitSource.SetLayout (cmd, VkImageAspectFlags.Color,
-                                       VkImageLayout.TransferSrcOptimal, VkImageLayout.ColorAttachmentOptimal,
-                                       VkPipelineStageFlags.Transfer, VkPipelineStageFlags.ColorAttachmentOutput);
-
-                               cmd.End ();
-                       }
-                       dev.WaitIdle ();
-               }
-               #region IDisposable implementation
-               bool isDisposed;
-               public void Dispose ()
-               {
-                       Dispose (true);
-                       GC.SuppressFinalize (this);
-               }
-
-               protected virtual void Dispose (bool disposing)
-               {
-                       if (!isDisposed && disposing) {
-                               dev.WaitIdle ();
-
-                               surf.Dispose ();
-                               gr.Dispose ();
-
-                               for (int i = 0; i < swapChain.ImageCount; i++) {
-                                       dev.DestroySemaphore (drawComplete[i]);
-                                       cmds[i].Free ();
-                               }
-                               drawFence.Dispose ();
-                               swapChain.Dispose ();
-                               cmdPool.Dispose ();
-
-                               vkDestroySurfaceKHR (instance.Handle, hSurf, IntPtr.Zero);
-
-                               dev.Dispose ();
-                               instance.Dispose ();
-                       }
-                       isDisposed = true;
-               }
-               #endregion
-       }
-}
\ No newline at end of file
index ac7ff1db13766a60ceeab38897792384f730718d..5741d064484a97d92c241e9987d09d45fde98ddf 100644 (file)
@@ -16,20 +16,19 @@ using Device = vke.Device;
 
 namespace Crow.Backends
 {
-       public class DefaultBackend : IBackend
+       public class DefaultBackend : CrowBackend
        {
                protected Instance instance;
                protected PhysicalDevice phy;
                protected vke.Device dev;
                protected Queue graphicQueue;   //for vkvg, we must have at least a graphic queue
-               protected IntPtr hWin;                  //GLFW window native pointer.
                protected VkSurfaceKHR hSurf;   //Vulkan Surface
                protected SwapChain swapChain;
                protected CommandPool cmdPool;
                protected PrimaryCommandBuffer[] cmds;
                protected VkSemaphore[] drawComplete;
                protected Fence drawFence;
-               VkvgBackend.Surface surf;
+               Crow.VkvgBackend.Surface surf;
                Crow.VkvgBackend.Device vkvgDev;
                SampleCount samples = SampleCount.Sample_1;
                bool vsync = false;
@@ -39,8 +38,10 @@ namespace Crow.Backends
                        return phy != null;
                }
                public DefaultBackend (int width, int height)
+               : base (width, height, IntPtr.Zero)
                {
 #if DEBUG
+                       //Instance.RENDER_DOC_CAPTURE = true;
                        instance = new Instance (Ext.I.VK_EXT_debug_utils);
 #else
                        instance = new Instance ();
@@ -61,9 +62,10 @@ namespace Crow.Backends
                        vkvgDev = new Crow.VkvgBackend.Device (
                                instance.Handle, phy.Handle, dev.VkDev.Handle, graphicQueue.qFamIndex, samples);
 
-                       surf = new VkvgBackend.Surface (vkvgDev, (int)width, (int)height);
+                       surf = new Crow.VkvgBackend.Surface (vkvgDev, (int)width, (int)height);
                }
-               public DefaultBackend (ref IntPtr nativeWindoPointer, out bool ownGlfwWinHandle, int width, int height)
+               public DefaultBackend (int width, int height, IntPtr nativeWindoPointer)
+               : base (width, height, nativeWindoPointer)
                {
                        if (nativeWindoPointer == IntPtr.Zero) {
                                Glfw3.Init ();
@@ -75,11 +77,6 @@ namespace Crow.Backends
                                if (hWin == IntPtr.Zero)
                                        throw new Exception ("[GLFW3] Unable to create Window");
 
-                               nativeWindoPointer = hWin;
-                               ownGlfwWinHandle = true;
-                       } else {
-                               hWin = nativeWindoPointer;
-                               ownGlfwWinHandle = false;
                        }
 
                        SwapChain.IMAGES_USAGE = VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst;
@@ -87,6 +84,7 @@ namespace Crow.Backends
 
                        List<string> instExts = new List<string> (Glfw3.GetRequiredInstanceExtensions ());
 #if DEBUG
+                       //Instance.RENDER_DOC_CAPTURE = true;
                        instExts.Add (Ext.I.VK_EXT_debug_utils);
 #endif
                        instance = new Instance (instExts.ToArray());
@@ -136,25 +134,25 @@ namespace Crow.Backends
                {
                        Dispose (false);
                }
-               public virtual ISurface CreateSurface(int width, int height)
+               public override ISurface CreateSurface(int width, int height)
                        => new Crow.VkvgBackend.Surface (vkvgDev, width, height);
-               public virtual ISurface CreateSurface(byte[] data, int width, int height)
+               public override ISurface CreateSurface(byte[] data, int width, int height)
                        => new Crow.VkvgBackend.Surface (vkvgDev, data, width, height);
-               public ISurface MainSurface => surf;
-               public IRegion CreateRegion () => new Crow.VkvgBackend.Region ();
-               public IContext CreateContext (ISurface surf)
+               public override ISurface MainSurface => surf;
+               public override IRegion CreateRegion () => new Crow.VkvgBackend.Region ();
+               public override IContext CreateContext (ISurface surf)
                {
-                       Crow.VkvgBackend.Context gr = new VkvgBackend.Context (surf as VkvgBackend.Surface);
+                       Crow.VkvgBackend.Context gr = new Crow.VkvgBackend.Context (surf as Crow.VkvgBackend.Surface);
                        return gr;
                }
                //IPattern CreatePattern (PatternType patternType);
-               public IGradient CreateGradient (GradientType gradientType, Rectangle bounds)
+               public override IGradient CreateGradient (GradientType gradientType, Rectangle bounds)
                {
                        switch (gradientType) {
                        case GradientType.Vertical:
-                               return new Crow.VkvgBackend.LinearGradient (bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
+                               return new Crow.VkvgBackend.LinearGradient (0, bounds.Top, 0, bounds.Bottom);
                        case GradientType.Horizontal:
-                               return new Crow.VkvgBackend.LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Top);
+                               return new Crow.VkvgBackend.LinearGradient (bounds.Left, 0, bounds.Right, 0);
                        case GradientType.Oblic:
                                return new Crow.VkvgBackend.LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
                        case GradientType.Radial:
@@ -162,7 +160,7 @@ namespace Crow.Backends
                        }
                        return null;
                }
-               public byte[] LoadBitmap (Stream stream, out Size dimensions)
+               public override byte[] LoadBitmap (Stream stream, out Size dimensions)
                {
                        byte[] image;
 #if STB_SHARP
@@ -180,13 +178,13 @@ namespace Crow.Backends
 #endif
                        return image;
                }
-               public ISvgHandle LoadSvg(Stream stream)
+               public override ISvgHandle LoadSvg(Stream stream)
                {
                        using (BinaryReader sr = new BinaryReader (stream))
-                               return new VkvgBackend.SvgHandle(vkvgDev, sr.ReadBytes ((int)stream.Length));
+                               return new Crow.VkvgBackend.SvgHandle(vkvgDev, sr.ReadBytes ((int)stream.Length));
                }
-               public ISvgHandle LoadSvg(string svgFragment) =>
-                       new VkvgBackend.SvgHandle (vkvgDev,System.Text.Encoding.Unicode.GetBytes (svgFragment));
+               public override ISvgHandle LoadSvg(string svgFragment) =>
+                       new Crow.VkvgBackend.SvgHandle (vkvgDev, System.Text.Encoding.Unicode.GetBytes (svgFragment));
                bool disposeContextOnFlush;
                IRegion clipping;
                protected void clear(IContext ctx) {
@@ -198,13 +196,13 @@ namespace Crow.Backends
                        ctx.Fill ();
                        ctx.Operator = Operator.Over;
                }
-               public IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
+               public override IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
                {
                        this.clipping = clipping;
                        IContext ctx = existingContext;
                        if (ctx == null) {
                                disposeContextOnFlush = true;
-                               ctx = new VkvgBackend.Context (surf);
+                               ctx = new Crow.VkvgBackend.Context (surf);
                        } else
                                disposeContextOnFlush = false;
 
@@ -212,7 +210,7 @@ namespace Crow.Backends
 
                        return ctx;
                }
-               public void FlushUIFrame(IContext ctx)
+               public override void FlushUIFrame(IContext ctx)
                {
                        if (disposeContextOnFlush)
                                ctx.Dispose ();
@@ -234,7 +232,7 @@ namespace Crow.Backends
 
                        dev.WaitIdle();
                }
-               public void ResizeMainSurface (int width, int height) {
+               public override void ResizeMainSurface (int width, int height) {
                        //resize is done on swapchain image aquisition failure
                }
                vke.Image blitSource;
@@ -243,7 +241,7 @@ namespace Crow.Backends
 
                        blitSource?.Dispose ();
                        surf?.Dispose ();
-                       surf = new VkvgBackend.Surface (vkvgDev, (int)width, (int)height);
+                       surf = new Crow.VkvgBackend.Surface (vkvgDev, (int)width, (int)height);
 
                        cmdPool.Reset();
 
@@ -281,8 +279,7 @@ namespace Crow.Backends
                        dev.WaitIdle ();
                }
                #region IDispose implementation
-               bool isDisposed;
-               public void Dispose ()
+               public override void Dispose ()
                {
                        Dispose (true);
                        GC.SuppressFinalize (this);
index 82cad101f7f4c0d4442274a1f74815ea15a78050..24d52c73da65336c85259ae624ad17a2188a9b7f 100644 (file)
@@ -16,7 +16,7 @@ namespace Crow.VkvgBackend
                #region CTORS & DTOR
                public Device (IntPtr instance, IntPtr phy, IntPtr dev, uint qFamIdx, SampleCount samples = SampleCount.Sample_1, uint qIndex = 0)
                {
-                       handle = NativeMethods.vkvg_device_create_multisample (instance, phy, dev, qFamIdx, qIndex, samples, false);
+                       handle = NativeMethods.vkvg_device_create_from_vk_multisample (instance, phy, dev, qFamIdx, qIndex, samples, false);
                }
                ~Device ()
                {
index fcaf46203bc28faccdb47725eccd07489c49f682..7b434b5d1cdc27ac721562cef443a91d4cd397d2 100644 (file)
@@ -14,11 +14,13 @@ namespace Crow.VkvgBackend
 
                #region Device
                [DllImport(libvkvg, CallingConvention = CallingConvention.Cdecl)]
-               internal static extern IntPtr vkvg_device_create(IntPtr instance, IntPtr phy, IntPtr dev, uint qFamIdx, uint qIndex);
+               internal static extern IntPtr vkvg_device_create(SampleCount samples, bool deferredResolve);
                [DllImport(libvkvg, CallingConvention = CallingConvention.Cdecl)]
-               internal static extern IntPtr vkvg_device_destroy(IntPtr device);
+               internal static extern IntPtr vkvg_device_create_from_vk(IntPtr instance, IntPtr phy, IntPtr dev, uint qFamIdx, uint qIndex);
+               [DllImport(libvkvg, CallingConvention = CallingConvention.Cdecl)]
+               internal static extern IntPtr vkvg_device_create_from_vk_multisample(IntPtr inst, IntPtr phy, IntPtr vkdev, uint qFamIdx, uint qIndex, SampleCount samples, bool deferredResolve);
                [DllImport(libvkvg, CallingConvention = CallingConvention.Cdecl)]
-               internal static extern IntPtr vkvg_device_create_multisample(IntPtr inst, IntPtr phy, IntPtr vkdev, uint qFamIdx, uint qIndex, SampleCount samples, bool deferredResolve);
+               internal static extern IntPtr vkvg_device_destroy(IntPtr device);
                [DllImport(libvkvg, CallingConvention = CallingConvention.Cdecl)]
                internal static extern IntPtr vkvg_device_reference(IntPtr dev);
                [DllImport(libvkvg, CallingConvention = CallingConvention.Cdecl)]
index 934483f5bc988ab509865a0454c09d1aeb6cf997..0a6f3007d8b0a96f19b4186f8fa547de4376a0f7 100644 (file)
@@ -26,10 +26,10 @@ namespace Crow.VkvgBackend
                }
                #endregion
 
-               public void Render(IContext cr) =>
-                       NativeMethods.vkvg_render_svg((cr as Context).handle, handle, null);
-               public void Render (IContext cr, string id) =>
-                       NativeMethods.vkvg_render_svg((cr as Context).handle, handle, id);
+               public void Render(IContext cr) {}
+                       //NativeMethods.vkvg_render_svg((cr as Context).handle, handle, null);
+               public void Render (IContext cr, string id) {}
+                       //NativeMethods.vkvg_render_svg((cr as Context).handle, handle, id);
                public Size Dimensions {
                        get {
                                NativeMethods.nsvg_get_size (handle, out int w, out int h);
index 610faa7166d8d26b04d08134dbf8daaa8ba15dca..2f2134e86012492db780b6679d2c7da153ce2575 100644 (file)
@@ -145,10 +145,10 @@ namespace Crow.Drawing {
                        this.hWin = hWin;
 
                        SwapChain.IMAGES_USAGE = VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst;
-                       SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Unorm;
+                       SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb;
 
                        //Instance.VALIDATION = true;
-                       //Instance.RENDER_DOC_CAPTURE = true;
+                       Instance.RENDER_DOC_CAPTURE = true;
                        List<string> instExts = new List<string> (Glfw3.GetRequiredInstanceExtensions ());
 #if DEBUG
                        instExts.Add (Ext.I.VK_EXT_debug_utils);
@@ -209,7 +209,7 @@ namespace Crow.Drawing {
                        //Console.WriteLine ($"build blit w:{width} h:{height}");
                        cmdPool.Reset();
 
-                       blitSource = new vke.Image (dev, new VkImage((ulong)surf.VkImage.ToInt64()), Vulkan.VkFormat.B8g8r8a8Unorm,
+                       blitSource = new vke.Image (dev, new VkImage((ulong)surf.VkImage.ToInt64()), Vulkan.VkFormat.B8g8r8a8Srgb,
                                Vulkan.VkImageUsageFlags.TransferSrc | Vulkan.VkImageUsageFlags.TransferDst | Vulkan.VkImageUsageFlags.ColorAttachment,
                                width, height);
 
index 707e5642e8e3a855bed859e1f262455693068217..9a4b1b00f1c10d0cdf6bd82b29e4b27e5d4a94f6 100644 (file)
                <Compile Remove="src\Widgets\ColorPicker2.cs" />
        </ItemGroup>
 
-       <ItemGroup>
-         <ProjectReference Include="..\Drawing2D\Drawing2D.csproj" />
-         <!--<ProjectReference Include="..\Backends\SkiaBackend\SkiaBackend.csproj" />-->
-         <ProjectReference Include="..\Backends\CairoBackend\CairoBackend.csproj" />
-         <!--<ProjectReference Include="..\Backends\VkvgBackend\VkvgBackend.csproj" />-->
-       </ItemGroup>
-
        <PropertyGroup Condition=" '$(CrowStbSharp)' == 'true'">
                <DefineConstants>$(DefineConstants);STB_SHARP</DefineConstants>
        </PropertyGroup>
-
+       <ItemGroup>
+               <ProjectReference Include="..\Drawing2D\Drawing2D.csproj" />
+       </ItemGroup>
 </Project>
index 74d0ed943b418f56ffc8bd85a82ff395c58cb8dc..ac0e20ba064bb5f7c9d70958a2cfcf025cf54781 100644 (file)
@@ -153,12 +153,69 @@ namespace Crow
                        }
                        return IntPtr.Zero;
                }
+               static string[] backends = {"CairoBackend", "VkvgBackend", "SkiaBackend"};
+               static Assembly resolving (System.Runtime.Loader.AssemblyLoadContext ctx, AssemblyName name) {
+                       if (name.Name == "CrowBackend") {
+                               string bp = Path.GetDirectoryName (Assembly.GetExecutingAssembly().Location);
+                               foreach (string b in backends) {
+                                       string bPath = Path.Combine (bp, b + ".dll");
+                                       if (File.Exists (bPath))
+                                               return ctx.LoadFromAssemblyPath (bPath);
+                               }
+                       }
+                       return ctx.LoadFromAssemblyName (name);
+               }
+               public static BackendType PreferedBackendType = BackendType.Default;
+               /// <summary>
+               /// If not null, backends assemblies will be search in this directory, else
+               /// backends are search where the main crow assembly is.
+               /// </summary>
+               public static string BackendsDirectory = null;
+               protected static bool tryFindBackendType (out Type backendType) {
+                       backendType = default;
+                       System.Runtime.Loader.AssemblyLoadContext ldCtx = System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly());
+                       foreach (Assembly a in ldCtx.Assemblies.Where (asb => backends.Contains (asb.GetName ().Name))) {
+                               IEnumerable<Type> backendTypes = a.ExportedTypes?.Where (e=>e.IsSubclassOf(typeof(CrowBackend)) && !e.IsAbstract);
+                               if (backendTypes != null) {
+                                       backendType = backendTypes.FirstOrDefault();
+                                       return true;
+                               }
+                       }
+                       string bp =
+                               (!string.IsNullOrEmpty(BackendsDirectory) && Directory.Exists(BackendsDirectory)) ?
+                                       BackendsDirectory :     Path.GetDirectoryName (Assembly.GetExecutingAssembly().Location);
+                       foreach (string b in backends) {
+                               string bPath = Path.Combine (bp, b + ".dll");
+                               if (File.Exists (bPath)) {
+                                       Assembly a = ldCtx.LoadFromAssemblyPath (bPath);
+                                       IEnumerable<Type> backendTypes = a.ExportedTypes?.Where (e=>e.IsSubclassOf(typeof(CrowBackend)) && !e.IsAbstract);
+                                       if (backendTypes != null) {
+                                               if (PreferedBackendType == BackendType.Default)
+                                                       backendType = backendTypes.FirstOrDefault(be => be.Name == "DefaultBackend");
+                                               else if (PreferedBackendType == BackendType.Egl)
+                                                       backendType = backendTypes.FirstOrDefault(be => be.Name == "EglBackend");
+                                               else if (PreferedBackendType == BackendType.Vulkan)
+                                                       backendType = backendTypes.FirstOrDefault(be => be.Name == "VulkanBackend");
+                                               else if (PreferedBackendType == BackendType.Gl)
+                                                       backendType = backendTypes.FirstOrDefault(be => be.Name == "GlBackend");
+
+                                               if (backendType == null)
+                                                       backendType = backendTypes.FirstOrDefault();
+                                               return backendType != null;
+                                       }
+                               }
+                       }
+
+                       return false;
+               }
 
 
                #region CTOR
                static Interface ()
                {
-                       System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).ResolvingUnmanagedDll += resolveUnmanaged;
+                       System.Runtime.Loader.AssemblyLoadContext ldCtx = System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly());
+                       ldCtx.ResolvingUnmanagedDll += resolveUnmanaged;
+                       ldCtx.Resolving += resolving;
 
                        CROW_CONFIG_ROOT =
                                System.IO.Path.Combine (
@@ -302,7 +359,7 @@ namespace Crow
                /// True if GLFW window has been created by the backend and should be disposed with the `Interface`, false otherwise.
                /// </summary>
                protected bool ownWindow;
-               protected IBackend backend;//backend device
+               protected CrowBackend backend;//backend device
                /// <summary>Clipping rectangles on the root context</summary>
                protected IRegion clipping;
                static string backendDeviceTypeString = "Crow.CairoBackend.Device";
@@ -316,7 +373,7 @@ namespace Crow
                /// Native GLFW window handle bound to this interface.
                /// </summary>
                public IntPtr WindowHandle => hWin;
-               public IBackend Backend => backend;
+               public CrowBackend Backend => backend;
                /// <summary>Main backend surface</summary>
                public ISurface MainSurface => backend.MainSurface;
                public IntPtr SurfacePointer {
@@ -394,7 +451,11 @@ namespace Crow
                }
 
                protected virtual void initBackend () {
-                       backend = new Crow.Backends.DefaultBackend (ref hWin, out ownWindow, clientRectangle.Width, clientRectangle.Height);
+                       if (!tryFindBackendType (out Type backendType))
+                               throw new Exception ("No backend found.");
+                       backend = (CrowBackend)Activator.CreateInstance (backendType, new object[] {clientRectangle.Width, clientRectangle.Height, hWin});
+                       hWin = backend.hWin;
+                       ownWindow = backend.ownGlfwWinHandle;
                        clipping = Backend.CreateRegion ();
                        registerGlfwCallbacks ();
                }
index bd40f7a54cea3674e3c1470a1f15cadca2cbf07d..f77f3b43e7162d3048ec1dcc6fed67c539c2ff55 100644 (file)
@@ -21,6 +21,7 @@
                <PackageCopyright>Copyright 2022</PackageCopyright>
                <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
                <GenerateDocumentationFile>true</GenerateDocumentationFile>
+               <NoWarn>$(NoWarn);1591</NoWarn>
        </PropertyGroup>
 
        <ItemGroup>
diff --git a/Drawing2D/src/CrowBackend.cs b/Drawing2D/src/CrowBackend.cs
new file mode 100644 (file)
index 0000000..876632f
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright (c) 2018-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.IO;
+
+namespace Drawing2D
+{
+       public abstract class CrowBackend: IDisposable
+       {
+               /// <summary>
+               /// GLFW Native window pointer
+               /// </summary>
+               public IntPtr hWin { get; protected set; }
+               public bool ownGlfwWinHandle { get; private set; }
+               public CrowBackend (int width, int height, IntPtr nativeWindow = default) {
+                       ownGlfwWinHandle = (nativeWindow == IntPtr.Zero);
+                       hWin = nativeWindow;
+               }
+               /// <summary>
+               /// Main rendering surface, usualy an accelerated window surface
+               /// </summary>
+               public abstract ISurface MainSurface { get; }
+               /// <summary>
+               /// Create a new surface
+               /// </summary>
+               /// <param name="width">width of the new surface</param>
+               /// <param name="height">height of the new surface</param>
+               /// <returns>the new surface instance</returns>
+               public abstract ISurface CreateSurface (int width, int height);
+               /// <summary>
+               /// Create a new surface backed by the byte array provided as argument
+               /// </summary>
+               /// <param name="data">a byte array to hold the pixels of the new surface</param>
+               /// <param name="width">width of the new surface</param>
+               /// <param name="height">height of the new surface</param>
+               /// <returns>the new surface instance</returns>
+               public abstract ISurface CreateSurface (byte[] data, int width, int height);
+               //ISurface CreateMainSurface (IntPtr glfwWinHandle, int width, int height);
+               public abstract IRegion CreateRegion ();
+               public abstract IContext CreateContext (ISurface surf);
+               //IPattern CreatePattern (PatternType patternType);
+               public abstract IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
+               public abstract byte[] LoadBitmap (Stream stream, out Size dimensions);
+               public abstract ISvgHandle LoadSvg (Stream stream);
+               public abstract ISvgHandle LoadSvg (string svgFragment);
+               public abstract IContext PrepareUIFrame (IContext existingContext, IRegion clipping);
+               public abstract void FlushUIFrame (IContext ctx);
+               public abstract void ResizeMainSurface (int width, int height);
+
+               protected bool isDisposed;
+               public abstract void Dispose();
+               /*IRegion CreateRegion ();
+ISurface CreateSurface (int width, int height);
+ISurface CreateSurface (byte[] data, int width, int height);
+ISurface CreateSurface (IntPtr glfwWinHandle, int width, int height);
+IContext CreateContext (ISurface surf);
+//IPattern CreatePattern (PatternType patternType);
+IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
+byte[] LoadBitmap (Stream stream, out Size dimensions);
+ISvgHandle LoadSvg (Stream stream);
+ISvgHandle LoadSvg (string svgFragment);*/
+       }
+}
+
index bf20a432b19ca6853df3b7652cae896efe8279cf..b75cc696006df172dc719d17eeb7863e88f9ab7f 100644 (file)
@@ -7,9 +7,9 @@ using System;
 namespace Drawing2D
 {
        public enum BackendType {
-               Native,
-               OpenGL,
-               EGL,
+               Default,
+               Gl,
+               Egl,
                Vulkan
        }
        public enum Status
diff --git a/Drawing2D/src/IBackend.cs b/Drawing2D/src/IBackend.cs
deleted file mode 100644 (file)
index ac52716..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2018-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.IO;
-
-namespace Drawing2D
-{
-       public interface IBackend: IDisposable
-       {
-               ISurface CreateSurface (int width, int height);
-               ISurface CreateSurface (byte[] data, int width, int height);
-               //ISurface CreateMainSurface (IntPtr glfwWinHandle, int width, int height);
-               ISurface MainSurface { get; }
-               IRegion CreateRegion ();
-               IContext CreateContext (ISurface surf);
-               //IPattern CreatePattern (PatternType patternType);
-               IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
-               byte[] LoadBitmap (Stream stream, out Size dimensions);
-               ISvgHandle LoadSvg (Stream stream);
-               ISvgHandle LoadSvg (string svgFragment);
-               IContext PrepareUIFrame (IContext existingContext, IRegion clipping);
-               void FlushUIFrame (IContext ctx);
-               void ResizeMainSurface (int width, int height);
-               /*IRegion CreateRegion ();
-               ISurface CreateSurface (int width, int height);
-               ISurface CreateSurface (byte[] data, int width, int height);
-               ISurface CreateSurface (IntPtr glfwWinHandle, int width, int height);
-               IContext CreateContext (ISurface surf);
-               //IPattern CreatePattern (PatternType patternType);
-               IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
-               byte[] LoadBitmap (Stream stream, out Size dimensions);
-               ISvgHandle LoadSvg (Stream stream);
-               ISvgHandle LoadSvg (string svgFragment);*/
-       }
-}
-
index 1fa6dd1617c32c784638d34d7c597d22921fb59b..da64b9b823e5c78929563a30947dfb3563fb253d 100644 (file)
        <ItemGroup>
                <ProjectReference Include="$(SolutionDir)Crow\Crow.csproj" />
        </ItemGroup>
+       <ItemGroup>
+         <ProjectReference Include="..\Drawing2D\Drawing2D.csproj" />
+         <!--<ProjectReference Include="..\Backends\SkiaBackend\SkiaBackend.csproj" />-->
+         <ProjectReference Include="..\Backends\CairoBackend\CairoBackend.csproj" />
+         <!--<ProjectReference Include="..\Backends\VkvgBackend\VkvgBackend.csproj" />-->
+       </ItemGroup>
        <ItemGroup>
                <None Include="$(SamplesDir)common\ui\Interfaces\**\*.*">
                        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
index b1c6d950a36c249a414aedad551c16028d6a85d1..ece49f6ba18943c31399e16015722385063581a1 100644 (file)
@@ -48,8 +48,8 @@ namespace PerfTests
                        Console.WriteLine ("Usage: PerfTests.exe [options]\n");
                        Console.WriteLine ("-o,--output:\n\tWrite results to output directory, if omited, results are printed to screen.");
                        Console.WriteLine ("-i,--input:\n\tInput directory to search recursively for '.crow' file to test. If ommitted, builtin unit tests are performs");
-                       Console.WriteLine ("-w,--width:\n\toutput surface width, not displayed on screen.");
-                       Console.WriteLine ("-h,--height:\n\toutput surface height, not displayed on screen.");
+                       Console.WriteLine ("-x,--width:\n\toutput surface width, not displayed on screen.");
+                       Console.WriteLine ("-y,--height:\n\toutput surface height, not displayed on screen.");
                        Console.WriteLine ("-c,--count:\n\trepeat each test 'c' times. (default = 10, minimum = 5");
 
                        Console.WriteLine ("-b,--begin:\n\tStarting stage for measures, may be the stage name or stage index");
@@ -60,7 +60,7 @@ namespace PerfTests
                        Console.WriteLine ("-r,--reset:\n\tenable clear iterators after each test file.");
                        Console.WriteLine ("-u,--update:\n\tmeasure 'n' update cycle with elapsed ticks string notified. (default = 0)");
                        Console.WriteLine ("-s,--screen:\n\tenable output to screen.");
-                       Console.WriteLine ("--help:\n\tthis help message.");
+                       Console.WriteLine ("-h,--help:\n\tthis help message.");
                }
 
                public TestInterface (string[] args, int width = 800, int height = 600)
@@ -84,11 +84,11 @@ namespace PerfTests
                                        case "--count":
                                                count = Math.Max(5, int.Parse (args[i++]));
                                                break;
-                                       case "-w":
+                                       case "-x":
                                        case "--width":
                                                clientRectangle.Width = int.Parse (args[i++]);
                                                break;
-                                       case "-h":
+                                       case "-y":
                                        case "--height":
                                                clientRectangle.Height = int.Parse (args[i++]);
                                                break;
@@ -110,6 +110,7 @@ namespace PerfTests
                                        case "--screen":
                                                screenOutput = true;
                                                break;
+                                       case "-h":
                                        case "--help":
                                        default:
                                                throw new Exception ("none");
@@ -157,11 +158,15 @@ namespace PerfTests
         }
                protected override void initBackend()
                {
+                       if (!tryFindBackendType (out Type backendType))
+                               throw new Exception ("No backend found.");
                        if (screenOutput)
-                               backend = new Crow.Backends.DefaultBackend (ref hWin, out ownWindow, clientRectangle.Width, clientRectangle.Height);
+                               backend = (Drawing2D.CrowBackend)Activator.CreateInstance (backendType, new object[] {clientRectangle.Width, clientRectangle.Height, hWin});
                        else
-                               backend = new Crow.Backends.DefaultBackend (clientRectangle.Width, clientRectangle.Height);
+                               backend = (Drawing2D.CrowBackend)Activator.CreateInstance (backendType, new object[] {clientRectangle.Width, clientRectangle.Height});
 
+                       hWin = backend.hWin;
+                       ownWindow = backend.ownGlfwWinHandle;
                        clipping = Backend.CreateRegion ();
                }