From: Jean-Philippe Bruyère Date: Thu, 12 Aug 2021 14:22:34 +0000 (+0200) Subject: it's now possible to run vkvgBackend in DebugLogView on cairo X-Git-Tag: v0.9.5-beta~2 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=950104a8d304ebc9e4499186bc4cac8e6721b6ff;p=jp%2Fcrow.git it's now possible to run vkvgBackend in DebugLogView on cairo --- diff --git a/Crow/src/GraphicBackends/vkvg/Surface.cs b/Crow/src/GraphicBackends/vkvg/Surface.cs index 6d7321a5..dba19ca4 100644 --- a/Crow/src/GraphicBackends/vkvg/Surface.cs +++ b/Crow/src/GraphicBackends/vkvg/Surface.cs @@ -65,6 +65,9 @@ namespace Crow.Drawing public void WriteToPng (string path) { NativeMethods.vkvg_surface_write_to_png (handle, path); } + public void WriteTo (IntPtr bitmap) { + NativeMethods.vkvg_surface_write_to_memory (handle, bitmap); + } public void Clear () { NativeMethods.vkvg_surface_clear (handle); } diff --git a/Crow/src/GraphicBackends/vkvg/VulkanContext.cs b/Crow/src/GraphicBackends/vkvg/VulkanContext.cs index 6b1ce5e5..801458a2 100644 --- a/Crow/src/GraphicBackends/vkvg/VulkanContext.cs +++ b/Crow/src/GraphicBackends/vkvg/VulkanContext.cs @@ -16,34 +16,29 @@ namespace Crow.Drawing { /// /// Base class for offscreen vulkan context without swapchain /// - public class VulkanContextBase : IDisposable { + public abstract class VulkanContextBase : IDisposable { + protected Interface iface; + public uint width { get; protected set; } + public uint height { get; protected set; } + protected Instance instance; protected PhysicalDevice phy; protected vke.Device dev; protected Queue graphicQueue;//for vkvg, we must have at least a graphic queue + public Crow.Drawing.Device VkvgDevice { get; protected set; } public void WaitIdle() => dev.WaitIdle (); - public VulkanContextBase () {} - public VulkanContextBase (ref byte[] pBitmap) { -#if DEBUG - instance = new Instance (Ext.I.VK_EXT_debug_utils); -#else - instance = new Instance (); -#endif - phy = instance.GetAvailablePhysicalDevice ().FirstOrDefault (); - VkPhysicalDeviceFeatures enabledFeatures = default; - dev = new vke.Device (phy); - graphicQueue = new Queue (dev, VkQueueFlags.Graphics); - dev.Activate (enabledFeatures); - } + public VulkanContextBase (Interface iface) { + this.iface = iface; + } - public Crow.Drawing.Device CreateVkvgDevice () => + + protected void createVkvgDevice () => VkvgDevice = new Crow.Drawing.Device (instance.Handle, phy.Handle, dev.VkDev.Handle, graphicQueue.qFamIndex, SampleCount.Sample_8); - public virtual void CreateSurface (Device vkvgDevice, int width, int height, ref Surface surf) { - surf?.Dispose (); - surf = new Surface (vkvgDevice, width, height); - } + + public abstract void CreateSurface (int width, int height, ref Surface surf); + public abstract bool render (); #region IDisposable Support protected bool isDisposed; @@ -51,6 +46,8 @@ namespace Crow.Drawing { if (!isDisposed) { dev.WaitIdle (); + VkvgDevice.Dispose (); + if (disposing) { dev.Dispose (); instance.Dispose (); @@ -69,23 +66,63 @@ namespace Crow.Drawing { } #endregion } - /// - /// Base class to build vulkan application. - /// Provide default swapchain with its command pool and buffers per image and the main present queue - /// - public class VulkanContext : VulkanContextBase { - public override void CreateSurface (Device vkvgDevice, int width, int height, ref Surface surf) { - WaitIdle(); + //vulkan context rendering to preallocated bitmap + public class OffscreenVulkanContext : VulkanContextBase { + public IntPtr bitmap { get; private set; } + Surface surface; + /// + /// Preallocated Pointer to output bitmap + /// + /// + public OffscreenVulkanContext (Interface iface) : base (iface) { +#if DEBUG + instance = new Instance (Ext.I.VK_EXT_debug_utils); +#else + instance = new Instance (); +#endif + phy = instance.GetAvailablePhysicalDevice ().FirstOrDefault (); + VkPhysicalDeviceFeatures enabledFeatures = default; + dev = new vke.Device (phy); + graphicQueue = new Queue (dev, VkQueueFlags.Graphics); + dev.Activate (enabledFeatures); - blitSource?.Dispose (); + createVkvgDevice (); + } + public override void CreateSurface (int width, int height, ref Surface surf) { surf?.Dispose (); - surf = new Surface (vkvgDevice, width, height); - buildBlitCommand (surf); + surface = new Surface (VkvgDevice, width, height); + surf = surface; - WaitIdle(); + this.width = (uint)width; + this.height = (uint)height; + + if (bitmap != IntPtr.Zero) + Marshal.FreeHGlobal (bitmap); + bitmap = Marshal.AllocHGlobal (height * width * 4); + Console.WriteLine($"vkCtx.CreateOffscreenSurface: w:{width} h:{height}"); } + public override bool render () { + surface.WriteTo (bitmap); + Console.WriteLine($"vkCtx.Render(WriteTo): w:{width} h:{height}"); + return true; + } + protected override void Dispose (bool disposing) { + if (!isDisposed) { + dev.WaitIdle (); + + surface?.Dispose (); + if (bitmap != IntPtr.Zero) + Marshal.FreeHGlobal (bitmap); - uint width, height; + base.Dispose (disposing); + } + } + } + /// + /// Base class to build vulkan application. + /// Provide default swapchain with its command pool and buffers per image and the main present queue + /// + public class VulkanContext : VulkanContextBase { IntPtr hWin;/** GLFW window native pointer. */ /**Vulkan Surface */ protected VkSurfaceKHR hSurf; @@ -104,7 +141,7 @@ namespace Crow.Drawing { uint frameCount; Stopwatch frameChrono; - public VulkanContext (IntPtr hWin, uint _width, uint _height, bool vsync = false) { + public VulkanContext (Interface iface, IntPtr hWin, uint _width, uint _height, bool vsync = false) : base (iface) { this.hWin = hWin; SwapChain.IMAGES_USAGE = VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst; @@ -150,9 +187,21 @@ namespace Crow.Drawing { drawComplete[i].SetDebugMarkerName (dev, "Semaphore DrawComplete" + i); } - cmdPool.SetName ("main CmdPool"); + cmdPool.SetName ("main CmdPool"); + + createVkvgDevice (); } + public override void CreateSurface (int width, int height, ref Surface surf) { + WaitIdle(); + + blitSource?.Dispose (); + surf?.Dispose (); + surf = new Surface (VkvgDevice, width, height); + buildBlitCommand (surf); + + WaitIdle(); + } internal vke.Image blitSource; @@ -190,15 +239,11 @@ namespace Crow.Drawing { cmd.End (); } } - public void WaitAndResetDrawFence () { - drawFence.Wait (); - drawFence.Reset (); - } /// /// Main render method called each frame. get next swapchain image, process resize if needed, submit and present to the presentQueue. /// Wait QueueIdle after presenting. /// - public bool render () { + public override bool render () { WaitIdle(); int idx = swapChain.GetNextImage (); @@ -211,12 +256,15 @@ namespace Crow.Drawing { if (cmds[idx] == null) return false; - WaitAndResetDrawFence(); + + drawFence.Wait (); + drawFence.Reset (); graphicQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence); (graphicQueue as PresentQueue).Present (swapChain, drawComplete[idx]); WaitIdle(); + iface.IsDirty = false; return true; } protected override void Dispose (bool disposing) { diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs index 21191f08..8725a27b 100644 --- a/Crow/src/Interface.cs +++ b/Crow/src/Interface.cs @@ -187,13 +187,27 @@ namespace Crow Glfw3.SetCursorPosCallback (hWin, HandleCursorPosDelegate); Glfw3.SetScrollCallback (hWin, HandleScrollDelegate); Glfw3.SetCharCallback (hWin, HandleCharDelegate); +#if !VKVG//resize is processed on context.Render failing Glfw3.SetWindowSizeCallback (hWin, HandleWindowSizeDelegate); +#endif Glfw3.SetWindowRefreshCallback (hWin, HandleWindowRefreshDelegate); } #if VKVG - VulkanContext vkCtx; - internal Device vkvgDevice; + protected VulkanContextBase vkCtx; + internal Device vkvgDevice => vkCtx.VkvgDevice; + + /// + /// Create the VulkanContext with swapchain support. Override it to use another vulkan backend. + /// #endif + protected void initBackend (bool offscreen = false) { +#if VKVG + if (offscreen) + vkCtx = new OffscreenVulkanContext (this); + else + vkCtx = new VulkanContext (this, hWin, (uint)clientRectangle.Width, (uint)clientRectangle.Height); +#endif + } protected void initSurface () { Glfw3.Init (); @@ -210,9 +224,8 @@ namespace Crow registerGlfwCallbacks (); #if VKVG - vkCtx = new VulkanContext (hWin, (uint)clientRectangle.Width, (uint)clientRectangle.Height); - vkvgDevice = vkCtx.CreateVkvgDevice (); - vkCtx.CreateSurface (vkvgDevice, clientRectangle.Width, clientRectangle.Height, ref surf); + initBackend (); + vkCtx.CreateSurface (clientRectangle.Width, clientRectangle.Height, ref surf); #else switch (Environment.OSVersion.Platform) { case PlatformID.MacOSX: @@ -237,7 +250,52 @@ namespace Crow } #endif } - + public void CreateMainSurface (ref Rectangle r) { + surf?.Dispose(); +#if (VKVG) + vkCtx.CreateSurface (clientRectangle.Width, clientRectangle.Height, ref surf); +#else + surf = new ImageSurface (Format.Argb32, r.Width, r.Height); +#endif + } + public Surface CreateSurface (ref Rectangle r) { +#if (VKVG) + return new Surface (vkvgDevice, r.Width, r.Height); +#else + return surf.CreateSimilar (Content.ColorAlpha, r.Width, r.Height); +#endif + } + public Surface CreateSurface (int width, int height) { +#if (VKVG) + return new Surface (vkvgDevice, width, height); +#else + return surf.CreateSimilar (Content.ColorAlpha, width, height); +#endif + } + public Surface CreateSurface (IntPtr existingSurfaceHandle) { +#if (VKVG) + return new Surface (vkvgDevice, existingSurfaceHandle); +#else + return Surface.Lookup (existingSurfaceHandle, false); +#endif + } + public Surface CreateSurfaceForData (IntPtr data, int width, int height) { +#if (VKVG) + throw new NotImplementedException (); +#else + return new ImageSurface (data, Format.Argb32, width, height, width * 4); +#endif + } + public IntPtr SurfacePointer { + get { + lock(UpdateMutex) +#if (VKVG) + return (vkCtx as OffscreenVulkanContext).bitmap; +#else + return surf.Handle; +#endif + } + } public void SetWindowIcon (string path) { using (Stream stream = GetStreamFromPath (path)) { #if STB_SHARP @@ -329,27 +387,7 @@ namespace Crow }; #endregion - public Surface CreateSurface (ref Rectangle r) { -#if (VKVG) - return new Surface (vkvgDevice, r.Width, r.Height); -#else - return surf.CreateSimilar (Content.ColorAlpha, r.Width, r.Height); -#endif - } - public Surface CreateSurface (int width, int height) { -#if (VKVG) - return new Surface (vkvgDevice, width, height); -#else - return surf.CreateSimilar (Content.ColorAlpha, width, height); -#endif - } - public Surface CreateSurface (IntPtr existingSurfaceHandle) { -#if (VKVG) - return new Surface (vkvgDevice, existingSurfaceHandle); -#else - return Surface.Lookup (existingSurfaceHandle, false); -#endif - } + public string WindowTitle { set => Glfw3.SetWindowTitle (hWin, value); } @@ -449,6 +487,9 @@ namespace Crow if (disposing) { // TODO: dispose managed state (managed objects). +#if VKVG + vkCtx.Dispose (); +#endif } currentCursor?.Dispose (); @@ -1080,11 +1121,8 @@ namespace Crow #if VKVG if (IsDirty) { - if (vkCtx.render ()) - IsDirty = false; - else { - resizeVulkanContext(); - } + if (!vkCtx.render ()) + ProcessResize (new Rectangle (0,0,(int)vkCtx.width, (int)vkCtx.height)); } #endif @@ -1100,13 +1138,9 @@ namespace Crow } #if VKVG void resizeVulkanContext () { + - vkCtx.CreateSurface (vkvgDevice, clientRectangle.Width, clientRectangle.Height, ref surf); - - foreach (Widget g in GraphicTree) - g.RegisterForLayouting (LayoutingType.All); - registerRefreshClientRectangle (); } #endif /// Layouting loop, this is the first step of the udpate and process registered @@ -1436,11 +1470,12 @@ namespace Crow /// when window resize event occurs. /// /// bounding box of the interface - public virtual void ProcessResize(Rectangle bounds){ + public virtual void ProcessResize(Rectangle bounds){ lock (UpdateMutex) { clientRectangle = bounds; #if VKVG + vkCtx.CreateSurface (clientRectangle.Width, clientRectangle.Height, ref surf); #else switch (Environment.OSVersion.Platform) { case PlatformID.MacOSX: @@ -1463,11 +1498,11 @@ namespace Crow case PlatformID.WinCE: throw new PlatformNotSupportedException ("Unable to create cairo surface."); } +#endif foreach (Widget g in GraphicTree) g.RegisterForLayouting (LayoutingType.All); registerRefreshClientRectangle (); -#endif } } diff --git a/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj b/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj index 54413ba6..8259275b 100644 --- a/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj +++ b/Samples/DebugLogAnalyzer/DebugLogAnalyzer.csproj @@ -11,8 +11,5 @@ Dbg.%(Filename)%(Extension) - - - \ No newline at end of file diff --git a/Samples/DebugLogAnalyzer/src/DebugInterface.cs b/Samples/DebugLogAnalyzer/src/DebugInterface.cs index 08927566..40656bfe 100644 --- a/Samples/DebugLogAnalyzer/src/DebugInterface.cs +++ b/Samples/DebugLogAnalyzer/src/DebugInterface.cs @@ -6,6 +6,7 @@ using System; using Crow.Drawing; using System.Threading; using Samples; +using System.Runtime.InteropServices; namespace Crow { @@ -18,7 +19,11 @@ namespace Crow public DebugInterface (IntPtr hWin) : base (hWin) { SolidBackground = false; - surf = CreateSurface (100, 100); + initBackend (true); + + clientRectangle = new Rectangle (0, 0, 100, 100); + CreateMainSurface (ref clientRectangle); + } public override void Run() @@ -30,14 +35,14 @@ namespace Crow }; t.Start (); } - public bool Terminate; + public bool ShutDown; string source; Action delRegisterForRepaint;//call RegisterForRepaint in the container widget (DebugInterfaceWidget) Action delSetCurrentException; Func delGetScreenCoordinate; void interfaceThread () { - while (!Terminate) { + while (!ShutDown) { try { Update(); @@ -70,20 +75,12 @@ namespace Crow Thread.Sleep(1000); } - if (IsDirty) { + if (IsDirty) delRegisterForRepaint(); - //Console.WriteLine ("[DbgIFace]RegisterForRepaint"); - } - + Thread.Sleep (UPDATE_INTERVAL); } } - public IntPtr SurfacePointer { - get { - lock(UpdateMutex) - return surf.Handle; - } - } public void RegisterDebugInterfaceCallback (object w){ Type t = w.GetType(); delRegisterForRepaint = (Action)Delegate.CreateDelegate(typeof(Action), w, t.GetMethod("RegisterForRepaint")); @@ -121,13 +118,18 @@ namespace Crow } } public void Resize (int width, int height) { - + if (!HaveVkvgBackend) + ProcessResize (new Rectangle(0,0,width, height)); + } + public override void ProcessResize(Rectangle bounds) { lock (UpdateMutex) { - clientRectangle = new Rectangle (0, 0, width, height); - surf?.Dispose(); - surf = CreateSurface (width, height); + clientRectangle = bounds.Size; + + CreateMainSurface (ref clientRectangle); + foreach (Widget g in GraphicTree) g.RegisterForLayouting (LayoutingType.All); + RegisterClip (clientRectangle); } } diff --git a/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs b/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs index 8da93de0..113e5e07 100644 --- a/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs +++ b/Samples/DebugLogAnalyzer/src/DebugInterfaceWidget.cs @@ -34,12 +34,12 @@ namespace Crow Action delResetDirtyState; Action delResetDebugger; Action delSaveDebugLog; - Func delGetSurfacePointer; + Func delGetSurfacePointer; Action delSetSource; FieldInfo fiDbg_IncludeEvents, fiDbg_DiscardEvents, fiDbg_ConsoleOutput; - bool initialized, recording; + bool initialized, recording, hasVkvgBackend; string crowDbgAssemblyLocation; DbgEvtType recordedEvents, discardedEvents; @@ -198,6 +198,11 @@ namespace Crow } crowLoadCtx = new AssemblyLoadContext("CrowDebuggerLoadContext"); + crowLoadCtx.Resolving += (context, assemblyName) => { + return crowLoadCtx.LoadFromAssemblyPath ( + System.IO.Path.Combine ( + System.IO.Path.GetDirectoryName(crowDbgAssemblyLocation), assemblyName.Name + ".dll")); + }; //using (crowLoadCtx.EnterContextualReflection()) { crowAssembly = crowLoadCtx.LoadFromAssemblyPath (crowDbgAssemblyLocation); @@ -210,7 +215,6 @@ namespace Crow } dbgIfaceType = thisAssembly.GetType("Crow.DebugInterface"); - dbgIFace = Activator.CreateInstance (dbgIfaceType, new object[] {IFace.WindowHandle}); delResize = (Action)Delegate.CreateDelegate(typeof(Action), @@ -252,6 +256,7 @@ namespace Crow null, debuggerType.GetMethod("Reset")); /*delSaveDebugLog = (Action)Delegate.CreateDelegate(typeof(Action), null, debuggerType.GetMethod("Save", new Type[] {dbgIfaceType, typeof(string)}));*/ + hasVkvgBackend = (bool)dbgIfaceType.GetField ("HaveVkvgBackend", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy).GetValue (null); dbgIfaceType.GetMethod("RegisterDebugInterfaceCallback").Invoke (dbgIFace, new object[] {this} ); dbgIfaceType.GetMethod("Run").Invoke (dbgIFace, null); @@ -265,7 +270,6 @@ namespace Crow protected override void onDraw(Context gr) { - Console.WriteLine("onDraw"); gr.SetSource(Colors.RoyalBlue); gr.Paint(); } @@ -376,8 +380,12 @@ namespace Crow bmp?.Dispose (); if (initialized) { - delResize (Slot.Width, Slot.Height); - bmp = IFace.CreateSurface (delGetSurfacePointer()); + delResize (Slot.Width, Slot.Height); + if (hasVkvgBackend) + bmp = IFace.CreateSurfaceForData (delGetSurfacePointer(), Slot.Width, Slot.Height); + else + bmp = IFace.CreateSurface (delGetSurfacePointer()); + } else bmp = IFace.CreateSurface (Slot.Width, Slot.Height);