From 764f158c099b5d8b827b28219f1525f434c531f1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Thu, 19 Sep 2019 17:17:59 +0200 Subject: [PATCH] wip --- README.md | 64 -------- SpirVTasks/CompileGLSLTask.cs | 6 +- samples/DistanceFieldFontTest/Program.cs | 1 - samples/Model/main.cs | 2 - samples/Textured/main.cs | 1 - samples/TexturedCube/main.cs | 1 - samples/Triangle/README.md | 68 ++++++++ samples/Triangle/main.cs | 3 +- samples/common/CrowWin.cs | 2 +- samples/deferred/main.cs | 16 +- samples/pbr/main.cs | 1 - vke/src/ExtensionMethods.cs | 49 ++++-- vke/src/FixedUtf8String.cs | 116 +++++-------- vke/src/MarshaledObject.cs | 24 +-- vke/src/MemoryPool.cs | 55 ++++--- vke/src/PinnedObjects.cs | 21 +++ vke/src/Utils.cs | 7 + vke/src/Version.cs | 23 --- vke/src/VkWindow.cs | 45 ++--- vke/src/base/CommandBuffer.cs | 37 ++--- vke/src/base/DebugReport.cs | 28 +--- vke/src/base/DebugUtilsMessenger.cs | 110 +++++++------ vke/src/base/DescriptorSetWrites.cs | 95 +++++++---- vke/src/base/Device.cs | 35 +--- vke/src/base/Image.cs | 2 +- vke/src/base/Instance.cs | 201 ++++++++++------------- vke/src/base/PhysicalDevice.cs | 198 ++++++++-------------- vke/src/base/Queue.cs | 27 +-- vke/src/glfw/CodePoint.cs | 2 +- vke/src/glfw/Glfw3.cs | 4 +- vke/src/ktx.cs | 7 +- vke/vke.csproj | 4 +- 32 files changed, 580 insertions(+), 675 deletions(-) create mode 100644 samples/Triangle/README.md create mode 100644 vke/src/PinnedObjects.cs delete mode 100644 vke/src/Version.cs diff --git a/README.md b/README.md index 3f59e44..0dc9e04 100644 --- a/README.md +++ b/README.md @@ -37,67 +37,3 @@ vke.net - ktx image loading. - Memory pools -### VkWindow class - -To create a new vulkan application, derrive your application from `VkWindow`. Validation and -debug reports may be activated with the static Fields of the `Instance` class. - -```csharp -class Program : VkWindow { - static void Main (string[] args) { - Instance.VALIDATION = true; - - using (Program vke = new Program ()) { - vke.Run (); - } - } -} -``` - -### Enabling features - -Override the `configureEnabledFeatures` method of `VkWindow` to enable features. -```csharp -protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures enabled_features) { - enabled_features.samplerAnisotropy = available_features.samplerAnisotropy; -} -``` -### Creating queues - -To create queues, override the `createQueues` method of `VkWindow`. This function is called before the logical device creation and will take care of physically available queues, creating duplicates if count exceed availability. The `base` method will create a default presentable queue. - -```csharp -protected override void createQueues () { - base.createQueues (); - transferQ = new Queue (dev, VkQueueFlags.Transfer); -} -``` -### Rendering - -The constructor of the `VkWIndow` will finish the vulkan initialisation, so that you may create pipelines, buffers, and so on in your constructor. - -VkWindow will provide the default swapchain, but it's up to you to create the frame buffers. For the triangle example, create them in the `OnResize` override. -```csharp -Framebuffer[] frameBuffers; - -protected override void OnResize () { - if (frameBuffers != null) - for (int i = 0; i < swapChain.ImageCount; ++i) - frameBuffers[i]?.Dispose (); - frameBuffers = new Framebuffer[swapChain.ImageCount]; - - for (int i = 0; i < swapChain.ImageCount; ++i) - frameBuffers[i] = new Framebuffer (pipeline.RenderPass, swapChain.Width, swapChain.Height, - (pipeline.Samples == VkSampleCountFlags.SampleCount1) ? new Image[] { - swapChain.images[i], - null - } : new Image[] { - null, - null, - swapChain.images[i] - }); - - buildCommandBuffers (); -} -``` - diff --git a/SpirVTasks/CompileGLSLTask.cs b/SpirVTasks/CompileGLSLTask.cs index cac29fc..d6f0741 100644 --- a/SpirVTasks/CompileGLSLTask.cs +++ b/SpirVTasks/CompileGLSLTask.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) + +using System; using System.Diagnostics; using System.IO; using Microsoft.Build.Framework; diff --git a/samples/DistanceFieldFontTest/Program.cs b/samples/DistanceFieldFontTest/Program.cs index 3c16773..666a1d1 100644 --- a/samples/DistanceFieldFontTest/Program.cs +++ b/samples/DistanceFieldFontTest/Program.cs @@ -16,7 +16,6 @@ namespace DistanceFieldFontTest { SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Unorm; #if DEBUG Instance.VALIDATION = true; - Instance.DEBUG_UTILS = true; Instance.RENDER_DOC_CAPTURE = false; #endif using (Program vke = new Program ()) { diff --git a/samples/Model/main.cs b/samples/Model/main.cs index 9acc570..05bae06 100644 --- a/samples/Model/main.cs +++ b/samples/Model/main.cs @@ -13,7 +13,6 @@ namespace ModelSample static void Main (string[] args) { #if DEBUG Instance.VALIDATION = true; - Instance.DEBUG_UTILS = true; Instance.RENDER_DOC_CAPTURE = false; #endif using (Program vke = new Program ()) { @@ -25,7 +24,6 @@ namespace ModelSample public Matrix4x4 projection; public Matrix4x4 view; public Matrix4x4 model; - //public Vector4 lightPos; } public struct PushConstants { diff --git a/samples/Textured/main.cs b/samples/Textured/main.cs index 3cff23c..e78dea0 100644 --- a/samples/Textured/main.cs +++ b/samples/Textured/main.cs @@ -10,7 +10,6 @@ namespace Textured { static void Main (string[] args) { #if DEBUG Instance.VALIDATION = true; - Instance.DEBUG_UTILS = true; Instance.RENDER_DOC_CAPTURE = true; #endif diff --git a/samples/TexturedCube/main.cs b/samples/TexturedCube/main.cs index 8a3336a..db810c4 100644 --- a/samples/TexturedCube/main.cs +++ b/samples/TexturedCube/main.cs @@ -14,7 +14,6 @@ namespace TextureCube { static void Main (string[] args) { #if DEBUG Instance.VALIDATION = true; - Instance.DEBUG_UTILS = true; Instance.RENDER_DOC_CAPTURE = false; #endif using (Program vke = new Program ()) { diff --git a/samples/Triangle/README.md b/samples/Triangle/README.md new file mode 100644 index 0000000..35e3a72 --- /dev/null +++ b/samples/Triangle/README.md @@ -0,0 +1,68 @@ + +### VkWindow class + +To create a new vulkan application, derrive your application from `VkWindow`. Validation and +debug reports may be activated with the static Fields of the `Instance` class. + +```csharp +class Program : VkWindow { + static void Main (string[] args) { + Instance.VALIDATION = true; + + using (Program vke = new Program ()) { + vke.Run (); + } + } +} +``` +### Enabling extensions + +The `VkWindow` class provides two properties that you may override to enable additional extensions. + +### Enabling features + +Override the `configureEnabledFeatures` method of `VkWindow` to enable features. +```csharp +protected override void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures enabled_features) { + enabled_features.samplerAnisotropy = available_features.samplerAnisotropy; +} +``` +### Creating queues + +To create queues, override the `createQueues` method of `VkWindow`. This function is called before the logical device creation and will take care of physically available queues, creating duplicates if count exceed availability. The `base` method will create a default presentable queue. + +```csharp +protected override void createQueues () { + base.createQueues (); + transferQ = new Queue (dev, VkQueueFlags.Transfer); +} +``` +### Rendering + +The constructor of the `VkWIndow` will finish the vulkan initialisation, so that you may create pipelines, buffers, and so on in your constructor. + +VkWindow will provide the default swapchain, but it's up to you to create the frame buffers. For the triangle example, create them in the `OnResize` override. +```csharp +Framebuffer[] frameBuffers; + +protected override void OnResize () { + if (frameBuffers != null) + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i]?.Dispose (); + frameBuffers = new Framebuffer[swapChain.ImageCount]; + + for (int i = 0; i < swapChain.ImageCount; ++i) + frameBuffers[i] = new Framebuffer (pipeline.RenderPass, swapChain.Width, swapChain.Height, + (pipeline.Samples == VkSampleCountFlags.SampleCount1) ? new Image[] { + swapChain.images[i], + null + } : new Image[] { + null, + null, + swapChain.images[i] + }); + + buildCommandBuffers (); +} +``` + diff --git a/samples/Triangle/main.cs b/samples/Triangle/main.cs index 9addb88..a9d5091 100644 --- a/samples/Triangle/main.cs +++ b/samples/Triangle/main.cs @@ -1,6 +1,7 @@ // Copyright (c) 2019 Jean-Philippe Bruyère // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; using System.Numerics; using System.Runtime.InteropServices; using vke; @@ -11,7 +12,6 @@ namespace Triangle { static void Main (string[] args) { #if DEBUG Instance.VALIDATION = true; - Instance.DEBUG_UTILS = true; Instance.RENDER_DOC_CAPTURE = false; #endif @@ -59,7 +59,6 @@ namespace Triangle { ushort[] indices = new ushort[] { 0, 1, 2 }; Program () : base () { - cmds = cmdPool.AllocateCommandBuffer(swapChain.ImageCount); vbo = new HostBuffer (dev, VkBufferUsageFlags.VertexBuffer, vertices); diff --git a/samples/common/CrowWin.cs b/samples/common/CrowWin.cs index cd440b0..ee7b2ac 100644 --- a/samples/common/CrowWin.cs +++ b/samples/common/CrowWin.cs @@ -87,7 +87,7 @@ namespace Crow { } void crow_thread_func () { - vkvgDev = new vkvg.Device (instance.Handle, phy.Handle, dev.Handle, presentQueue.qFamIndex, + vkvgDev = new vkvg.Device (instance.Handle, phy.Handle, dev.VkDev.Handle, presentQueue.qFamIndex, vkvg.SampleCount.Sample_4, presentQueue.index); crow = new Interface (vkvgDev, (int)swapChain.Width, (int)swapChain.Height); diff --git a/samples/deferred/main.cs b/samples/deferred/main.cs index b12d520..1130f75 100644 --- a/samples/deferred/main.cs +++ b/samples/deferred/main.cs @@ -11,7 +11,6 @@ namespace deferred { static void Main (string[] args) { #if DEBUG Instance.VALIDATION = true; - Instance.DEBUG_UTILS = true; //Instance.RENDER_DOC_CAPTURE = false; #endif SwapChain.PREFERED_FORMAT = VkFormat.B8g8r8a8Srgb; @@ -27,6 +26,10 @@ namespace deferred { } } + public override string[] EnabledInstanceExtensions => new string[] { + Ext.I.VK_EXT_debug_utils + }; + public override string[] EnabledDeviceExtensions => new string[] { Ext.D.VK_KHR_swapchain, Ext.D.VK_EXT_debug_marker @@ -75,9 +78,16 @@ namespace deferred { DescriptorPool descriptorPool; DescriptorSet descriptorSet; + vke.DebugUtils.Messenger dbgmsg; + + Deferred () : base("deferred") { + dbgmsg = new vke.DebugUtils.Messenger (instance, VkDebugUtilsMessageTypeFlagsEXT.PerformanceEXT | VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT | VkDebugUtilsMessageTypeFlagsEXT.GeneralEXT, + VkDebugUtilsMessageSeverityFlagsEXT.InfoEXT | + VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT | + VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT | + VkDebugUtilsMessageSeverityFlagsEXT.VerboseEXT); - Deferred () : base("deferred") { camera = new Camera (Utils.DegreesToRadians (45f), 1f, 0.1f, 16f); camera.SetPosition (0, 0, 2); @@ -512,6 +522,7 @@ namespace deferred { #endregion protected override void Dispose (bool disposing) { + dev.WaitIdle (); if (disposing) { if (!isDisposed) { computeCmdPool.Dispose (); @@ -522,6 +533,7 @@ namespace deferred { plBlur.Dispose (); plToneMap.Dispose (); descriptorPool.Dispose (); + dbgmsg.Dispose (); } dev.DestroySemaphore (blurComplete); } diff --git a/samples/pbr/main.cs b/samples/pbr/main.cs index 45ee433..b3b84ee 100644 --- a/samples/pbr/main.cs +++ b/samples/pbr/main.cs @@ -18,7 +18,6 @@ namespace pbrSample { static void Main (string[] args) { #if DEBUG Instance.VALIDATION = true; - Instance.DEBUG_UTILS = true; Instance.RENDER_DOC_CAPTURE = false; #endif using (Program vke = new Program ()) { diff --git a/vke/src/ExtensionMethods.cs b/vke/src/ExtensionMethods.cs index df7d5e6..afefdd9 100644 --- a/vke/src/ExtensionMethods.cs +++ b/vke/src/ExtensionMethods.cs @@ -31,10 +31,22 @@ namespace vke { /// public static Dictionary handles = new Dictionary(); + /// + /// Unpin the specified object and free the GCHandle associated. + /// + public static void Unpin (this object obj) { + if (!handles.ContainsKey (obj)) { + Debug.WriteLine ("Trying to unpin unpinned object: {0}.", obj); + return; + } + handles[obj].Free (); + handles.Remove (obj); + } + /// /// Pin the specified object and return a pointer. MUST be Unpined as soon as possible. /// - public static IntPtr Pin (this object obj) { + public static IntPtr Pin (this object obj) { if (handles.ContainsKey (obj)) { Debug.WriteLine ("Trying to pin already pinned object: {0}", obj); return handles[obj].AddrOfPinnedObject (); @@ -43,17 +55,6 @@ namespace vke { GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); handles.Add (obj, hnd); return hnd.AddrOfPinnedObject (); - } - /// - /// Unpin the specified object and free the GCHandle associated. - /// - public static void Unpin (this object obj) { - if (!handles.ContainsKey (obj)) { - Debug.WriteLine ("Trying to unpin unpinned object: {0}.", obj); - return; - } - handles[obj].Free (); - handles.Remove (obj); } public static IntPtr Pin (this List obj) { if (handles.ContainsKey (obj)) @@ -81,6 +82,30 @@ namespace vke { handles.Add (obj, hnd); return hnd.AddrOfPinnedObject (); } + + //pin with pinning context + public static IntPtr Pin (this object obj, PinnedObjects ctx) { + GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin (this List obj, PinnedObjects ctx) { + GCHandle hnd = GCHandle.Alloc (obj.ToArray (), GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin (this T[] obj, PinnedObjects ctx) { + GCHandle hnd = GCHandle.Alloc (obj, GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + public static IntPtr Pin (this string obj, PinnedObjects ctx) { + byte[] n = System.Text.Encoding.UTF8.GetBytes (obj + '\0'); + GCHandle hnd = GCHandle.Alloc (n, GCHandleType.Pinned); + ctx.Handles.Add (hnd); + return hnd.AddrOfPinnedObject (); + } + #endregion #region DebugMarkers diff --git a/vke/src/FixedUtf8String.cs b/vke/src/FixedUtf8String.cs index 9d11cfd..e8d9bb7 100644 --- a/vke/src/FixedUtf8String.cs +++ b/vke/src/FixedUtf8String.cs @@ -2,78 +2,46 @@ using System.Runtime.InteropServices; using System.Text; -namespace Vulkan -{ - public class FixedUtf8String : IDisposable - { - GCHandle _handle; - uint _numBytes; - - public IntPtr Ptr => _handle.AddrOfPinnedObject(); - - public FixedUtf8String(string s) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - - byte[] text = Encoding.UTF8.GetBytes(s + "\0"); - _handle = GCHandle.Alloc(text, GCHandleType.Pinned); - _numBytes = (uint)text.Length; - } - - public void SetText(string s) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - - _handle.Free(); - byte[] text = Encoding.UTF8.GetBytes(s); - _handle = GCHandle.Alloc(text, GCHandleType.Pinned); - _numBytes = (uint)text.Length; - } - - private string GetString() - { - return Marshal.PtrToStringUni(Ptr); - } - - public static implicit operator IntPtr (FixedUtf8String utf8String) => utf8String.Ptr; - public static implicit operator FixedUtf8String(string s) => new FixedUtf8String(s); - public static implicit operator string(FixedUtf8String utf8String) => utf8String.GetString(); - - #region IDisposable Support - private bool disposedValue = false; // Pour détecter les appels redondants - - protected virtual void Dispose (bool disposing) { - if (!disposedValue) { - if (disposing) { - // TODO: supprimer l'état managé (objets managés). - } - - // TODO: libérer les ressources non managées (objets non managés) et remplacer un finaliseur ci-dessous. - // TODO: définir les champs de grande taille avec la valeur Null. - _handle.Free (); - disposedValue = true; - } - } - - // TODO: remplacer un finaliseur seulement si la fonction Dispose(bool disposing) ci-dessus a du code pour libérer les ressources non managées. - ~FixedUtf8String() { - // Ne modifiez pas ce code. Placez le code de nettoyage dans Dispose(bool disposing) ci-dessus. - Dispose(false); - } - - // Ce code est ajouté pour implémenter correctement le modèle supprimable. - public void Dispose () { - // Ne modifiez pas ce code. Placez le code de nettoyage dans Dispose(bool disposing) ci-dessus. - Dispose (true); - // TODO: supprimer les marques de commentaire pour la ligne suivante si le finaliseur est remplacé ci-dessus. - GC.SuppressFinalize(this); - } - #endregion - } +namespace Vulkan { + public class FixedUtf8String : IDisposable { + GCHandle handle; + readonly uint numBytes; + + public IntPtr Ptr => handle.AddrOfPinnedObject (); + + public FixedUtf8String (string s) { + if (s == null) + throw new ArgumentNullException (nameof (s)); + + byte[] text = Encoding.UTF8.GetBytes (s + "\0"); + handle = GCHandle.Alloc (text, GCHandleType.Pinned); + numBytes = (uint)text.Length; + } + + private string GetString () { + return Marshal.PtrToStringUni (Ptr); + } + + public static implicit operator IntPtr (FixedUtf8String utf8String) => utf8String.Ptr; + public static implicit operator FixedUtf8String (string s) => new FixedUtf8String (s); + public static implicit operator string (FixedUtf8String utf8String) => utf8String.GetString (); + + #region IDisposable Support + private bool disposedValue = false; // Pour détecter les appels redondants + + protected virtual void Dispose (bool disposing) { + if (!disposedValue) { + handle.Free (); + disposedValue = true; + } + } + ~FixedUtf8String () { + Dispose (false); + } + public void Dispose () { + Dispose (true); + GC.SuppressFinalize (this); + } + #endregion + } } \ No newline at end of file diff --git a/vke/src/MarshaledObject.cs b/vke/src/MarshaledObject.cs index f6dd178..10cd344 100644 --- a/vke/src/MarshaledObject.cs +++ b/vke/src/MarshaledObject.cs @@ -20,24 +20,12 @@ namespace vke { public MarshaledObject (T mobj) { handle = GCHandle.Alloc (mobj, GCHandleType.Pinned); } - - void freeHandle () { - if (!disposed) - handle.Free (); - disposed = true; + ~MarshaledObject () { + handle.Free (); } - - #region IDisposable Support - private bool disposed; - - ~MarshaledObject() { - freeHandle (); - } - - public void Dispose () { - freeHandle (); - GC.SuppressFinalize(this); - } - #endregion + public void Dispose () { + handle.Free (); + GC.SuppressFinalize (this); + } } } diff --git a/vke/src/MemoryPool.cs b/vke/src/MemoryPool.cs index f3fc11b..492dd2f 100644 --- a/vke/src/MemoryPool.cs +++ b/vke/src/MemoryPool.cs @@ -8,9 +8,12 @@ using static Vulkan.Vk; namespace vke { #if MEMORY_POOLS + /// Direct how memory is allocated by a MemoryPool. public enum MemoryPoolType { + /// Not yet implemented. Random, - Linear + /// First free space next to the last added ressource will be choosen. + Linear } /// /// A memory pool is a single chunck of memory of a kind shared among multiple resources. @@ -19,34 +22,36 @@ namespace vke { Device dev; internal VkDeviceMemory vkMemory; VkMemoryAllocateInfo memInfo = VkMemoryAllocateInfo.New (); - - //Resource firstResource; + readonly ulong bufferImageGranularity; Resource lastResource; - //Resource mappedFrom; - //Resource mappedTo; - - //ulong freeMemPointer; IntPtr mappedPointer; - + /// Allocated device size in byte. public ulong Size => memInfo.allocationSize; + /// Return true if pool memory is currently mapped. public bool IsMapped => mappedPointer != IntPtr.Zero; + /// Return mapped memory pointer or null if not mapped. public IntPtr MappedData => mappedPointer; - public Resource Last => lastResource; + /// Last added resource, this is the entry element for the double linked list of ressource. + public Resource Last => lastResource; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// device + /// The vulkan device instance associated with this memory pool. /// Memory type index. /// Size public MemoryPool (Device dev, uint memoryTypeIndex, UInt64 size) { this.dev = dev; + bufferImageGranularity = dev.phy.Limits.bufferImageGranularity; memInfo.allocationSize = size; memInfo.memoryTypeIndex = memoryTypeIndex; Utils.CheckResult (vkAllocateMemory (dev.VkDev, ref memInfo, IntPtr.Zero, out vkMemory)); } - + /// + /// Allocate memory for a new resource in this memory pool. + /// + /// An or a ressource. public void Add (Resource resource) { resource.memoryPool = this; @@ -58,8 +63,8 @@ namespace vke { do { offset = previous.poolOffset + previous.AllocatedDeviceMemorySize; - if (previous.IsLinar != resource.IsLinar && offset % dev.BufferImageGranularity > 0) - offset += dev.BufferImageGranularity - (offset % dev.BufferImageGranularity); + if (previous.IsLinar != resource.IsLinar && offset % bufferImageGranularity > 0) + offset += bufferImageGranularity - (offset % bufferImageGranularity); if (offset % resource.MemoryAlignment > 0) offset += resource.MemoryAlignment - (offset % resource.MemoryAlignment); @@ -107,11 +112,16 @@ namespace vke { resource.bindMemory (); } - + /// + /// Try to reorganize ressources in this pool to optimize memory usage. + /// public void Defrag () { throw new NotImplementedException (); } - + /// + /// Remove the specified resource. + /// + /// Resource. public void Remove (Resource resource) { if (resource == lastResource) lastResource = resource.previous; @@ -124,16 +134,23 @@ namespace vke { } } resource.next = resource.previous = null; - } + }/// + /// Map the pool's memory at the specified offset. + /// + /// Size. + /// Offset. public void Map (ulong size = Vk.WholeSize, ulong offset = 0) { Utils.CheckResult (vkMapMemory (dev.VkDev, vkMemory, offset, size, 0, ref mappedPointer)); } + /// + /// Unmap previously mapped memory of this pool. + /// public void Unmap () { vkUnmapMemory (dev.VkDev, vkMemory); mappedPointer = IntPtr.Zero; } -#region IDisposable Support + #region IDisposable Support private bool disposedValue; protected virtual void Dispose (bool disposing) { @@ -155,7 +172,7 @@ namespace vke { Dispose (true); GC.SuppressFinalize(this); } -#endregion + #endregion } #endif } \ No newline at end of file diff --git a/vke/src/PinnedObjects.cs b/vke/src/PinnedObjects.cs new file mode 100644 index 0000000..525a311 --- /dev/null +++ b/vke/src/PinnedObjects.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2019 Jean-Philippe Bruyère +// +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace vke { + /// + /// Keep pinned object gc handles and free them on dispose. + /// + public class PinnedObjects : IDisposable { + public readonly List Handles = new List (); + + public void Dispose () { + for (int i = Handles.Count - 1; i >= 0; i--) + Handles[i].Free (); + GC.SuppressFinalize (this); + } + } +} diff --git a/vke/src/Utils.cs b/vke/src/Utils.cs index b2a3801..3cbd039 100644 --- a/vke/src/Utils.cs +++ b/vke/src/Utils.cs @@ -285,6 +285,13 @@ namespace Vulkan { break; } } + /// + /// Try to get the block width and height of a compressed format + /// + /// truereturn true if format given as first argument is a compressed format. + /// Vulkan format to test. + /// Compressed block width. + /// Compressed block height. public static bool TryGetCompressedFormatBlockSize (this VkFormat format, out uint width, out uint height) { width = height = 1; diff --git a/vke/src/Version.cs b/vke/src/Version.cs deleted file mode 100644 index ed71d20..0000000 --- a/vke/src/Version.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Vulkan -{ - public struct Version - { - private readonly uint value; - - public Version(uint major, uint minor, uint patch) - { - value = major << 22 | minor << 12 | patch; - } - - public uint Major => value >> 22; - - public uint Minor => (value >> 12) & 0x3ff; - - public uint Patch => (value >> 22) & 0xfff; - - public static implicit operator uint(Version version) - { - return version.value; - } - } -} \ No newline at end of file diff --git a/vke/src/VkWindow.cs b/vke/src/VkWindow.cs index 6d8ceb0..fc40cb4 100644 --- a/vke/src/VkWindow.cs +++ b/vke/src/VkWindow.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; using Glfw; using Vulkan; using static Vulkan.Vk; @@ -18,10 +19,12 @@ namespace vke { static Dictionary windows = new Dictionary(); IntPtr hWin; - + /**Vulkan Surface */ protected VkSurfaceKHR hSurf; - protected Instance instance; - protected PhysicalDevice phy; + /**vke Instance encapsulating a VkInstance. */ + protected Instance instance; + /**vke Physical device associated with this window*/ + protected PhysicalDevice phy; protected Device dev; protected PresentQueue presentQueue; protected SwapChain swapChain; @@ -29,8 +32,6 @@ namespace vke { protected CommandBuffer[] cmds; protected VkSemaphore[] drawComplete; - DebugReport dbgRepport; - protected uint fps; protected bool updateViewRequested = true; protected double lastMouseX, lastMouseY; @@ -48,7 +49,12 @@ namespace vke { Stopwatch frameChrono; /// - /// Override this property to change the list of enabled extensions + /// Override this property to change the list of enabled instance extensions + /// + public virtual string[] EnabledInstanceExtensions => null; + + /// + /// Override this property to change the list of enabled device extensions /// public virtual string[] EnabledDeviceExtensions => new string[] { Ext.D.VK_KHR_swapchain }; @@ -100,22 +106,17 @@ namespace vke { } void initVulkan (bool vSync) { - instance = new Instance (); - - if (Instance.DEBUG_UTILS) { - //dbgmsg = new CVKL.DebugUtils.Messenger (instance); - dbgRepport = new DebugReport (instance, - VkDebugReportFlagsEXT.ErrorEXT - | VkDebugReportFlagsEXT.WarningEXT - | VkDebugReportFlagsEXT.PerformanceWarningEXT - ); - } + List instExts = new List (Glfw3.GetRequiredInstanceExtensions ()); + if (EnabledInstanceExtensions != null) + instExts.AddRange (EnabledInstanceExtensions); + + instance = new Instance (instExts.ToArray()); hSurf = instance.CreateSurface (hWin); - phy = instance.GetAvailablePhysicalDevice ().Where (p => p.HasSwapChainSupport).FirstOrDefault (); + phy = instance.GetAvailablePhysicalDevice ().FirstOrDefault (p => p.HasSwapChainSupport); - VkPhysicalDeviceFeatures enabledFeatures = default (VkPhysicalDeviceFeatures); + VkPhysicalDeviceFeatures enabledFeatures = default; configureEnabledFeatures (phy.Features, ref enabledFeatures); //First create the c# device class @@ -146,13 +147,14 @@ namespace vke { cmdPool.SetName ("main CmdPool"); } /// - /// override this method to modify enabled features before device creation + /// Override this method to modify enabled features before device creation. Feature availability is given by the first argument. /// - /// Features. + /// Available features for the selected vulkan physical device associated with this window + /// Set boolean fileds of this structure to true to enable features. protected virtual void configureEnabledFeatures (VkPhysicalDeviceFeatures available_features, ref VkPhysicalDeviceFeatures enabled_features) { } /// - /// override this method to create additional queue. Dedicated queue of the requested type will be selected first, created queues may excess + /// Override this method to create additional queue. Dedicated queue of the requested type will be selected first, created queues may excess /// available physical queues. /// protected virtual void createQueues () { @@ -333,7 +335,6 @@ namespace vke { if (disposing) { cmdPool.Dispose (); dev.Dispose (); - dbgRepport?.Dispose (); instance.Dispose (); } else Debug.WriteLine ("a VkWindow has not been correctly disposed"); diff --git a/vke/src/base/CommandBuffer.cs b/vke/src/base/CommandBuffer.cs index 220a565..83e2f9b 100644 --- a/vke/src/base/CommandBuffer.cs +++ b/vke/src/base/CommandBuffer.cs @@ -41,27 +41,22 @@ namespace vke { IntPtr dstStageMask = Marshal.AllocHGlobal (sizeof(uint)); Marshal.WriteInt32 (dstStageMask, (int)VkPipelineStageFlags.ColorAttachmentOutput); - submit_info.pWaitDstStageMask = dstStageMask; - if (signal != VkSemaphore.Null) { - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = signal.Pin(); - } - if (wait != VkSemaphore.Null) { - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = wait.Pin(); - } - - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = handle.Pin(); - - Utils.CheckResult (vkQueueSubmit (queue, 1, ref submit_info, fence)); - - if (signal != VkSemaphore.Null) - signal.Unpin (); - if (wait != VkSemaphore.Null) - wait.Unpin (); - handle.Unpin (); - + using (PinnedObjects pctx = new PinnedObjects ()) { + submit_info.pWaitDstStageMask = dstStageMask; + if (signal != VkSemaphore.Null) { + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = signal.Pin (pctx); + } + if (wait != VkSemaphore.Null) { + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = wait.Pin (pctx); + } + + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = handle.Pin (pctx); + + Utils.CheckResult (vkQueueSubmit (queue, 1, ref submit_info, fence)); + } Marshal.FreeHGlobal (dstStageMask); } public void Start (VkCommandBufferUsageFlags usage = 0) { diff --git a/vke/src/base/DebugReport.cs b/vke/src/base/DebugReport.cs index 1e1842b..e5e8e88 100644 --- a/vke/src/base/DebugReport.cs +++ b/vke/src/base/DebugReport.cs @@ -1,35 +1,13 @@ -// -// DebugReport.cs +// Copyright (c) 2019 Jean-Philippe Bruyère // -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2019 jp -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; using System.Runtime.InteropServices; using Vulkan; using static Vulkan.Vk; namespace vke { - + [Obsolete("Use the new VK_EXT_debug_utils extension")] public class DebugReport : IDisposable { VkDebugReportCallbackEXT handle; Instance inst; diff --git a/vke/src/base/DebugUtilsMessenger.cs b/vke/src/base/DebugUtilsMessenger.cs index 9a83392..419e140 100644 --- a/vke/src/base/DebugUtilsMessenger.cs +++ b/vke/src/base/DebugUtilsMessenger.cs @@ -4,68 +4,80 @@ using Vulkan; using static Vulkan.Vk; namespace vke.DebugUtils { - - public class Messenger : IDisposable { + /// + /// Dispoable vke class that encapsulate a VkDebugUtilsMessengerEXT object + /// + public class Messenger : IDisposable { Instance inst; - VkDebugUtilsMessengerEXT handle; - PFN_vkDebugUtilsMessengerCallbackEXT onMessage = new PFN_vkDebugUtilsMessengerCallbackEXT(HandlePFN_vkDebugUtilsMessengerCallbackEXT); + readonly VkDebugUtilsMessengerEXT handle; + readonly static PFN_vkDebugUtilsMessengerCallbackEXT onMessage = new PFN_vkDebugUtilsMessengerCallbackEXT(HandlePFN_vkDebugUtilsMessengerCallbackEXT); static VkBool32 HandlePFN_vkDebugUtilsMessengerCallbackEXT (VkDebugUtilsMessageSeverityFlagsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, IntPtr pCallbackData, IntPtr pUserData) { - //Console.WriteLine ("{0} {1}: {2}",messageSeverity, messageTypes, Marshal.PtrToStringAnsi(pUserData)); - Console.WriteLine ("MESSAGE RECEIVED"); - return false; - } - - - - // PFN_vkDebugReportCallbackEXT debugCallbackDelegate = new PFN_vkDebugReportCallbackEXT (debugCallback); + VkDebugUtilsMessengerCallbackDataEXT data = Marshal.PtrToStructure (pCallbackData); + ConsoleColor curColor = Console.ForegroundColor; - // static VkBool32 debugCallback (VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, ulong obj, - // UIntPtr location, int messageCode, IntPtr pLayerPrefix, IntPtr pMessage, IntPtr pUserData) { - // string prefix = ""; - // switch (flags) { - // case 0: - // prefix = "?"; - // break; - // case VkDebugReportFlagsEXT.InformationEXT: - // Console.ForegroundColor = ConsoleColor.Gray; - // prefix = "INFO"; - // break; - // case VkDebugReportFlagsEXT.WarningEXT: - // Console.ForegroundColor = ConsoleColor.DarkYellow; - // prefix = "WARN"; - // break; - // case VkDebugReportFlagsEXT.PerformanceWarningEXT: - // Console.ForegroundColor = ConsoleColor.Yellow; - // prefix = "PERF"; - // break; - // case VkDebugReportFlagsEXT.ErrorEXT: - // Console.ForegroundColor = ConsoleColor.DarkRed; - // prefix = "EROR"; - // break; - // case VkDebugReportFlagsEXT.DebugEXT: - // Console.ForegroundColor = ConsoleColor.Red; - // prefix = "DBUG"; - // break; - // } + switch (messageSeverity) { + case VkDebugUtilsMessageSeverityFlagsEXT.VerboseEXT: + Console.ForegroundColor = ConsoleColor.White; + break; + case VkDebugUtilsMessageSeverityFlagsEXT.InfoEXT: + Console.ForegroundColor = ConsoleColor.DarkCyan; + break; + case VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT: + Console.ForegroundColor = ConsoleColor.DarkYellow; + break; + case VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT: + Console.ForegroundColor = ConsoleColor.Red; + break; + } - // Console.WriteLine ("{0} {1}: {2}",prefix, messageCode, Marshal.PtrToStringAnsi(pMessage)); - //Console.ForegroundColor = ConsoleColor.White; - // return VkBool32.False; - //} - - public Messenger (Instance instance, - VkDebugUtilsMessageTypeFlagsEXT typeMask = VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT, - VkDebugUtilsMessageSeverityFlagsEXT severityMask = VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT | VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT) { + switch (messageTypes) { + case VkDebugUtilsMessageTypeFlagsEXT.GeneralEXT: + Console.Write ("GEN:"); + break; + case VkDebugUtilsMessageTypeFlagsEXT.PerformanceEXT: + Console.Write ("PERF:"); + break; + } + Console.WriteLine (Marshal.PtrToStringAnsi (data.pMessage)); + Console.ForegroundColor = curColor; + return false; + } + /// + /// Create a new debug utils messenger providing a PFN_vkDebugUtilsMessengerCallbackEXT delegate. + /// + /// Vulkan Instance. + /// Message callback. + /// Type mask. + /// Severity mask. + public Messenger (Instance instance, PFN_vkDebugUtilsMessengerCallbackEXT onMessageDelegate, + VkDebugUtilsMessageTypeFlagsEXT typeMask = + VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT, + VkDebugUtilsMessageSeverityFlagsEXT severityMask = + VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT | + VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT) { inst = instance; VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.New (); info.messageType = typeMask; info.messageSeverity = severityMask; - info.pfnUserCallback = Marshal.GetFunctionPointerForDelegate (onMessage); + info.pfnUserCallback = Marshal.GetFunctionPointerForDelegate (onMessageDelegate); info.pUserData = IntPtr.Zero; Utils.CheckResult (vkCreateDebugUtilsMessengerEXT (inst.VkInstance, ref info, IntPtr.Zero, out handle)); + } + /// + /// Create a new debug utils messenger with default message callback outputing to Console. + /// + /// Vulkan Instance. + /// Type mask. + /// Severity mask. + public Messenger (Instance instance, + VkDebugUtilsMessageTypeFlagsEXT typeMask = + VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT, + VkDebugUtilsMessageSeverityFlagsEXT severityMask = + VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT | + VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT) : this (instance, onMessage, typeMask, severityMask) { } #region IDisposable Support diff --git a/vke/src/base/DescriptorSetWrites.cs b/vke/src/base/DescriptorSetWrites.cs index 51f8c0a..227ea0d 100644 --- a/vke/src/base/DescriptorSetWrites.cs +++ b/vke/src/base/DescriptorSetWrites.cs @@ -121,47 +121,76 @@ namespace vke { /// execute the descriptors writes targeting descriptorSets setted on AddWriteInfo call /// public void Write (Device dev, params object[] descriptors) { - //if (descriptors.Length != WriteDescriptorSets.Count) - // throw new Exception ("descriptors count must equal the WriteInfo count."); - List descriptorsLists = new List ();//strore temp arrays of pDesc for unpinning - //if descriptorCount>1 - int i = 0; - int wdsPtr = 0; - while (i < descriptors.Length) { - int firstDescriptor = i; - VkWriteDescriptorSet wds = WriteDescriptorSets[wdsPtr]; - if (dstSetOverride != null) - wds.dstSet = dstSetOverride.Value.Handle; - IntPtr pDescriptors = IntPtr.Zero; + using (PinnedObjects pinCtx = new PinnedObjects ()) { + int i = 0; + int wdsPtr = 0; + while (i < descriptors.Length) { + int firstDescriptor = i; + VkWriteDescriptorSet wds = WriteDescriptorSets[wdsPtr]; + if (dstSetOverride != null) + wds.dstSet = dstSetOverride.Value.Handle; + IntPtr pDescriptors = IntPtr.Zero; - if (wds.descriptorCount > 1) { - List descPtrArray = new List (); - for (int d = 0; d < wds.descriptorCount; d++) { - descPtrArray.Add (descriptors[i].Pin ()); + if (wds.descriptorCount > 1) { + List descPtrArray = new List (); + for (int d = 0; d < wds.descriptorCount; d++) { + descPtrArray.Add (descriptors[i].Pin (pinCtx)); + i++; + } + pDescriptors = descPtrArray.Pin (pinCtx); + } else { + pDescriptors = descriptors[i].Pin (pinCtx); i++; } - descriptorsLists.Add (descPtrArray); - pDescriptors = descPtrArray.Pin (); - } else { - pDescriptors = descriptors[i].Pin (); - i++; + if (descriptors[firstDescriptor] is VkDescriptorBufferInfo) + wds.pBufferInfo = pDescriptors; + else if (descriptors[firstDescriptor] is VkDescriptorImageInfo) + wds.pImageInfo = pDescriptors; + + WriteDescriptorSets[wdsPtr] = wds; + wdsPtr++; } - if (descriptors[firstDescriptor] is VkDescriptorBufferInfo) - wds.pBufferInfo = pDescriptors; - else if (descriptors[firstDescriptor] is VkDescriptorImageInfo) - wds.pImageInfo = pDescriptors; + vkUpdateDescriptorSets (dev.VkDev, (uint)WriteDescriptorSets.Count, WriteDescriptorSets.Pin (pinCtx), 0, IntPtr.Zero); + } + } + /// + /// execute the descriptors writes targeting descriptorSets setted on AddWriteInfo call + /// + public void Push (CommandBuffer cmd, PipelineLayout plLayout, params object[] descriptors) { + using (PinnedObjects pinCtx = new PinnedObjects ()) { + int i = 0; + int wdsPtr = 0; + while (i < descriptors.Length) { + int firstDescriptor = i; + VkWriteDescriptorSet wds = WriteDescriptorSets[wdsPtr]; + wds.dstSet = 0; + IntPtr pDescriptors = IntPtr.Zero; - WriteDescriptorSets[wdsPtr] = wds; - wdsPtr++; + if (wds.descriptorCount > 1) { + List descPtrArray = new List (); + for (int d = 0; d < wds.descriptorCount; d++) { + descPtrArray.Add (descriptors[i].Pin (pinCtx)); + i++; + } + pDescriptors = descPtrArray.Pin (pinCtx); + } else { + pDescriptors = descriptors[i].Pin (pinCtx); + i++; + } + if (descriptors[firstDescriptor] is VkDescriptorBufferInfo) + wds.pBufferInfo = pDescriptors; + else if (descriptors[firstDescriptor] is VkDescriptorImageInfo) + wds.pImageInfo = pDescriptors; + + WriteDescriptorSets[wdsPtr] = wds; + wdsPtr++; + } + vkCmdPushDescriptorSetKHR (cmd.Handle, VkPipelineBindPoint.Graphics, plLayout.handle, 0, + (uint)WriteDescriptorSets.Count, WriteDescriptorSets.Pin (pinCtx)); } - vkUpdateDescriptorSets (dev.VkDev, (uint)WriteDescriptorSets.Count, WriteDescriptorSets.Pin (), 0, IntPtr.Zero); - WriteDescriptorSets.Unpin (); - foreach (object descArray in descriptorsLists) - descArray.Unpin (); - for (i = 0; i < descriptors.Length; i++) - descriptors[i].Unpin (); } } + /// /// Descriptor set writes include descriptor in write addition with IDisposable model /// diff --git a/vke/src/base/Device.cs b/vke/src/base/Device.cs index 8f61fe9..a925625 100644 --- a/vke/src/base/Device.cs +++ b/vke/src/base/Device.cs @@ -1,30 +1,7 @@ -// -// Device.cs +// Copyright (c) 2019 Jean-Philippe Bruyère // -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2019 jp -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -40,12 +17,11 @@ namespace vke { /// after being disposed. /// public class Device : IDisposable { - public readonly PhysicalDevice phy; + public readonly PhysicalDevice phy; /**Vulkan physical device class*/ VkDevice dev; - public VkDevice VkDev => dev; - public IntPtr Handle => dev.Handle; - public readonly ulong BufferImageGranularity; + public VkDevice VkDev => dev; /**Vulkan logical device handle*/ + internal List queues = new List (); internal bool debugMarkersEnabled; @@ -56,7 +32,6 @@ namespace vke { public Device (PhysicalDevice _phy) { phy = _phy; - BufferImageGranularity = phy.Limits.bufferImageGranularity; } public void Activate (VkPhysicalDeviceFeatures enabledFeatures, params string[] extensions) { diff --git a/vke/src/base/Image.cs b/vke/src/base/Image.cs index 7b6d000..5238fa7 100644 --- a/vke/src/base/Image.cs +++ b/vke/src/base/Image.cs @@ -555,7 +555,7 @@ namespace vke { case VkImageLayout.TransferSrcOptimal: // Image will be used as a transfer source // Make sure any reads from and writes to the image have been finished - imageMemoryBarrier.srcAccessMask |= VkAccessFlags.TransferRead; + //imageMemoryBarrier.srcAccessMask |= VkAccessFlags.TransferRead; imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferRead; break; diff --git a/vke/src/base/Instance.cs b/vke/src/base/Instance.cs index 86e303b..71e9c9d 100644 --- a/vke/src/base/Instance.cs +++ b/vke/src/base/Instance.cs @@ -25,6 +25,7 @@ // THE SOFTWARE. using System; using System.Collections.Generic; +using System.Linq; using System.Runtime.InteropServices; using Vulkan; using static Vulkan.Vk; @@ -33,119 +34,99 @@ namespace vke { /// /// Vulkan Instance disposable class /// - public class Instance : IDisposable { + public class Instance : IDisposable { /// If true, the VK_LAYER_KHRONOS_validation layer is loaded at startup; public static bool VALIDATION; - /// If true, the VK_EXT_debug_utils and VK_EXT_debug_report instance extensions are enabled - public static bool DEBUG_UTILS; /// If true, the VK_LAYER_RENDERDOC_Capture layer is loaded at startup; public static bool RENDER_DOC_CAPTURE; - VkInstance inst; + public static uint VK_MAJOR = 1; + public static uint VK_MINOR = 1; + + public static string ENGINE_NAME = "vke.net"; + public static string APPLICATION_NAME = "vke.net"; + + VkInstance inst; public IntPtr Handle => inst.Handle; public VkInstance VkInstance => inst; static class Strings { - public static FixedUtf8String Name = "VKENGINE"; - public static FixedUtf8String VK_KHR_SURFACE_EXTENSION_NAME = "VK_KHR_surface"; - public static FixedUtf8String VK_KHR_WIN32_SURFACE_EXTENSION_NAME = "VK_KHR_win32_surface"; - public static FixedUtf8String VK_KHR_XCB_SURFACE_EXTENSION_NAME = "VK_KHR_xcb_surface"; - public static FixedUtf8String VK_KHR_XLIB_SURFACE_EXTENSION_NAME = "VK_KHR_xlib_surface"; - public static FixedUtf8String VK_KHR_SWAPCHAIN_EXTENSION_NAME = "VK_KHR_swapchain"; - public static FixedUtf8String VK_EXT_DEBUG_REPORT_EXTENSION_NAME = "VK_EXT_debug_report"; - public static FixedUtf8String VK_EXT_DEBUG_UTILS_EXTENSION_NAME = "VK_EXT_debug_utils"; - public static FixedUtf8String LayerValidation = "VK_LAYER_KHRONOS_validation"; - public static FixedUtf8String LayerValidation_old = "VK_LAYER_LUNARG_standard_validation"; - public static FixedUtf8String LayerMonitor = "VK_LAYER_LUNARG_monitor"; - public static FixedUtf8String VkTraceLayeName = "VK_LAYER_LUNARG_vktrace"; - public static FixedUtf8String RenderdocCaptureLayerName = "VK_LAYER_RENDERDOC_Capture"; - public static FixedUtf8String main = "main"; - } - - public Instance () { - init (); - } - - unsafe bool ExtensionIsSupported (FixedUtf8String layer, string extName) { - uint count; - Utils.CheckResult (vkEnumerateInstanceExtensionProperties ((IntPtr)layer, out count, IntPtr.Zero)); - VkExtensionProperties[] tmp = new VkExtensionProperties[count]; - Utils.CheckResult (vkEnumerateInstanceExtensionProperties (layer, out count, tmp.Pin ())); - tmp.Unpin (); - - fixed (VkExtensionProperties* ep = tmp) { - for (int i = 0; i < tmp.Length; i++) { - IntPtr n = (IntPtr)ep[i].extensionName; - if (Marshal.PtrToStringAnsi (n) == extName) - return true; - } - } - return false; - } - + public static FixedUtf8String main = "main"; + } + const string strValidationLayer = "VK_LAYER_KHRONOS_validation"; + const string strRenderDocLayer = "VK_LAYER_RENDERDOC_Capture"; - void init () { + /// + /// Create a new vulkan instance with enabled extensions given as argument. + /// + /// List of extension to enable if supported + public Instance (params string[] extensions) { List instanceExtensions = new List (); List enabledLayerNames = new List (); - instanceExtensions.Add (Strings.VK_KHR_SURFACE_EXTENSION_NAME); - if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) { - instanceExtensions.Add (Strings.VK_KHR_WIN32_SURFACE_EXTENSION_NAME); - } else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) { - instanceExtensions.Add (Strings.VK_KHR_XCB_SURFACE_EXTENSION_NAME); - } else { - throw new PlatformNotSupportedException (); - } - - if (VALIDATION) { - enabledLayerNames.Add (Strings.LayerValidation); - //enabledLayerNames.Add (Strings.LayerValidation_old); + string[] supportedExts = SupportedExtensions (IntPtr.Zero); - if (DEBUG_UTILS) { - //if (ExtensionIsSupported(Strings.LayerValidation, Strings.VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) - //instanceExtensions.Add (Strings.VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - instanceExtensions.Add (Strings.VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + using (PinnedObjects pctx = new PinnedObjects ()) { + for (int i = 0; i < extensions.Length; i++) { + if (supportedExts.Contains (extensions[i])) + instanceExtensions.Add (extensions[i].Pin (pctx)); + else + Console.WriteLine ($"Vulkan initialisation: Unsupported extension: {extensions[i]}"); } - } - if (RENDER_DOC_CAPTURE) - enabledLayerNames.Add (Strings.RenderdocCaptureLayerName); + if (VALIDATION) + enabledLayerNames.Add (strValidationLayer.Pin (pctx)); + if (RENDER_DOC_CAPTURE) + enabledLayerNames.Add (strRenderDocLayer.Pin (pctx)); - VkApplicationInfo appInfo = new VkApplicationInfo () { - sType = VkStructureType.ApplicationInfo, - apiVersion = new Vulkan.Version (1, 0, 0), - pApplicationName = Strings.Name, - pEngineName = Strings.Name, - }; - VkInstanceCreateInfo instanceCreateInfo = VkInstanceCreateInfo.New (); - instanceCreateInfo.pApplicationInfo = appInfo.Pin (); + VkApplicationInfo appInfo = new VkApplicationInfo () { + sType = VkStructureType.ApplicationInfo, + apiVersion = new Vulkan.Version (VK_MAJOR, VK_MINOR, 0), + pApplicationName = ENGINE_NAME.Pin (pctx), + pEngineName = APPLICATION_NAME.Pin (pctx), + }; - if (instanceExtensions.Count > 0) { - instanceCreateInfo.enabledExtensionCount = (uint)instanceExtensions.Count; - instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.Pin (); - } - if (enabledLayerNames.Count > 0) { - instanceCreateInfo.enabledLayerCount = (uint)enabledLayerNames.Count; - instanceCreateInfo.ppEnabledLayerNames = enabledLayerNames.Pin (); + VkInstanceCreateInfo instanceCreateInfo = VkInstanceCreateInfo.New (); + instanceCreateInfo.pApplicationInfo = appInfo.Pin (pctx); + + if (instanceExtensions.Count > 0) { + instanceCreateInfo.enabledExtensionCount = (uint)instanceExtensions.Count; + instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.Pin (pctx); + } + if (enabledLayerNames.Count > 0) { + instanceCreateInfo.enabledLayerCount = (uint)enabledLayerNames.Count; + instanceCreateInfo.ppEnabledLayerNames = enabledLayerNames.Pin (pctx); + } + + VkResult result = vkCreateInstance (ref instanceCreateInfo, IntPtr.Zero, out inst); + if (result != VkResult.Success) + throw new InvalidOperationException ("Could not create Vulkan instance. Error: " + result); + + Vk.LoadInstanceFunctionPointers (inst); } + } - VkResult result = vkCreateInstance (ref instanceCreateInfo, IntPtr.Zero, out inst); - if (result != VkResult.Success) - throw new InvalidOperationException ("Could not create Vulkan instance. Error: " + result); + public string[] SupportedExtensions (IntPtr layer) { + Utils.CheckResult (vkEnumerateInstanceExtensionProperties (layer, out uint count, IntPtr.Zero)); - Vk.LoadInstanceFunctionPointers (inst); + int sizeStruct = Marshal.SizeOf (); + IntPtr ptrSupExts = Marshal.AllocHGlobal (sizeStruct * (int)count); + Utils.CheckResult (vkEnumerateInstanceExtensionProperties (layer, out count, ptrSupExts)); - appInfo.Unpin (); + string[] result = new string[count]; + IntPtr tmp = ptrSupExts; + for (int i = 0; i < count; i++) { + result[i] = Marshal.PtrToStringAnsi (tmp); + tmp += sizeStruct; + } - if (instanceExtensions.Count > 0) - instanceExtensions.Unpin (); - if (enabledLayerNames.Count > 0) - enabledLayerNames.Unpin (); + Marshal.FreeHGlobal (ptrSupExts); + return result; } public PhysicalDeviceCollection GetAvailablePhysicalDevice () => new PhysicalDeviceCollection (inst); @@ -158,35 +139,35 @@ namespace vke { return surf; } public void GetDelegate (string name, out T del) { - using (FixedUtf8String n = new FixedUtf8String (name)) { - del = Marshal.GetDelegateForFunctionPointer (vkGetInstanceProcAddr (Handle, (IntPtr)n)); - } - } + using (FixedUtf8String n = new FixedUtf8String (name)) { + del = Marshal.GetDelegateForFunctionPointer (vkGetInstanceProcAddr (Handle, (IntPtr)n)); + } + } - #region IDisposable Support - private bool disposedValue = false; + #region IDisposable Support + private bool disposedValue = false; - protected virtual void Dispose (bool disposing) { - if (!disposedValue) { + protected virtual void Dispose (bool disposing) { + if (!disposedValue) { if (disposing) { // TODO: supprimer l'état managé (objets managés). } else System.Diagnostics.Debug.WriteLine ("Instance disposed by Finalizer"); - - vkDestroyInstance (inst, IntPtr.Zero); - - disposedValue = true; - } - } - - ~Instance () { - Dispose(false); - } - - public void Dispose () { - Dispose (true); - GC.SuppressFinalize(this); - } - #endregion - } + + vkDestroyInstance (inst, IntPtr.Zero); + + disposedValue = true; + } + } + + ~Instance () { + Dispose (false); + } + + public void Dispose () { + Dispose (true); + GC.SuppressFinalize (this); + } + #endregion + } } diff --git a/vke/src/base/PhysicalDevice.cs b/vke/src/base/PhysicalDevice.cs index 82e2582..c82e20e 100644 --- a/vke/src/base/PhysicalDevice.cs +++ b/vke/src/base/PhysicalDevice.cs @@ -1,28 +1,6 @@ -// -// PhysicalDevice.cs +// Copyright (c) 2019 Jean-Philippe Bruyère // -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2019 jp -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; using Vulkan; using static Vulkan.Vk; @@ -30,66 +8,58 @@ using static Vulkan.Utils; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; - using System.Linq; namespace vke { - public class PhysicalDeviceCollection : IEnumerable { - VkInstance inst; - PhysicalDevice[] phys; - + /// + /// Collection of physical devices returned by the vulkan instance. + /// + public class PhysicalDeviceCollection : IEnumerable { + readonly VkInstance inst; + readonly PhysicalDevice[] phys; + + /// + /// Retrieve the physical devices available for the provided vulkan instance + /// + /// The vulkan instance to retrieve the physical devices from. public PhysicalDeviceCollection (VkInstance instance) { inst = instance; - init (); - } + CheckResult (vkEnumeratePhysicalDevices (inst, out uint gpuCount, IntPtr.Zero)); + if (gpuCount <= 0) + throw new Exception ("No GPU found"); - public PhysicalDevice this[int i] { - get { - return phys[i]; - } - } - - public IEnumerator GetEnumerator () { - return ((IEnumerable)phys).GetEnumerator (); - } + IntPtr gpus = Marshal.AllocHGlobal (Marshal.SizeOf () * (int)gpuCount); + CheckResult (vkEnumeratePhysicalDevices (inst, out gpuCount, gpus), "Could not enumerate physical devices."); - IEnumerator IEnumerable.GetEnumerator () { - return ((IEnumerable)phys).GetEnumerator (); - } - - void init () { - uint gpuCount = 0; - CheckResult (vkEnumeratePhysicalDevices (inst, out gpuCount, IntPtr.Zero)); - if (gpuCount <= 0) - throw new Exception ("No GPU found"); - - IntPtr gpus = Marshal.AllocHGlobal (Marshal.SizeOf ()* (int)gpuCount); - CheckResult (vkEnumeratePhysicalDevices (inst, out gpuCount, gpus), "Could not enumerate physical devices."); - - phys = new PhysicalDevice[gpuCount]; + phys = new PhysicalDevice[gpuCount]; - for (int i = 0; i < gpuCount; i++) - phys[i] = new PhysicalDevice (Marshal.ReadIntPtr(gpus + i * Marshal.SizeOf())); + for (int i = 0; i < gpuCount; i++) + phys[i] = new PhysicalDevice (Marshal.ReadIntPtr (gpus + i * Marshal.SizeOf ())); Marshal.FreeHGlobal (gpus); - } + } + + public PhysicalDevice this[int i] => phys[i]; + public IEnumerator GetEnumerator () => ((IEnumerable)phys).GetEnumerator (); + IEnumerator IEnumerable.GetEnumerator () => ((IEnumerable)phys).GetEnumerator (); } + /// + /// Vke class that encapsulate a physical device. + /// public class PhysicalDevice { - IntPtr phy; + readonly IntPtr phy; public VkPhysicalDeviceMemoryProperties memoryProperties { get; private set; } public VkQueueFamilyProperties[] QueueFamilies { get; private set; } public VkPhysicalDeviceProperties Properties { get { - VkPhysicalDeviceProperties pdp; - vkGetPhysicalDeviceProperties (phy, out pdp); + vkGetPhysicalDeviceProperties (phy, out VkPhysicalDeviceProperties pdp); return pdp; } } public VkPhysicalDeviceFeatures Features { get { - VkPhysicalDeviceFeatures df; - vkGetPhysicalDeviceFeatures (phy, out df); + vkGetPhysicalDeviceFeatures (phy, out VkPhysicalDeviceFeatures df); return df; } } @@ -97,88 +67,60 @@ namespace vke { public bool HasSwapChainSupport { get; private set; } public IntPtr Handle => phy; + public bool GetDeviceExtensionSupported (string extName) => SupportedExtensions (IntPtr.Zero).Contains (extName); - public PhysicalDevice (IntPtr vkPhy) { + #region CTOR + internal PhysicalDevice (IntPtr vkPhy) { phy = vkPhy; - init (); - } - unsafe void init () { - // Gather physical Device memory properties - IntPtr tmp = Marshal.AllocHGlobal (Marshal.SizeOf()); - vkGetPhysicalDeviceMemoryProperties (phy, tmp); - memoryProperties = Marshal.PtrToStructure (tmp); + // Gather physical Device memory properties + IntPtr tmp = Marshal.AllocHGlobal (Marshal.SizeOf ()); + vkGetPhysicalDeviceMemoryProperties (phy, tmp); + memoryProperties = Marshal.PtrToStructure (tmp); - uint queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties (phy, out queueFamilyCount, IntPtr.Zero); - QueueFamilies = new VkQueueFamilyProperties[queueFamilyCount]; + vkGetPhysicalDeviceQueueFamilyProperties (phy, out uint queueFamilyCount, IntPtr.Zero); + QueueFamilies = new VkQueueFamilyProperties[queueFamilyCount]; - if (queueFamilyCount <= 0) - throw new Exception ("No queues found for physical device"); + if (queueFamilyCount <= 0) + throw new Exception ("No queues found for physical device"); vkGetPhysicalDeviceQueueFamilyProperties (phy, out queueFamilyCount, QueueFamilies.Pin ()); QueueFamilies.Unpin (); - uint propCount = 0; - - vkEnumerateDeviceExtensionProperties (phy, IntPtr.Zero, out propCount, IntPtr.Zero); - - VkExtensionProperties[] extProps = new VkExtensionProperties[propCount]; - - vkEnumerateDeviceExtensionProperties (phy, IntPtr.Zero, out propCount, extProps.Pin ()); - extProps.Unpin (); - - for (int i = 0; i < extProps.Length; i++) - { - fixed (VkExtensionProperties* ep = extProps) { - IntPtr n = (IntPtr)ep[i].extensionName; - switch (Marshal.PtrToStringAnsi(n)) - { - case "VK_KHR_swapchain": - HasSwapChainSupport = true; - break; - } - } - } - } - - public unsafe bool GetDeviceExtensionSupported (string extName) { - uint propCount = 0; - - vkEnumerateDeviceExtensionProperties (phy, IntPtr.Zero, out propCount, IntPtr.Zero); + HasSwapChainSupport = GetDeviceExtensionSupported (Ext.D.VK_KHR_swapchain); + } + #endregion - VkExtensionProperties[] extProps = new VkExtensionProperties[propCount]; + public string[] SupportedExtensions (IntPtr layer) { + CheckResult (vkEnumerateDeviceExtensionProperties (phy, layer, out uint count, IntPtr.Zero)); - vkEnumerateDeviceExtensionProperties (phy, IntPtr.Zero, out propCount, extProps.Pin ()); - extProps.Unpin (); + int sizeStruct = Marshal.SizeOf (); + IntPtr ptrSupExts = Marshal.AllocHGlobal (sizeStruct * (int)count); + CheckResult (vkEnumerateDeviceExtensionProperties (phy, layer, out count, ptrSupExts)); - for (int i = 0; i < extProps.Length; i++) { - fixed (VkExtensionProperties* ep = extProps) { - IntPtr n = (IntPtr)ep[i].extensionName; - if (Marshal.PtrToStringAnsi (n) == extName) - return true; - } + string[] result = new string[count]; + IntPtr tmp = ptrSupExts; + for (int i = 0; i < count; i++) { + result[i] = Marshal.PtrToStringAnsi (tmp); + tmp += sizeStruct; } - Console.WriteLine ($"INFO: unsuported device extension: {extName}"); - return false; - } + Marshal.FreeHGlobal (ptrSupExts); + return result; + } - public bool GetPresentIsSupported (uint qFamilyIndex, VkSurfaceKHR surf) { - VkBool32 isSupported = false; - vkGetPhysicalDeviceSurfaceSupportKHR (phy, qFamilyIndex, surf, out isSupported); + public bool GetPresentIsSupported (uint qFamilyIndex, VkSurfaceKHR surf) { + vkGetPhysicalDeviceSurfaceSupportKHR (phy, qFamilyIndex, surf, out VkBool32 isSupported); return isSupported; } - public VkSurfaceCapabilitiesKHR GetSurfaceCapabilities (VkSurfaceKHR surf) { - VkSurfaceCapabilitiesKHR caps; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phy, surf, out caps); + public VkSurfaceCapabilitiesKHR GetSurfaceCapabilities (VkSurfaceKHR surf) { + vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phy, surf, out VkSurfaceCapabilitiesKHR caps); return caps; } - unsafe public VkSurfaceFormatKHR[] GetSurfaceFormats (VkSurfaceKHR surf) { - uint count = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR (phy, surf, out count, IntPtr.Zero); + public VkSurfaceFormatKHR[] GetSurfaceFormats (VkSurfaceKHR surf) { + vkGetPhysicalDeviceSurfaceFormatsKHR (phy, surf, out uint count, IntPtr.Zero); VkSurfaceFormatKHR[] formats = new VkSurfaceFormatKHR[count]; vkGetPhysicalDeviceSurfaceFormatsKHR (phy, surf, out count, formats.Pin()); @@ -186,9 +128,8 @@ namespace vke { return formats; } - unsafe public VkPresentModeKHR[] GetSurfacePresentModes (VkSurfaceKHR surf) { - uint count = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR (phy, surf, out count, IntPtr.Zero); + public VkPresentModeKHR[] GetSurfacePresentModes (VkSurfaceKHR surf) { + vkGetPhysicalDeviceSurfacePresentModesKHR (phy, surf, out uint count, IntPtr.Zero); VkPresentModeKHR[] modes = new VkPresentModeKHR[count]; vkGetPhysicalDeviceSurfacePresentModesKHR (phy, surf, out count, modes.Pin()); @@ -196,9 +137,8 @@ namespace vke { return modes; } - public VkFormatProperties GetFormatProperties (VkFormat format) { - VkFormatProperties properties; - vkGetPhysicalDeviceFormatProperties (phy, format, out properties); + public VkFormatProperties GetFormatProperties (VkFormat format) { + vkGetPhysicalDeviceFormatProperties (phy, format, out VkFormatProperties properties); return properties; } } diff --git a/vke/src/base/Queue.cs b/vke/src/base/Queue.cs index 1dddfa0..6c3bad8 100644 --- a/vke/src/base/Queue.cs +++ b/vke/src/base/Queue.cs @@ -1,30 +1,7 @@ -// -// Queue.cs +// Copyright (c) 2019 Jean-Philippe Bruyère // -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2019 jp -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; -using System.Collections; using Vulkan; using static Vulkan.Vk; diff --git a/vke/src/glfw/CodePoint.cs b/vke/src/glfw/CodePoint.cs index 09a60c9..a081e9f 100644 --- a/vke/src/glfw/CodePoint.cs +++ b/vke/src/glfw/CodePoint.cs @@ -27,7 +27,7 @@ namespace Glfw /// /// The character representation of the codepoint. /// - public char ToChar() => Encoding.UTF32.GetChars (new byte[] { byte0, byte0, byte0, byte0 })[0]; + public char ToChar() => Encoding.UTF32.GetChars (new byte[] { byte0, byte1, byte2, byte3 })[0]; /// /// Converts the value of this instance to its equivalent string representation. /// diff --git a/vke/src/glfw/Glfw3.cs b/vke/src/glfw/Glfw3.cs index 1531d79..081ec5c 100644 --- a/vke/src/glfw/Glfw3.cs +++ b/vke/src/glfw/Glfw3.cs @@ -452,11 +452,11 @@ namespace Glfw { { IntPtr names = GetRequiredInstanceExtensions(out int count); - var result = new string[count]; + string[] result = new string[count]; for (int nameIndex = 0; nameIndex < count; nameIndex++) { - IntPtr name = Marshal.ReadIntPtr (names, nameIndex); + IntPtr name = Marshal.ReadIntPtr (names, nameIndex * Marshal.SizeOf()); result[nameIndex] = Marshal.PtrToStringAnsi(name); } diff --git a/vke/src/ktx.cs b/vke/src/ktx.cs index ce6948f..5baa7d1 100644 --- a/vke/src/ktx.cs +++ b/vke/src/ktx.cs @@ -2,12 +2,11 @@ // // This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) using System; +using System.Collections.Generic; using System.IO; - -using Vulkan; -using vke; using System.Runtime.InteropServices; -using System.Collections.Generic; +using vke; +using Vulkan; namespace KTX { diff --git a/vke/vke.csproj b/vke/vke.csproj index ca13eff..7e4158a 100644 --- a/vke/vke.csproj +++ b/vke/vke.csproj @@ -26,6 +26,8 @@ false 7.2 + true + $(NoWarn);1591 @@ -47,7 +49,7 @@ - + -- 2.47.3