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;
{
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;
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 null;
}
- public byte[] LoadBitmap (Stream stream, out Size dimensions)
+ public override byte[] LoadBitmap (Stream stream, out Size dimensions)
{
byte[] image;
#if STB_SHARP
#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));
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;
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);
+++ /dev/null
-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) {
-
- }
- }
-}
-
/// </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);
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);
/// </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);
}
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);
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);
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;
/// </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);
}
--- /dev/null
+<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>
// 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
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>
/// </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);
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();
}
+++ /dev/null
-// 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
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;
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 ();
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 ();
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;
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());
{
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:
}
return null;
}
- public byte[] LoadBitmap (Stream stream, out Size dimensions)
+ public override byte[] LoadBitmap (Stream stream, out Size dimensions)
{
byte[] image;
#if STB_SHARP
#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) {
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;
return ctx;
}
- public void FlushUIFrame(IContext ctx)
+ public override void FlushUIFrame(IContext ctx)
{
if (disposeContextOnFlush)
ctx.Dispose ();
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;
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();
dev.WaitIdle ();
}
#region IDispose implementation
- bool isDisposed;
- public void Dispose ()
+ public override void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
#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 ()
{
#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)]
}
#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);
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);
//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);
<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>
}
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 (
/// 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";
/// 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 {
}
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 ();
}
<PackageCopyright>Copyright 2022</PackageCopyright>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
+ <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
<ItemGroup>
--- /dev/null
+// 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);*/
+ }
+}
+
namespace Drawing2D
{
public enum BackendType {
- Native,
- OpenGL,
- EGL,
+ Default,
+ Gl,
+ Egl,
Vulkan
}
public enum Status
+++ /dev/null
-// 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);*/
- }
-}
-
<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>
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");
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)
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;
case "--screen":
screenOutput = true;
break;
+ case "-h":
case "--help":
default:
throw new Exception ("none");
}
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 ();
}