diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2019-04-05 14:13:20 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2019-04-05 14:13:20 +0200 |
| commit | 04d94de392b6e5ca4f82acc233df7b3f97abca36 (patch) | |
| tree | 27df9645ea97cf36c99cb4f8ed5f347cc00cb458 /vke | |
| parent | 7d305b07ccaeb2a8cd342e3395db46f2f8fffade (diff) | |
Activable pattern wip
Diffstat (limited to 'vke')
| -rw-r--r-- | vke/src/Activable.cs | 71 | ||||
| -rw-r--r-- | vke/src/Buffer.cs | 26 | ||||
| -rw-r--r-- | vke/src/DescriptorSetLayout.cs | 51 | ||||
| -rw-r--r-- | vke/src/Device.cs | 32 | ||||
| -rw-r--r-- | vke/src/ExtensionMethods.cs | 17 | ||||
| -rw-r--r-- | vke/src/FrameBuffer.cs | 122 | ||||
| -rw-r--r-- | vke/src/Image.cs | 37 | ||||
| -rw-r--r-- | vke/src/Pipeline.cs | 187 | ||||
| -rw-r--r-- | vke/src/PipelineConfig.cs | 163 | ||||
| -rw-r--r-- | vke/src/PipelineLayout.cs | 74 | ||||
| -rw-r--r-- | vke/src/RenderPass.cs | 176 | ||||
| -rw-r--r-- | vke/src/Resource.cs | 52 | ||||
| -rw-r--r-- | vke/src/ShaderInfo.cs | 69 |
13 files changed, 620 insertions, 457 deletions
diff --git a/vke/src/Activable.cs b/vke/src/Activable.cs new file mode 100644 index 0000000..da5fdfd --- /dev/null +++ b/vke/src/Activable.cs @@ -0,0 +1,71 @@ +// +// Activable.cs +// +// Author: +// Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +// +// 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. +using System; +using System.Collections.Generic; +using System.Linq; +using Vulkan; +using static Vulkan.VulkanNative; + +namespace VKE { + public enum ActivableState { Init, Activated, Disposed }; + public abstract class Activable : IDisposable { + protected uint references; + protected ActivableState state; + + public Device dev { get; private set; } + + protected Activable (Device dev) { + this.dev = dev; + } + + public virtual void Activate () { + if (state == ActivableState.Disposed) + GC.ReRegisterForFinalize (this); + state = ActivableState.Activated; + references++; + } + + public void Desactivate () { + } + #region IDisposable Support + protected virtual void Dispose (bool disposing) { + state = ActivableState.Disposed; + } + + ~Activable() { + Dispose(false); + } + public void Dispose () { + if (references>0) + references--; + if (references>0) + return; + Dispose (true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/vke/src/Buffer.cs b/vke/src/Buffer.cs index 1ad293e..d11c7da 100644 --- a/vke/src/Buffer.cs +++ b/vke/src/Buffer.cs @@ -111,9 +111,12 @@ namespace VKE { } public override void Activate () { - allocateMemory (); - bindMemory (0); - SetupDescriptor (); + if (state != ActivableState.Activated) { + allocateMemory (); + bindMemory (0); + SetupDescriptor (); + } + base.Activate (); } @@ -158,18 +161,11 @@ namespace VKE { Utils.CheckResult (vkBindBufferMemory (dev.VkDev, handle, vkMemory, offset)); } protected override void Dispose (bool disposing) { - if (references>0) - return; - if (!isDisposed) { - base.Dispose (disposing); - if (!disposing) - System.Diagnostics.Debug.WriteLine ($"A Buffer Ressource was not properly disposed."); - - - vkDestroyBuffer (dev.VkDev, handle, IntPtr.Zero); - - isDisposed = true; - } + if (state == ActivableState.Activated) { + base.Dispose (disposing); + vkDestroyBuffer (dev.VkDev, handle, IntPtr.Zero); + } + state = ActivableState.Disposed; } } } diff --git a/vke/src/DescriptorSetLayout.cs b/vke/src/DescriptorSetLayout.cs index 4d58ad3..49f5403 100644 --- a/vke/src/DescriptorSetLayout.cs +++ b/vke/src/DescriptorSetLayout.cs @@ -24,19 +24,19 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.Collections.Generic; using Vulkan; using static Vulkan.VulkanNative; namespace VKE { - public class DescriptorSetLayout : IDisposable { + public sealed class DescriptorSetLayout : Activable { internal VkDescriptorSetLayout handle; - internal Device dev; + public VkDescriptorSetLayoutCreateFlags Flags { get; private set; } = VkDescriptorSetLayoutCreateFlags.None; + public List<VkDescriptorSetLayoutBinding> Bindings { get; private set; } = new List<VkDescriptorSetLayoutBinding> (); - public NativeList<VkDescriptorSetLayoutBinding> Bindings = new NativeList<VkDescriptorSetLayoutBinding> (); - - public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags) { - dev = device; + #region CTORS + public DescriptorSetLayout (Device device, VkDescriptorSetLayoutCreateFlags flags) : base (device) { Flags = flags; } public DescriptorSetLayout (Device device, params VkDescriptorSetLayoutBinding[] bindings) @@ -48,35 +48,24 @@ namespace VKE { Bindings.Add (b); Activate (); } - public void Activate () { - if (isDisposed) { - GC.ReRegisterForFinalize (this); - isDisposed = false; - } - VkDescriptorSetLayoutCreateInfo info = new VkDescriptorSetLayoutCreateInfo (Flags, Bindings.Count, Bindings.Data); - Utils.CheckResult (vkCreateDescriptorSetLayout (dev.VkDev, ref info, IntPtr.Zero, out handle)); - } - - #region IDisposable Support - private bool isDisposed = false; // Pour détecter les appels redondants + #endregion - protected virtual void Dispose (bool disposing) { - if (!isDisposed) { - if (disposing) { - Bindings.Dispose (); - } else - System.Diagnostics.Debug.WriteLine ("A descriptorSetLayout has not been disposed."); - vkDestroyDescriptorSetLayout (dev.VkDev, handle, IntPtr.Zero); - isDisposed = true; + public override void Activate () { + if (state != ActivableState.Activated) { + VkDescriptorSetLayoutCreateInfo info = new VkDescriptorSetLayoutCreateInfo (Flags, (uint)Bindings.Count, Bindings.Pin()); + Utils.CheckResult (vkCreateDescriptorSetLayout (dev.VkDev, ref info, IntPtr.Zero, out handle)); + Bindings.Unpin (); } + base.Activate (); } - ~DescriptorSetLayout() { - Dispose(false); - } - public void Dispose () { - Dispose (true); - GC.SuppressFinalize(this); + #region IDisposable Support + protected override void Dispose (bool disposing) { + if (!disposing) + System.Diagnostics.Debug.WriteLine ("VKE DescriptorSetLayout disposed by finalizer"); + if (state == ActivableState.Activated) + vkDestroyDescriptorSetLayout (dev.VkDev, handle, IntPtr.Zero); + base.Dispose (disposing); } #endregion } diff --git a/vke/src/Device.cs b/vke/src/Device.cs index 85b2f48..869f639 100644 --- a/vke/src/Device.cs +++ b/vke/src/Device.cs @@ -45,13 +45,13 @@ namespace VKE { unsafe public void Activate (VkPhysicalDeviceFeatures enabledFeatures, params string[] extensions) { - NativeList<VkDeviceQueueCreateInfo> qInfos = new NativeList<VkDeviceQueueCreateInfo> (); - NativeList<float> priorities = null; + List<VkDeviceQueueCreateInfo> qInfos = new List<VkDeviceQueueCreateInfo> (); + List<List<float>> prioritiesLists = new List<List<float>> (); foreach (IGrouping<uint, Queue> qfams in queues.GroupBy (q => q.qFamIndex)) { int qTot = qfams.Count (); uint qIndex = 0; - priorities = new NativeList<float> (); + List<float>priorities = new List<float> (); bool qCountReached = false;//true when queue count of that family is reached foreach (Queue q in qfams) { @@ -62,18 +62,18 @@ namespace VKE { qIndex = 0; qCountReached = true; } - } + } qInfos.Add (new VkDeviceQueueCreateInfo { sType = VkStructureType.DeviceQueueCreateInfo, queueCount = qCountReached ? phy.QueueFamilies[qfams.Key].queueCount : qIndex, queueFamilyIndex = qfams.Key, - pQueuePriorities = (float*)priorities.Data.ToPointer () + pQueuePriorities = priorities.Pin () }); - } - float tmp = priorities[0]; + prioritiesLists.Add (priorities);//add for unpined + } - NativeList<IntPtr> deviceExtensions = new NativeList<IntPtr> (); + List<IntPtr> deviceExtensions = new List<IntPtr> (); for (int i = 0; i < extensions.Length; i++) { deviceExtensions.Add (new FixedUtf8String(extensions[i])); } @@ -81,20 +81,22 @@ namespace VKE { VkPhysicalDeviceFeatures features = enabledFeatures; VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.New (); - deviceCreateInfo.queueCreateInfoCount = qInfos.Count; - deviceCreateInfo.pQueueCreateInfos = (VkDeviceQueueCreateInfo*)qInfos.Data.ToPointer(); + deviceCreateInfo.queueCreateInfoCount = (uint)qInfos.Count; + deviceCreateInfo.pQueueCreateInfos = qInfos.Pin(); deviceCreateInfo.pEnabledFeatures = &features; if (deviceExtensions.Count > 0) { - deviceCreateInfo.enabledExtensionCount = deviceExtensions.Count; - deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.Data; + deviceCreateInfo.enabledExtensionCount = (uint)deviceExtensions.Count; + deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.Pin(); } Utils.CheckResult (vkCreateDevice (phy.Handle, ref deviceCreateInfo, IntPtr.Zero, out dev)); - qInfos.Dispose (); - priorities.Dispose (); - deviceExtensions.Dispose (); + qInfos.Unpin (); + foreach (List<float> fa in prioritiesLists) + fa.Unpin (); + + deviceExtensions.Unpin (); foreach (Queue q in queues) q.updateHandle (); diff --git a/vke/src/ExtensionMethods.cs b/vke/src/ExtensionMethods.cs index 1cf01cd..620c379 100644 --- a/vke/src/ExtensionMethods.cs +++ b/vke/src/ExtensionMethods.cs @@ -62,6 +62,21 @@ namespace VKE { handles[obj].Free (); handles.Remove (obj); } - + public static IntPtr Pin<T> (this List<T> obj) { + if (handles.ContainsKey (obj)) + Debug.WriteLine ("Pinning already pinned object: {0}", obj); + + GCHandle hnd = GCHandle.Alloc (obj.ToArray(), GCHandleType.Pinned); + handles.Add (obj, hnd); + return hnd.AddrOfPinnedObject (); + } + //public static void Unpin<T> (this List<T> obj) { + // if (!handles.ContainsKey (obj)) { + // Debug.WriteLine ("Trying to unpin {0}, but object has not been pinned.", obj); + // return; + // } + // handles[obj].Free (); + // handles.Remove (obj); + //} } } diff --git a/vke/src/FrameBuffer.cs b/vke/src/FrameBuffer.cs index 431c21e..e0b81a7 100644 --- a/vke/src/FrameBuffer.cs +++ b/vke/src/FrameBuffer.cs @@ -32,17 +32,19 @@ using static Vulkan.VulkanNative; namespace VKE { - public class Framebuffer : IDisposable { + public class Framebuffer : Activable { internal VkFramebuffer handle; RenderPass renderPass; - public List<Image> attachments = new List<Image> (); + + public List<Image> attachments = new List<Image> (); VkFramebufferCreateInfo createInfo = VkFramebufferCreateInfo.New (); + public uint Width => createInfo.width; public uint Height => createInfo.height; public uint Layers => createInfo.layers; - public Framebuffer (RenderPass _renderPass, uint _width, uint _height, uint _layers = 1) { + public Framebuffer (RenderPass _renderPass, uint _width, uint _height, uint _layers = 1) : base(_renderPass.dev) { renderPass = _renderPass; createInfo.width = _width; createInfo.height = _height; @@ -50,6 +52,46 @@ namespace VKE { createInfo.renderPass = renderPass.handle; } + public Framebuffer (RenderPass _renderPass, uint _width, uint _height, params Image[] views) + : this (_renderPass, _width, _height) { + for (int i = 0; i < views.Length; i++) { + Image v = views[i]; + if (v == null) { + //automatically create attachment if not in unused state in the renderpass + VkAttachmentDescription ad = renderPass.attachments[i]; + VkImageUsageFlags usage = VkImageUsageFlags.None; + VkImageAspectFlags aspectFlags = VkImageAspectFlags.None; + + checkLayoutRequirements (ad.initialLayout, ref usage, ref aspectFlags); + checkLayoutRequirements (ad.finalLayout, ref usage, ref aspectFlags); + foreach (SubPass sp in renderPass.subpasses) { + //TODO:check subpass usage + } + + v = new Image (renderPass.dev, ad.format, usage, VkMemoryPropertyFlags.DeviceLocal, + _width, _height, VkImageType.Image2D, ad.samples, VkImageTiling.Optimal, 1, createInfo.layers); + v.CreateView (VkImageViewType.Image2D, aspectFlags); + } else + v.Activate ();//increase ref and create handle if not already activated + + attachments.Add (v); + } + Activate (); + } + + public override void Activate () { + if (state != ActivableState.Activated) { + VkImageView[] views = attachments.Select (a => a.Descriptor.imageView).ToArray (); + createInfo.attachmentCount = (uint)views.Length; + createInfo.pAttachments = views.Pin (); + + Utils.CheckResult (vkCreateFramebuffer (renderPass.dev.VkDev, ref createInfo, IntPtr.Zero, out handle)); + + views.Unpin (); + } + base.Activate (); + } + void checkLayoutRequirements (VkImageLayout layout, ref VkImageUsageFlags usage, ref VkImageAspectFlags aspectFlags) { switch (layout) { case VkImageLayout.ColorAttachmentOptimal: @@ -84,71 +126,17 @@ namespace VKE { } } - - public Framebuffer (RenderPass _renderPass, uint _width, uint _height, params Image[] views) - : this (_renderPass, _width, _height) { - for (int i = 0; i < views.Length; i++) { - Image v = views[i]; - if (v == null){ - //automatically create attachment if not in unused state in the renderpass - VkAttachmentDescription ad = renderPass.attachments[i]; - VkImageUsageFlags usage = VkImageUsageFlags.None; - VkImageAspectFlags aspectFlags = VkImageAspectFlags.None; - - checkLayoutRequirements (ad.initialLayout, ref usage, ref aspectFlags); - checkLayoutRequirements (ad.finalLayout, ref usage, ref aspectFlags); - foreach (SubPass sp in renderPass.subpasses) { - //TODO:check subpass usage - } - - v = new Image (renderPass.dev, ad.format, usage, VkMemoryPropertyFlags.DeviceLocal, - _width, _height, VkImageType.Image2D, ad.samples, VkImageTiling.Optimal, 1, createInfo.layers); - v.CreateView (VkImageViewType.Image2D, aspectFlags); - } - v.references++; - attachments.Add (v); - } - Activate (); - } - - public void Activate () { - if (isDisposed) { - GC.ReRegisterForFinalize (this); - isDisposed = false; - } - VkImageView[] views; - views = attachments.Select(a=>a.Descriptor.imageView).ToArray(); - - createInfo.attachmentCount = (uint)views.Length; - createInfo.pAttachments = views.Pin(); - - Utils.CheckResult (vkCreateFramebuffer (renderPass.dev.VkDev, ref createInfo, IntPtr.Zero, out handle)); - - views.Unpin(); - } - #region IDisposable Support - private bool isDisposed = false; // Pour détecter les appels redondants - - protected virtual void Dispose (bool disposing) { - if (!isDisposed) { - renderPass.dev.DestroyFramebuffer (handle); - if (disposing) { - foreach (Image img in attachments) - img.Dispose(); - } else - System.Diagnostics.Debug.WriteLine ("A FrameBuffer has not been disposed."); - - isDisposed = true; - } - } - - ~Framebuffer () { - Dispose (false); - } - public void Dispose () { - Dispose (true); - GC.SuppressFinalize (this); + protected override void Dispose (bool disposing) { + if (state == ActivableState.Activated) + dev.DestroyFramebuffer (handle); + if (disposing) { + foreach (Image img in attachments) + img.Dispose(); + }else + System.Diagnostics.Debug.WriteLine ("VKE Activable object disposed by finalizer"); + + base.Dispose (disposing); } #endregion diff --git a/vke/src/Image.cs b/vke/src/Image.cs index a193544..295cdf1 100644 --- a/vke/src/Image.cs +++ b/vke/src/Image.cs @@ -46,8 +46,6 @@ namespace VKE { /// </summary> public Image (Device device, VkImage vkHandle, VkFormat format, VkImageUsageFlags usage, uint width, uint height) : base (device, VkMemoryPropertyFlags.DeviceLocal) { - dev = device; - info.imageType = VkImageType.Image2D; info.format = format; info.extent.width = width; @@ -61,6 +59,8 @@ namespace VKE { handle = vkHandle; imported = true; + + state = ActivableState.Activated; references++;//increment ref because it is bound to swapchain } @@ -224,9 +224,11 @@ namespace VKE { Utils.CheckResult (vkBindImageMemory (dev.VkDev, handle, vkMemory, offset)); } public override void Activate () { - Utils.CheckResult (vkCreateImage (dev.VkDev, ref info, IntPtr.Zero, out handle)); - allocateMemory (); - bindMemory (); + if (state != ActivableState.Activated) { + Utils.CheckResult (vkCreateImage (dev.VkDev, ref info, IntPtr.Zero, out handle)); + allocateMemory (); + bindMemory (); + } base.Activate (); } @@ -457,26 +459,17 @@ namespace VKE { } protected override void Dispose (bool disposing) { - if (references>0) - return; - if (!isDisposed) { - if (!disposing) - System.Diagnostics.Debug.WriteLine ($"An Image Ressource was not properly disposed."); - - if (Descriptor.sampler.Handle != 0) + if (state == ActivableState.Activated) { + if (Descriptor.sampler.Handle != 0) dev.DestroySampler (Descriptor.sampler); if (Descriptor.imageView.Handle != 0) dev.DestroyImageView (Descriptor.imageView); - if (imported) - return; - - if (!imported) - base.Dispose (disposing); - - dev.DestroyImage (handle); - - isDisposed = true; - } + if (!imported) { + base.Dispose (disposing); + dev.DestroyImage (handle); + } + } + state = ActivableState.Disposed; } } } diff --git a/vke/src/Pipeline.cs b/vke/src/Pipeline.cs index 3187e50..c3cb68d 100644 --- a/vke/src/Pipeline.cs +++ b/vke/src/Pipeline.cs @@ -30,37 +30,8 @@ using Vulkan; using static Vulkan.VulkanNative; namespace VKE { - public class ShaderInfo : IDisposable { - public VkShaderStageFlags StageFlags; - public string SpirvPath; - public FixedUtf8String EntryPoint; - - public ShaderInfo (VkShaderStageFlags _stageFlags, string _spirvPath, string _entryPoint = "main") { - StageFlags = _stageFlags; - SpirvPath = _spirvPath; - EntryPoint = new FixedUtf8String (_entryPoint); - } - - #region IDisposable Support - private bool disposedValue = false; // Pour détecter les appels redondants - - protected virtual void Dispose (bool disposing) { - if (!disposedValue) { - if (disposing) - EntryPoint.Dispose (); - - disposedValue = true; - } - } - public void Dispose () { - Dispose (true); - } - #endregion - } - - public class Pipeline : IDisposable { - internal VkPipeline handle; - Device dev; + public class Pipeline : Activable { + internal VkPipeline handle; VkPipelineBindPoint bindPoint = VkPipelineBindPoint.Graphics; VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = VkPipelineInputAssemblyStateCreateInfo.New (); @@ -69,10 +40,10 @@ namespace VKE { public VkPipelineDepthStencilStateCreateInfo depthStencilState = VkPipelineDepthStencilStateCreateInfo.New (); public VkPipelineMultisampleStateCreateInfo multisampleState = VkPipelineMultisampleStateCreateInfo.New (); - NativeList<VkPipelineColorBlendAttachmentState> blendAttachments = new NativeList<VkPipelineColorBlendAttachmentState>(); - NativeList<VkDynamicState> dynamicStates = new NativeList<VkDynamicState> (); - public NativeList<VkVertexInputBindingDescription> vertexBindings = new NativeList<VkVertexInputBindingDescription> (); - public NativeList<VkVertexInputAttributeDescription> vertexAttributes = new NativeList<VkVertexInputAttributeDescription> (); + List<VkPipelineColorBlendAttachmentState> blendAttachments = new List<VkPipelineColorBlendAttachmentState>(); + List<VkDynamicState> dynamicStates = new List<VkDynamicState> (); + public List<VkVertexInputBindingDescription> vertexBindings = new List<VkVertexInputBindingDescription> (); + public List<VkVertexInputAttributeDescription> vertexAttributes = new List<VkVertexInputAttributeDescription> (); public List<ShaderInfo> shaders = new List<ShaderInfo>(); public PipelineLayout Layout; @@ -102,16 +73,16 @@ namespace VKE { public void AddShader (VkShaderStageFlags _stageFlags, string _spirvPath, string _entryPoint = "main") { shaders.Add (new ShaderInfo (_stageFlags, _spirvPath, _entryPoint)); } + + #region CTORS /// <summary> /// Create a new Pipeline with supplied RenderPass /// </summary> public Pipeline (Device dev, RenderPass renderPass, VkPrimitiveTopology topology = VkPrimitiveTopology.TriangleList, - VkSampleCountFlags samples = VkSampleCountFlags.Count1) - { - this.dev = dev; + VkSampleCountFlags samples = VkSampleCountFlags.Count1) : base (dev) + { RenderPass = renderPass; - RenderPass.references++; inputAssemblyState.topology = topology; @@ -126,10 +97,7 @@ namespace VKE { viewportState.viewportCount = 1; viewportState.scissorCount = 1; - blendAttachments.Add (new VkPipelineColorBlendAttachmentState { - colorWriteMask = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A, - blendEnable = False - }); + blendAttachments.Add (new VkPipelineColorBlendAttachmentState (false)); dynamicStates.Add (VkDynamicState.Viewport); dynamicStates.Add (VkDynamicState.Scissor); @@ -156,97 +124,82 @@ namespace VKE { : this (dev, new RenderPass (dev, colorFormat, depthFormat, samples), topology,samples) { } + #endregion - public unsafe void Activate () { - if (isDisposed) { - GC.ReRegisterForFinalize (this); - isDisposed = false; - } - - Layout.Activate (); - - VkGraphicsPipelineCreateInfo info = VkGraphicsPipelineCreateInfo.New (); - info.renderPass = RenderPass.handle; - info.layout = Layout.handle; + public override void Activate () { + if (state != ActivableState.Activated) { + Layout.Activate (); + RenderPass.Activate (); - NativeList<VkPipelineShaderStageCreateInfo> shaderStages = new NativeList<VkPipelineShaderStageCreateInfo> (); - foreach (ShaderInfo shader in shaders) { - shaderStages.Add (new VkPipelineShaderStageCreateInfo { - sType = VkStructureType.PipelineShaderStageCreateInfo, - stage = shader.StageFlags, - pName = shader.EntryPoint.StringPtr, - module = dev.LoadSPIRVShader (shader.SpirvPath), - }); - } + List<VkPipelineShaderStageCreateInfo> shaderStages = new List<VkPipelineShaderStageCreateInfo> (); + foreach (ShaderInfo shader in shaders) + shaderStages.Add (shader.GetStageCreateInfo(dev)); - VkPipelineColorBlendStateCreateInfo colorBlendInfo = VkPipelineColorBlendStateCreateInfo.New (); - colorBlendInfo.attachmentCount = blendAttachments.Count; - colorBlendInfo.pAttachments = (VkPipelineColorBlendAttachmentState*) blendAttachments.Data.ToPointer (); + VkPipelineColorBlendStateCreateInfo colorBlendInfo = VkPipelineColorBlendStateCreateInfo.New (); + colorBlendInfo.attachmentCount = (uint)blendAttachments.Count; + colorBlendInfo.pAttachments = blendAttachments.Pin (); - VkPipelineDynamicStateCreateInfo dynStatesInfo = VkPipelineDynamicStateCreateInfo.New (); - dynStatesInfo.dynamicStateCount = dynamicStates.Count; - dynStatesInfo.pDynamicStates = (VkDynamicState*)dynamicStates.Data.ToPointer (); + VkPipelineDynamicStateCreateInfo dynStatesInfo = VkPipelineDynamicStateCreateInfo.New (); + dynStatesInfo.dynamicStateCount = (uint)dynamicStates.Count; + dynStatesInfo.pDynamicStates = dynamicStates.Pin (); - VkPipelineVertexInputStateCreateInfo vertInputInfo = VkPipelineVertexInputStateCreateInfo.New (); - vertInputInfo.vertexBindingDescriptionCount = vertexBindings.Count; - vertInputInfo.pVertexBindingDescriptions = (VkVertexInputBindingDescription*)vertexBindings.Data.ToPointer (); - vertInputInfo.vertexAttributeDescriptionCount = vertexAttributes.Count; - vertInputInfo.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription*)vertexAttributes.Data.ToPointer (); + VkPipelineVertexInputStateCreateInfo vertInputInfo = VkPipelineVertexInputStateCreateInfo.New (); + vertInputInfo.vertexBindingDescriptionCount = (uint)vertexBindings.Count; + vertInputInfo.pVertexBindingDescriptions = vertexBindings.Pin (); + vertInputInfo.vertexAttributeDescriptionCount = (uint)vertexAttributes.Count; + vertInputInfo.pVertexAttributeDescriptions = vertexAttributes.Pin (); - //local copy of class fiels whose addresses are requested - VkPipelineInputAssemblyStateCreateInfo sInputAssembly = inputAssemblyState; - VkPipelineRasterizationStateCreateInfo sRasterization = rasterizationState; - VkPipelineMultisampleStateCreateInfo sMultisample = multisampleState; - VkPipelineViewportStateCreateInfo sViewport = viewportState; - VkPipelineDepthStencilStateCreateInfo sDepthStencil = depthStencilState; + VkGraphicsPipelineCreateInfo info = VkGraphicsPipelineCreateInfo.New (); + info.renderPass = RenderPass.handle; + info.layout = Layout.handle; + info.pVertexInputState = vertInputInfo.Pin (); + info.pInputAssemblyState = inputAssemblyState.Pin (); + info.pRasterizationState = rasterizationState.Pin (); + info.pColorBlendState = colorBlendInfo.Pin (); + info.pMultisampleState = multisampleState.Pin (); + info.pViewportState = viewportState.Pin (); + info.pDepthStencilState = depthStencilState.Pin (); + info.pDynamicState = dynStatesInfo.Pin (); + info.stageCount = (uint)shaders.Count; + info.pStages = shaderStages.Pin (); - info.pVertexInputState = &vertInputInfo; - info.pInputAssemblyState = &sInputAssembly; - info.pRasterizationState = &sRasterization; - info.pColorBlendState = &colorBlendInfo; - info.pMultisampleState = &sMultisample; - info.pViewportState = &sViewport; - info.pDepthStencilState = &sDepthStencil; - info.pDynamicState = &dynStatesInfo; - info.stageCount = (uint)shaders.Count; - info.pStages = (VkPipelineShaderStageCreateInfo*)shaderStages.Data.ToPointer(); + Utils.CheckResult (vkCreateGraphicsPipelines (dev.VkDev, VkPipelineCache.Null, 1, ref info, IntPtr.Zero, out handle)); - Utils.CheckResult (vkCreateGraphicsPipelines (dev.VkDev, VkPipelineCache.Null, 1, ref info, IntPtr.Zero, out handle)); + for (int i = 0; i < shaders.Count; i++) + dev.DestroyShaderModule (shaderStages[i].module); - for (int i = 0; i < shaders.Count; i++) - dev.DestroyShaderModule (shaderStages[i].module); + vertInputInfo.Unpin (); + inputAssemblyState.Unpin (); + rasterizationState.Unpin (); + colorBlendInfo.Unpin (); + multisampleState.Unpin (); + viewportState.Unpin (); + depthStencilState.Unpin (); + dynStatesInfo.Unpin (); + shaderStages.Unpin (); - shaderStages.Dispose (); + vertexAttributes.Unpin (); + vertexBindings.Unpin (); + dynamicStates.Unpin (); + blendAttachments.Unpin (); + } + base.Activate (); } public void Bind (CommandBuffer cmd) { vkCmdBindPipeline (cmd.Handle, bindPoint, handle); } - #region IDisposable Support - private bool isDisposed = false; // Pour détecter les appels redondants - protected virtual void Dispose (bool disposing) { - if (!isDisposed) { - if (disposing) { - blendAttachments.Dispose (); - dynamicStates.Dispose (); - vertexBindings.Dispose (); - vertexAttributes.Dispose (); - RenderPass.Dispose (); - Layout.Dispose (); - } else - System.Diagnostics.Debug.WriteLine ("A Pipeline has not been disposed."); + #region IDisposable Support + protected override void Dispose (bool disposing) { + if (disposing) { + RenderPass.Dispose (); + Layout.Dispose (); + }else + System.Diagnostics.Debug.WriteLine ("VKE Activable object disposed by finalizer"); + if (state == ActivableState.Activated) VulkanNative.vkDestroyPipeline (dev.VkDev, handle, IntPtr.Zero); - isDisposed = true; - } - } - - ~Pipeline () { - Dispose (false); - } - public void Dispose () { - Dispose (true); - GC.SuppressFinalize (this); + base.Dispose (disposing); } #endregion } diff --git a/vke/src/PipelineConfig.cs b/vke/src/PipelineConfig.cs new file mode 100644 index 0000000..09b500c --- /dev/null +++ b/vke/src/PipelineConfig.cs @@ -0,0 +1,163 @@ +//// +//// FrameBuffer.cs +//// +//// Author: +//// Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +//// +//// 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. +//using System; +//using System.Collections.Generic; +//using System.Runtime.InteropServices; +//using Vulkan; +//using static Vulkan.VulkanNative; + +//namespace VKE { +// public class PipelineConfig { +// VkPipelineBindPoint bindPoint = VkPipelineBindPoint.Graphics; +// VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = VkPipelineInputAssemblyStateCreateInfo.New (); +// VkPipelineRasterizationStateCreateInfo rasterizationState = VkPipelineRasterizationStateCreateInfo.New (); +// VkPipelineViewportStateCreateInfo viewportState = VkPipelineViewportStateCreateInfo.New (); +// public VkPipelineDepthStencilStateCreateInfo depthStencilState = VkPipelineDepthStencilStateCreateInfo.New (); +// public VkPipelineMultisampleStateCreateInfo multisampleState = VkPipelineMultisampleStateCreateInfo.New (); + +// NativeList<VkPipelineColorBlendAttachmentState> blendAttachments = new NativeList<VkPipelineColorBlendAttachmentState>(); +// NativeList<VkDynamicState> dynamicStates = new NativeList<VkDynamicState> (); +// public NativeList<VkVertexInputBindingDescription> vertexBindings = new NativeList<VkVertexInputBindingDescription> (); +// public NativeList<VkVertexInputAttributeDescription> vertexAttributes = new NativeList<VkVertexInputAttributeDescription> (); +// public List<ShaderInfo> shaders = new List<ShaderInfo>(); + +// public PipelineLayout Layout; + +// public VkSampleCountFlags Samples { +// get { return multisampleState.rasterizationSamples; } +// } + +// public RenderPass RenderPass { get; private set; } + +// public void SetVertexAttributes (uint binding, params VkFormat[] attribsDesc) { +// uint offset = 0; + +// for (uint i = 0; i < attribsDesc.Length; i++) { +// vertexAttributes.Add (new VkVertexInputAttributeDescription (binding, i, attribsDesc[i], offset)); +// VkFormatSize fs; +// Utils.vkGetFormatSize (attribsDesc[i], out fs); +// offset += fs.blockSizeInBits/8; +// } +// } +// public void AddVertexBinding (uint binding, uint stride, VkVertexInputRate inputRate = VkVertexInputRate.Vertex) { +// vertexBindings.Add (new VkVertexInputBindingDescription (binding, stride, inputRate)); +// } +// public void AddVertexBinding<T> (uint binding, VkVertexInputRate inputRate = VkVertexInputRate.Vertex) { +// vertexBindings.Add (new VkVertexInputBindingDescription (binding, (uint)Marshal.SizeOf<T> (), inputRate)); +// } +// public void AddShader (VkShaderStageFlags _stageFlags, string _spirvPath, string _entryPoint = "main") { +// shaders.Add (new ShaderInfo (_stageFlags, _spirvPath, _entryPoint)); +// } +// /// <summary> +// /// Create a new Pipeline with supplied RenderPass +// /// </summary> +// public PipelineConfig (Device dev, RenderPass renderPass, VkPrimitiveTopology topology = VkPrimitiveTopology.TriangleList, +// VkSampleCountFlags samples = VkSampleCountFlags.Count1) +// { + +// RenderPass = renderPass; +// RenderPass.references++; + +// inputAssemblyState.topology = topology; + +// rasterizationState.polygonMode = VkPolygonMode.Fill; +// rasterizationState.cullMode = (uint)VkCullModeFlags.None; +// rasterizationState.frontFace = VkFrontFace.CounterClockwise; +// rasterizationState.depthClampEnable = False; +// rasterizationState.rasterizerDiscardEnable = False; +// rasterizationState.depthBiasEnable = False; +// rasterizationState.lineWidth = 1.0f; + +// viewportState.viewportCount = 1; +// viewportState.scissorCount = 1; + +// blendAttachments.Add (new VkPipelineColorBlendAttachmentState { +// colorWriteMask = VkColorComponentFlags.R | VkColorComponentFlags.G | VkColorComponentFlags.B | VkColorComponentFlags.A, +// blendEnable = False +// }); + +// dynamicStates.Add (VkDynamicState.Viewport); +// dynamicStates.Add (VkDynamicState.Scissor); + +// depthStencilState.depthTestEnable = True; +// depthStencilState.depthWriteEnable = True; +// depthStencilState.depthCompareOp = VkCompareOp.LessOrEqual; +// depthStencilState.depthBoundsTestEnable = False; +// depthStencilState.back.failOp = VkStencilOp.Keep; +// depthStencilState.back.passOp = VkStencilOp.Keep; +// depthStencilState.back.compareOp = VkCompareOp.Always; +// depthStencilState.stencilTestEnable = False; +// depthStencilState.front = depthStencilState.back; + +// multisampleState.rasterizationSamples = samples; +// } + +// /// <summary> +// /// Create a new pipeline and the default renderpass for it +// /// </summary> +// public PipelineConfig (Device dev, VkFormat colorFormat, VkFormat depthFormat, +// VkPrimitiveTopology topology = VkPrimitiveTopology.TriangleList, +// VkSampleCountFlags samples = VkSampleCountFlags.Count1) +// : this (dev, new RenderPass (dev, colorFormat, depthFormat, samples), topology,samples) +// { +// } + +// public unsafe void Activate () { + +// } + +// public void Bind (CommandBuffer cmd) { +// vkCmdBindPipeline (cmd.Handle, bindPoint, handle); +// } +// #region IDisposable Support +// private bool isDisposed = false; // Pour détecter les appels redondants + +// protected virtual void Dispose (bool disposing) { +// if (!isDisposed) { +// if (disposing) { +// blendAttachments.Dispose (); +// dynamicStates.Dispose (); +// vertexBindings.Dispose (); +// vertexAttributes.Dispose (); +// RenderPass.Dispose (); +// Layout.Dispose (); +// } else +// System.Diagnostics.Debug.WriteLine ("A Pipeline has not been disposed."); +// VulkanNative.vkDestroyPipeline (dev.VkDev, handle, IntPtr.Zero); +// isDisposed = true; +// } +// } + +// ~PipelineConfig () { +// Dispose (false); +// } +// public void Dispose () { +// Dispose (true); +// GC.SuppressFinalize (this); +// } +// #endregion +// } +//} diff --git a/vke/src/PipelineLayout.cs b/vke/src/PipelineLayout.cs index 68f7d4b..c1afc79 100644 --- a/vke/src/PipelineLayout.cs +++ b/vke/src/PipelineLayout.cs @@ -30,18 +30,13 @@ using Vulkan; using static Vulkan.VulkanNative; namespace VKE { - - public class PipelineLayout : IDisposable { - internal uint references; + public sealed class PipelineLayout : Activable { internal VkPipelineLayout handle; - internal Device dev; public List<DescriptorSetLayout> DescriptorSetLayouts = new List<DescriptorSetLayout> (); - public NativeList<VkPushConstantRange> PushConstantRanges = new NativeList<VkPushConstantRange> (); + public List<VkPushConstantRange> PushConstantRanges = new List<VkPushConstantRange> (); - public PipelineLayout (Device device) { - dev = device; - } + public PipelineLayout (Device device) : base (device) { } public PipelineLayout (Device device, VkPushConstantRange pushConstantRange, params DescriptorSetLayout[] descriptorSetLayouts) : this (device, descriptorSetLayouts) { PushConstantRanges.Add (pushConstantRange); @@ -61,52 +56,33 @@ namespace VKE { foreach (VkPushConstantRange pcr in pushConstantRanges) PushConstantRanges.Add (pcr); } - public PipelineLayout Activate () { - if (isDisposed) { - isDisposed = false; - GC.ReRegisterForFinalize (this); - PushConstantRanges = new NativeList<VkPushConstantRange> (); - } - VkPipelineLayoutCreateInfo info = VkPipelineLayoutCreateInfo.New (); - VkDescriptorSetLayout[] dsls = DescriptorSetLayouts.Select (dsl => dsl.handle).ToArray (); - if (dsls.Length > 0) { - info.setLayoutCount = (uint)dsls.Length; - info.pSetLayouts = dsls.Pin (); - } - if (PushConstantRanges.Count > 0) { - info.pushConstantRangeCount = (uint)PushConstantRanges.Count; - info.pPushConstantRanges = PushConstantRanges.Data; + public override void Activate () { + if (state != ActivableState.Activated) { + VkPipelineLayoutCreateInfo info = VkPipelineLayoutCreateInfo.New (); + VkDescriptorSetLayout[] dsls = DescriptorSetLayouts.Select (dsl => dsl.handle).ToArray (); + + if (dsls.Length > 0) { + info.setLayoutCount = (uint)dsls.Length; + info.pSetLayouts = dsls.Pin (); + } + if (PushConstantRanges.Count > 0) { + info.pushConstantRangeCount = (uint)PushConstantRanges.Count; + info.pPushConstantRanges = PushConstantRanges.Pin(); + } + Utils.CheckResult (vkCreatePipelineLayout (dev.VkDev, ref info, IntPtr.Zero, out handle)); + dsls.Unpin (); + PushConstantRanges.Unpin (); } - Utils.CheckResult (vkCreatePipelineLayout (dev.VkDev, ref info, IntPtr.Zero, out handle)); - dsls.Unpin (); - return this; + base.Activate (); } #region IDisposable Support - private bool isDisposed = false; // Pour détecter les appels redondants - - protected virtual void Dispose (bool disposing) { - if (!isDisposed) { - if (disposing) { - PushConstantRanges.Dispose (); - } else - System.Diagnostics.Debug.WriteLine ("One Pipeline layout was not disposed"); - + protected override void Dispose (bool disposing) { + if (!disposing) + System.Diagnostics.Debug.WriteLine ("VKE Activable PipelineLayout disposed by finalizer"); + if (state == ActivableState.Activated) vkDestroyPipelineLayout (dev.VkDev, handle, IntPtr.Zero); - isDisposed = true; - } - } - - ~PipelineLayout() { - Dispose(false); - } - public void Dispose () { - if (references>0) - references--; - if (references>0) - return; - Dispose (true); - GC.SuppressFinalize(this); + base.Dispose (disposing); } #endregion } diff --git a/vke/src/RenderPass.cs b/vke/src/RenderPass.cs index 8e73e10..809edf3 100644 --- a/vke/src/RenderPass.cs +++ b/vke/src/RenderPass.cs @@ -30,16 +30,75 @@ using Vulkan; using static Vulkan.VulkanNative; namespace VKE { - public class RenderPass : IDisposable { - internal uint references; - internal VkRenderPass handle; - internal Device dev; - - internal NativeList<VkAttachmentDescription> attachments = new NativeList<VkAttachmentDescription> (); - public NativeList<VkClearValue> ClearValues = new NativeList<VkClearValue> (); + public class RenderPass : Activable { + internal VkRenderPass handle; + internal List<VkAttachmentDescription> attachments = new List<VkAttachmentDescription> (); + public List<VkClearValue> ClearValues = new List<VkClearValue> (); internal List<SubPass> subpasses = new List<SubPass> (); - NativeList<VkSubpassDependency> dependencies = new NativeList<VkSubpassDependency> (); + List<VkSubpassDependency> dependencies = new List<VkSubpassDependency> (); + + #region CTORS + public RenderPass (Device device) : base(device) { } + + /// <summary> + /// Create default renderpass with one color and one depth attachments + /// </summary> + public RenderPass (Device device, VkFormat colorFormat, VkFormat depthFormat, VkSampleCountFlags samples = VkSampleCountFlags.Count1) + : this (device){ + + AddAttachment (colorFormat, (samples == VkSampleCountFlags.Count1) ? VkImageLayout.PresentSrcKHR : VkImageLayout.ColorAttachmentOptimal, samples); + AddAttachment (depthFormat, VkImageLayout.DepthStencilAttachmentOptimal, samples); + + ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.2f) }); + ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) }); + + SubPass subpass0 = new SubPass (); + + subpass0.AddColorReference (0, VkImageLayout.ColorAttachmentOptimal); + subpass0.SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal); + + if (samples != VkSampleCountFlags.Count1) { + AddAttachment (colorFormat, VkImageLayout.PresentSrcKHR, VkSampleCountFlags.Count1); + ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.2f) }); + subpass0.AddResolveReference (2, VkImageLayout.ColorAttachmentOptimal); + } + + + AddSubpass (subpass0); + + AddDependency (VulkanNative.SubpassExternal, 0, + VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, + VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); + AddDependency (0, 1, + VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, + VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); + } + #endregion + + public override void Activate () { + if (state != ActivableState.Activated) { + List<VkSubpassDescription> spDescs = new List<VkSubpassDescription> (); + foreach (SubPass sp in subpasses) + spDescs.Add (sp.SubpassDescription); + + VkRenderPassCreateInfo renderPassInfo = VkRenderPassCreateInfo.New (); + renderPassInfo.attachmentCount = (uint)attachments.Count; + renderPassInfo.pAttachments = attachments.Pin (); + renderPassInfo.subpassCount = (uint)spDescs.Count; + renderPassInfo.pSubpasses = spDescs.Pin (); + renderPassInfo.dependencyCount = (uint)dependencies.Count; + renderPassInfo.pDependencies = dependencies.Pin (); + + handle = dev.CreateRenderPass (renderPassInfo); + + attachments.Unpin (); + spDescs.Unpin (); + dependencies.Unpin (); + } + base.Activate (); + } + public void AddAttachment (VkFormat format, VkImageLayout finalLayout, VkSampleCountFlags samples = VkSampleCountFlags.Count1, @@ -93,72 +152,6 @@ namespace VKE { public void AddSubpass (SubPass subPass) { subpasses.Add (subPass); } - public RenderPass (Device device) { - dev = device; - } - /// <summary> - /// Create default renderpass with one color and one depth attachments - /// </summary> - public RenderPass (Device device, VkFormat colorFormat, VkFormat depthFormat, VkSampleCountFlags samples = VkSampleCountFlags.Count1) - : this (device){ - - AddAttachment (colorFormat, (samples == VkSampleCountFlags.Count1) ? VkImageLayout.PresentSrcKHR : VkImageLayout.ColorAttachmentOptimal, samples); - AddAttachment (depthFormat, VkImageLayout.DepthStencilAttachmentOptimal, samples); - - ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.2f) }); - ClearValues.Add (new VkClearValue { depthStencil = new VkClearDepthStencilValue (1.0f, 0) }); - - SubPass subpass0 = new SubPass (); - - subpass0.AddColorReference (0, VkImageLayout.ColorAttachmentOptimal); - subpass0.SetDepthReference (1, VkImageLayout.DepthStencilAttachmentOptimal); - - if (samples != VkSampleCountFlags.Count1) { - AddAttachment (colorFormat, VkImageLayout.PresentSrcKHR, VkSampleCountFlags.Count1); - ClearValues.Add (new VkClearValue { color = new VkClearColorValue (0.0f, 0.0f, 0.2f) }); - subpass0.AddResolveReference (2, VkImageLayout.ColorAttachmentOptimal); - } - - - AddSubpass (subpass0); - - AddDependency (VulkanNative.SubpassExternal, 0, - VkPipelineStageFlags.BottomOfPipe, VkPipelineStageFlags.ColorAttachmentOutput, - VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite); - AddDependency (0, 1, - VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, - VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead); - - Activate (); - } - public void Activate () { - if (isDisposed) { - GC.ReRegisterForFinalize (this); - isDisposed = false; - } - using (NativeList<VkSubpassDescription> spDescs = new NativeList<VkSubpassDescription> ((uint)subpasses.Count)) { - foreach (SubPass sp in subpasses) - spDescs.Add (sp.SubpassDescription); - - VkRenderPassCreateInfo renderPassInfo = VkRenderPassCreateInfo.New (); - renderPassInfo.attachmentCount = attachments.Count; - renderPassInfo.pAttachments = attachments.Data; - renderPassInfo.subpassCount = spDescs.Count; - renderPassInfo.pSubpasses = spDescs.Data; - renderPassInfo.dependencyCount = dependencies.Count; - renderPassInfo.pDependencies = dependencies.Data; - - handle = dev.CreateRenderPass (renderPassInfo); - } - } - - //public Framebuffer CreateFramebuffer (SwapChain swapChain) { - // Framebuffer fb; - - // return fb; - //} - - /// <summary> /// Begin Render pass with framebuffer extent dimensions /// </summary> @@ -174,42 +167,25 @@ namespace VKE { info.renderPass = handle; info.renderArea.extent.width = width; info.renderArea.extent.height = height; - info.clearValueCount = ClearValues.Count; - info.pClearValues = (VkClearValue*) ClearValues.Data.ToPointer(); + info.clearValueCount = (uint)ClearValues.Count; + info.pClearValues = ClearValues.Pin (); info.framebuffer = frameBuffer.handle; vkCmdBeginRenderPass (cmd.Handle, ref info, VkSubpassContents.Inline); + + ClearValues.Unpin (); } public void End (CommandBuffer cmd) { vkCmdEndRenderPass (cmd.Handle); } #region IDisposable Support - private bool isDisposed = false; // Pour détecter les appels redondants - - protected virtual void Dispose (bool disposing) { - if (!isDisposed) { - if (disposing) { - attachments.Dispose (); - ClearValues.Dispose (); - dependencies.Dispose (); - } else - System.Diagnostics.Debug.WriteLine ("A Renderpass has not been disposed."); + protected override void Dispose (bool disposing) { + if (!disposing) + System.Diagnostics.Debug.WriteLine ("VKE Activable RenderPass disposed by finalizer"); + if (state == ActivableState.Activated) dev.DestroyRenderPass (handle); - isDisposed = true; - } - } - - ~RenderPass () { - Dispose (false); - } - public void Dispose () { - if (references>0) - references--; - if (references>0) - return; - Dispose (true); - GC.SuppressFinalize (this); + base.Dispose (disposing); } #endregion } diff --git a/vke/src/Resource.cs b/vke/src/Resource.cs index 2c87e50..22b7375 100644 --- a/vke/src/Resource.cs +++ b/vke/src/Resource.cs @@ -6,9 +6,7 @@ using Vulkan; using static Vulkan.VulkanNative; namespace VKE { - public abstract class Resource : IDisposable { - internal uint references; - protected Device dev; + public abstract class Resource : Activable { protected VkDeviceMemory vkMemory; protected UInt64 deviceMemSize; protected IntPtr mappedData; @@ -17,21 +15,13 @@ namespace VKE { public IntPtr MappedData => mappedData; public UInt64 AllocatedDeviceMemorySize => deviceMemSize; - protected Resource (Device device, VkMemoryPropertyFlags memoryFlags) { - dev = device; + protected Resource (Device device, VkMemoryPropertyFlags memoryFlags) : base (device) { MemoryFlags = memoryFlags; } protected abstract VkMemoryRequirements getMemoryRequirements (); protected abstract void bindMemory (ulong offset); - //memory is not allocated and bindind in here because Activate may be called in ctor of - //derrived classes, and appropriate virtual allocateMemory and bindMemory must be called - public virtual void Activate () { - if (isDisposed) - GC.ReRegisterForFinalize (this); - } - protected void allocateMemory () { VkMemoryRequirements memReqs = getMemoryRequirements (); VkMemoryAllocateInfo memInfo = VkMemoryAllocateInfo.New (); @@ -68,34 +58,16 @@ namespace VKE { vkFlushMappedMemoryRanges (dev.VkDev, 1, ref range); } - #region IDisposable Support - protected bool isDisposed; - - protected virtual void Dispose (bool disposing) { - if (!isDisposed) { - if (disposing) { - // TODO: supprimer l'état managé (objets managés). - } - - if (mappedData != IntPtr.Zero) - Unmap (); - vkFreeMemory (dev.VkDev, vkMemory, IntPtr.Zero); - - isDisposed = true; - } - } - - ~Resource () { - Dispose (false); - } - - public void Dispose () { - if (references>0) - references--; - if (references>0) - return; - Dispose (true); - GC.SuppressFinalize (this); + #region IDisposable Support + protected override void Dispose (bool disposing) { + if (!disposing) + System.Diagnostics.Debug.WriteLine ("VKE Activable object disposed by finalizer"); + if (state == ActivableState.Activated) { + if (mappedData != IntPtr.Zero) + Unmap (); + vkFreeMemory (dev.VkDev, vkMemory, IntPtr.Zero); + } + base.Dispose (disposing); } #endregion } diff --git a/vke/src/ShaderInfo.cs b/vke/src/ShaderInfo.cs new file mode 100644 index 0000000..f346195 --- /dev/null +++ b/vke/src/ShaderInfo.cs @@ -0,0 +1,69 @@ +// +// FrameBuffer.cs +// +// Author: +// Jean-Philippe Bruyère <jp_bruyere@hotmail.com> +// +// 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. +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Vulkan; +using static Vulkan.VulkanNative; + +namespace VKE { + public class ShaderInfo : IDisposable { + public VkShaderStageFlags StageFlags; + public string SpirvPath; + public FixedUtf8String EntryPoint; + + public ShaderInfo (VkShaderStageFlags _stageFlags, string _spirvPath, string _entryPoint = "main") { + StageFlags = _stageFlags; + SpirvPath = _spirvPath; + EntryPoint = new FixedUtf8String (_entryPoint); + } + + public VkPipelineShaderStageCreateInfo GetStageCreateInfo (Device dev) { + return new VkPipelineShaderStageCreateInfo { + sType = VkStructureType.PipelineShaderStageCreateInfo, + stage = StageFlags, + pName = EntryPoint, + module = dev.LoadSPIRVShader (SpirvPath), + }; + } + + #region IDisposable Support + private bool disposedValue = false; // Pour détecter les appels redondants + + protected virtual void Dispose (bool disposing) { + if (!disposedValue) { + if (disposing) + EntryPoint.Dispose (); + + disposedValue = true; + } + } + public void Dispose () { + Dispose (true); + } + #endregion + } +} |