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
Y1NmvOw`VI=M*si-07*qoM6N<$f>b@31poj5
literal 0
HcmV?d00001
diff --git a/samples/screenShots/Triangle.png b/samples/screenShots/Triangle.png
new file mode 100644
index 0000000000000000000000000000000000000000..0340b5668cb166474d9aeb554cebdd9ea2a51aa6
GIT binary patch
literal 7393
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
literal 0
HcmV?d00001
diff --git a/vke.net.sln b/vke.net.sln
index 1ce579e..f8baa1e 100644
--- a/vke.net.sln
+++ b/vke.net.sln
@@ -8,11 +8,12 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "global", "global", "{7285454A-930F-4536-AB84-C076B44C0C80}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
+ README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "addons", "addons", "{4AA67AB0-C331-4CB2-9C00-B74F5DE31658}"
ProjectSection(SolutionItems) = preProject
- addons/Directory.Build.props = "Directory.Build.props"
+ addons\Directory.Build.props = addons\Directory.Build.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvironmentPipeline", "addons\EnvironmentPipeline\EnvironmentPipeline.csproj", "{F04C3F79-2E08-4D35-A804-43039DCB7F5E}"
@@ -25,9 +26,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VkvgPipeline", "addons\Vkvg
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{16439374-B8DB-4643-8116-EB3358B49A12}"
ProjectSection(SolutionItems) = preProject
- samples/Directory.Build.props = "Directory.Build.props"
+ samples\Directory.Build.props = samples\Directory.Build.props
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClearScreen", "samples\ClearScreen\ClearScreen.csproj", "{1D2A1968-8F04-4BE0-B03A-573F1F68AB66}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle", "samples\Triangle\Triangle.csproj", "{124152F8-FAE6-4D4B-87B9-6074DD365E9B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Textured", "samples\Textured\Textured.csproj", "{1B2DF710-E500-49E5-8802-EBA71A05E827}"
@@ -159,6 +162,16 @@ Global
{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU
{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.Release|Any CPU.Build.0 = Release|Any CPU
{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.DebugCrow|Any CPU.ActiveCfg = Debug|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.DebugCrow|Any CPU.Build.0 = Debug|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.ReleaseSpirVTasks|Any CPU.ActiveCfg = Debug|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.ReleaseSpirVTasks|Any CPU.Build.0 = Debug|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.ActiveCfg = Release|Any CPU
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66}.BuildPackages|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FEF3AF30-5B88-4D3C-8BD7-8734200E0D1E} = {4AA67AB0-C331-4CB2-9C00-B74F5DE31658}
@@ -173,6 +186,7 @@ Global
{D9A41382-444E-44ED-B638-3D8F06F2FBC2} = {16439374-B8DB-4643-8116-EB3358B49A12}
{124152F8-FAE6-4D4B-87B9-6074DD365E9B} = {16439374-B8DB-4643-8116-EB3358B49A12}
{7EB2430B-6BC0-4AE9-B1FA-57C3DB2AE1C5} = {16439374-B8DB-4643-8116-EB3358B49A12}
+ {1D2A1968-8F04-4BE0-B03A-573F1F68AB66} = {16439374-B8DB-4643-8116-EB3358B49A12}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
diff --git a/vke/src/VkWindow.cs b/vke/src/VkWindow.cs
index e2e2fb4..acb23eb 100644
--- a/vke/src/VkWindow.cs
+++ b/vke/src/VkWindow.cs
@@ -35,7 +35,7 @@ namespace vke {
protected CommandPool cmdPool;
protected CommandBuffer[] cmds;
protected VkSemaphore[] drawComplete;
- protected VkFence drawFence;
+ protected Fence drawFence;
protected uint fps { get; private set; }
protected bool updateViewRequested = true;
@@ -173,7 +173,7 @@ namespace vke {
cmds = new CommandBuffer[swapChain.ImageCount];
drawComplete = new VkSemaphore[swapChain.ImageCount];
- drawFence = dev.CreateFence (true);
+ drawFence = new Fence (dev, true, "draw fence");
for (int i = 0; i < swapChain.ImageCount; i++) {
drawComplete[i] = dev.CreateSemaphore ();
@@ -218,8 +218,8 @@ namespace vke {
if (cmds[idx] == null)
return;
- dev.WaitForFence (drawFence);
- dev.ResetFence (drawFence);
+ drawFence.Wait ();
+ drawFence.Reset ();
presentQueue.Submit (cmds[idx], swapChain.presentComplete, drawComplete[idx], drawFence);
presentQueue.Present (swapChain, drawComplete[idx]);
@@ -393,8 +393,7 @@ namespace vke {
dev.DestroySemaphore (drawComplete[i]);
cmds[i].Free ();
}
- dev.DestroyFence (drawFence);
-
+ drawFence.Dispose ();
swapChain.Dispose ();
vkDestroySurfaceKHR (instance.Handle, hSurf, IntPtr.Zero);
diff --git a/vke/src/base/Activable.cs b/vke/src/base/Activable.cs
index 5fc2a99..2f7edf5 100644
--- a/vke/src/base/Activable.cs
+++ b/vke/src/base/Activable.cs
@@ -41,7 +41,8 @@ namespace vke {
//With the debug utils extension, setting name to vulkan's object ease the debugging.
protected string name;
///
- /// This property has to be implemented in every vulkan object. It must return the correct debug marker info.
+ /// This property has to be implemented in every vulkan object. It must return the correct debug marker info to use
+ /// if VK_EXT_debug_utils extension is enabled.
///
/// The debug marker info.
protected abstract VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo { get; }
@@ -52,11 +53,11 @@ namespace vke {
#region CTOR
protected Activable (Device dev) {
- this.Dev = dev;
- this.name = GetType ().Name;
+ Dev = dev;
+ name = GetType ().Name;
}
protected Activable (Device dev, string name) {
- this.Dev = dev;
+ Dev = dev;
this.name = name;
}
#endregion
@@ -76,7 +77,7 @@ namespace vke {
name.Unpin ();
}
///
- /// Activation of the object, the reference count is incremented.
+ /// Activation of the object, the reference count is incremented and if Debug utils is enabled, name is set.
///
public virtual void Activate () {
references++;
diff --git a/vke/src/base/Buffer.cs b/vke/src/base/Buffer.cs
index 9a86f14..aa25004 100644
--- a/vke/src/base/Buffer.cs
+++ b/vke/src/base/Buffer.cs
@@ -7,33 +7,45 @@ using static Vulkan.Vk;
namespace vke {
- ///
- /// Base class for HostBuffer and GPUBuffer
- ///
- public class Buffer : Resource {
- internal VkBuffer handle;
+ ///
+ /// Base class for managed vulkan buffer objects
+ ///
+ public class Buffer : Resource {
+ internal VkBuffer handle;
protected VkBufferCreateInfo createInfo = VkBufferCreateInfo.New ();
-
- public VkDescriptorBufferInfo Descriptor;
+ /// Native handle of this vulkan buffer.
+ /// The handle.
public VkBuffer Handle => handle;
public VkBufferCreateInfo Infos => createInfo;
+ /// Buffer memory is always linear.
public override bool IsLinar => true;
protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo
=> new VkDebugUtilsObjectNameInfoEXT (VkObjectType.Buffer, handle.Handle);
#region CTORS
- public Buffer (Device device, VkBufferUsageFlags usage, VkMemoryPropertyFlags _memoryPropertyFlags, UInt64 size)
- : base (device, _memoryPropertyFlags) {
-
- createInfo.size = size;
- createInfo.usage = usage;
- createInfo.sharingMode = VkSharingMode.Exclusive;
-
- Activate ();//DONT OVERRIDE Activate in derived classes!!!!
- }
+ ///
+ /// Create a vulkan buffer and automatically activate it. Automatic activation on startup implies to explicitly dispose the buffer.
+ ///
+ /// Logical Device.
+ /// a bitmask specifying allowed usages of the buffer
+ /// Memory property flags.
+ /// Desired size in byte of the buffer to be created.
+ /// value specifying the sharing mode of the buffer when it will be accessed by multiple queue familie
+ public Buffer (Device device, VkBufferUsageFlags usage, VkMemoryPropertyFlags _memoryPropertyFlags, UInt64 size, VkSharingMode sharingMode = VkSharingMode.Exclusive)
+ : base (device, _memoryPropertyFlags) {
+
+ createInfo.size = size;
+ createInfo.usage = usage;
+ createInfo.sharingMode = VkSharingMode.Exclusive;
+
+ Activate ();
+ }
#endregion
- public override void Activate () {
+ ///
+ /// Activate this vulkan buffer. Note that buffers are automatically activated on creation.
+ ///
+ public sealed override void Activate () {
if (state != ActivableState.Activated) {
Utils.CheckResult (vkCreateBuffer (Dev.VkDev, ref createInfo, IntPtr.Zero, out handle));
#if MEMORY_POOLS
@@ -43,11 +55,11 @@ namespace vke {
allocateMemory ();
bindMemory ();
#endif
- SetupDescriptor ();
}
base.Activate ();
- }
+ }
+ #region Implement abstract members of the Resource abstract class.
internal override void updateMemoryRequirements () {
vkGetBufferMemoryRequirements (Dev.VkDev, handle, out memReqs);
}
@@ -59,49 +71,84 @@ namespace vke {
Utils.CheckResult (vkBindBufferMemory (Dev.VkDev, handle, vkMemory, 0));
#endif
}
+ #endregion
- public void SetupDescriptor (ulong size = WholeSize, ulong offset = 0) {
- Descriptor.buffer = handle;
- Descriptor.range = size;
- Descriptor.offset = offset;
- }
-
- public void CopyTo (CommandBuffer cmd, Image img, VkImageLayout finalLayout = VkImageLayout.ShaderReadOnlyOptimal) {
- img.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal);
-
- VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy {
- imageExtent = img.CreateInfo.extent,
- imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color)
- };
-
- vkCmdCopyBufferToImage (cmd.Handle, handle, img.handle, VkImageLayout.TransferDstOptimal, 1, ref bufferCopyRegion);
+ ///
+ /// Get a default buffer descriptor for the full size with no offset.
+ ///
+ /// the vulkan buffer descriptor
+ public VkDescriptorBufferInfo Descriptor { get => GetDescriptor (); }
+ ///
+ /// Get a buffer descriptor.
+ ///
+ /// a vulkan buffer descriptor
+ /// Size in byte of the buffer view
+ /// an offset in the buffer memory at which point this descriptor.
+ public VkDescriptorBufferInfo GetDescriptor (ulong size = WholeSize, ulong offset = 0) =>
+ new VkDescriptorBufferInfo { buffer = handle, range = size, offset = offset };
+
+ ///
+ /// Copy a vulkan buffer to an Image.
+ ///
+ /// a command buffer to handle the operation.
+ /// The Image to copy the buffer to.
+ /// The final layout to setup for the destination image.
+ public void CopyTo (CommandBuffer cmd, Image img, VkImageLayout finalLayout = VkImageLayout.ShaderReadOnlyOptimal) {
+ img.SetLayout (cmd, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal);
+
+ VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy {
+ imageExtent = img.CreateInfo.extent,
+ imageSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color)
+ };
+
+ vkCmdCopyBufferToImage (cmd.Handle, handle, img.handle, VkImageLayout.TransferDstOptimal, 1, ref bufferCopyRegion);
img.SetLayout (cmd, VkImageAspectFlags.Color, finalLayout);
}
- public void CopyTo (CommandBuffer cmd, Buffer buff, ulong size = 0, ulong srcOffset = 0, ulong dstOffset = 0) {
- VkBufferCopy bufferCopy = new VkBufferCopy {
- size = (size == 0) ? AllocatedDeviceMemorySize : size,
- srcOffset = srcOffset,
- dstOffset = dstOffset
- };
- vkCmdCopyBuffer (cmd.Handle, handle, buff.handle, 1, ref bufferCopy);
- }
+ ///
+ /// Copy a vulkan buffer to another buffer.
+ ///
+ /// a command buffer to handle the operation.
+ /// the destination buffer.
+ /// size of the copy operation in byte.
+ /// a source offset for the copy operation.
+ /// an offset in the destination buffer for the copy operation.
+ public void CopyTo (CommandBuffer cmd, Buffer buff, ulong size = 0, ulong srcOffset = 0, ulong dstOffset = 0) {
+ VkBufferCopy bufferCopy = new VkBufferCopy {
+ size = (size == 0) ? AllocatedDeviceMemorySize : size,
+ srcOffset = srcOffset,
+ dstOffset = dstOffset
+ };
+ vkCmdCopyBuffer (cmd.Handle, handle, buff.handle, 1, ref bufferCopy);
+ }
+ ///
+ /// Fill a vulkan buffer memory with an unsinged integer value.
+ ///
+ /// a command buffer to handle the operation.
+ /// an unsigned integer to fill the buffer with.
+ /// size in byte to fill.
+ /// an offset in byte in the buffer for the fill operation.
public void Fill (CommandBuffer cmd, uint data, ulong size = 0, ulong offset = 0) {
vkCmdFillBuffer (cmd.Handle, handle, offset, (size == 0) ? AllocatedDeviceMemorySize : size, data);
}
public override string ToString () {
- return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString("x")}]");
+ return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]");
}
-#region IDisposable Support
+ #region IDisposable Support
+ ///
+ /// Destroy the native handle and set the Activable's state to `Disposed`.
+ ///
+ /// Note that Buffers have to be always explicitly disposed on cleanup.
+ /// If set to true, this object is currently disposed by the user, not the finalizer.
protected override void Dispose (bool disposing) {
if (state == ActivableState.Activated) {
base.Dispose (disposing);
vkDestroyBuffer (Dev.VkDev, handle, IntPtr.Zero);
}
state = ActivableState.Disposed;
- }
-#endregion
+ }
+ #endregion
}
}
diff --git a/vke/src/base/CommandBuffer.cs b/vke/src/base/CommandBuffer.cs
index 9c65dc1..ef85867 100644
--- a/vke/src/base/CommandBuffer.cs
+++ b/vke/src/base/CommandBuffer.cs
@@ -33,8 +33,14 @@ namespace vke {
//State = States.Init;
}
-
- public void Submit (VkQueue queue, VkSemaphore wait = default(VkSemaphore), VkSemaphore signal = default (VkSemaphore), VkFence fence = default(VkFence)) {
+ ///
+ /// Submit an executable command buffer with optional wait and signal semaphores, and an optional fence to be signaled when the commands have been completed.
+ ///
+ /// Queue.
+ /// Wait.
+ /// Signal.
+ /// Fence.
+ public void Submit (VkQueue queue, VkSemaphore wait = default, VkSemaphore signal = default, Fence fence = null) {
VkSubmitInfo submit_info = VkSubmitInfo.New();
IntPtr dstStageMask = Marshal.AllocHGlobal (sizeof(uint));
@@ -58,10 +64,17 @@ namespace vke {
}
Marshal.FreeHGlobal (dstStageMask);
}
+ ///
+ /// Put the command buffer in the recording state.
+ ///
+ /// optional command buffer usage flags.
public void Start (VkCommandBufferUsageFlags usage = 0) {
VkCommandBufferBeginInfo cmdBufInfo = new VkCommandBufferBeginInfo (usage);
Utils.CheckResult (vkBeginCommandBuffer (handle, ref cmdBufInfo));
}
+ ///
+ /// Put the command buffer in the executable state if no errors are present in the recording.
+ ///
public void End () {
Utils.CheckResult (vkEndCommandBuffer (handle));
}
diff --git a/vke/src/base/DescriptorPool.cs b/vke/src/base/DescriptorPool.cs
index 26339f5..2970257 100644
--- a/vke/src/base/DescriptorPool.cs
+++ b/vke/src/base/DescriptorPool.cs
@@ -3,7 +3,6 @@
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
using System.Collections.Generic;
-using System.Xml.Serialization;
using Vulkan;
using static Vulkan.Vk;
@@ -11,20 +10,28 @@ namespace vke {
[Serializable]
public sealed class DescriptorPool : Activable {
internal VkDescriptorPool handle;
- [XmlAttribute]
public uint MaxSets;
- [XmlArrayItem("PoolSize")]
-
- public List PoolSizes = new List ();
+ public List PoolSizes { get; private set; } = new List ();
protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo
=> new VkDebugUtilsObjectNameInfoEXT (VkObjectType.DescriptorPool, handle.Handle);
#region CTORS
DescriptorPool () : base (null) {}
+ ///
+ /// Create a new managed descriptor pool that will be manualy activated after the pool sizes had been populated.
+ ///
+ /// the logical device that create the pool.
+ /// maximum number of descriptor sets that can be allocated from the pool
public DescriptorPool (Device device, uint maxSets = 1) : base (device) {
MaxSets = maxSets;
}
+ ///
+ /// Create and automatically activate a new Descriptor pool with the supplied pool sizes.
+ ///
+ /// the logical device that create the pool.
+ /// maximum number of descriptor sets that can be allocated from the pool
+ /// an array of pool sizes describing descriptor types and counts
public DescriptorPool (Device device, uint maxSets = 1, params VkDescriptorPoolSize[] poolSizes)
: this (device, maxSets) {
@@ -34,7 +41,7 @@ namespace vke {
}
#endregion
- public override void Activate () {
+ public sealed override void Activate () {
if (state != ActivableState.Activated) {
VkDescriptorPoolCreateInfo info = VkDescriptorPoolCreateInfo.New();
info.poolSizeCount = (uint)PoolSizes.Count;
@@ -46,11 +53,12 @@ namespace vke {
}
base.Activate ();
}
-
- ///
- /// Create and allocate a new DescriptorSet
- ///
- public DescriptorSet Allocate (params DescriptorSetLayout[] layouts) {
+ ///
+ /// Allocate a new DescriptorSet from this pool.
+ ///
+ /// A managed descriptor set.
+ /// a variable sized array of descriptor layout(s) to allocate the descriptor for.
+ public DescriptorSet Allocate (params DescriptorSetLayout[] layouts) {
DescriptorSet ds = new DescriptorSet (this, layouts);
Allocate (ds);
return ds;
diff --git a/vke/src/base/DescriptorSet.cs b/vke/src/base/DescriptorSet.cs
index 80c583d..8df8be5 100644
--- a/vke/src/base/DescriptorSet.cs
+++ b/vke/src/base/DescriptorSet.cs
@@ -3,7 +3,7 @@
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System.Collections.Generic;
using Vulkan;
-
+//TODO:
namespace vke {
public class DescriptorSet {
internal VkDescriptorSet handle;
diff --git a/vke/src/base/Device.cs b/vke/src/base/Device.cs
index 56e38fe..65aff0f 100644
--- a/vke/src/base/Device.cs
+++ b/vke/src/base/Device.cs
@@ -97,7 +97,10 @@ namespace vke {
resourceManager = new ResourceManager (this);
#endif
}
-
+ ///
+ /// Creates a new semaphore.
+ ///
+ /// The semaphore native handle
public VkSemaphore CreateSemaphore () {
VkSemaphore tmp;
VkSemaphoreCreateInfo info = VkSemaphoreCreateInfo.New ();
@@ -108,38 +111,14 @@ namespace vke {
vkDestroySemaphore (dev, semaphore, IntPtr.Zero);
semaphore = 0;
}
- public VkFence CreateFence (bool signaled = false) {
- VkFence tmp;
- VkFenceCreateInfo info = VkFenceCreateInfo.New ();
- info.flags = signaled ? VkFenceCreateFlags.Signaled : 0;
- Utils.CheckResult (vkCreateFence (dev, ref info, IntPtr.Zero, out tmp));
- return tmp;
- }
- /// Destroy the fence.
- /// A valid fence handle.
- public void DestroyFence (VkFence fence) {
- vkDestroyFence (dev, fence, IntPtr.Zero);
- fence = 0;
- }
- public void WaitForFence (VkFence fence, ulong timeOut = UInt64.MaxValue) {
- vkWaitForFences (dev, 1, ref fence, 1, timeOut);
- }
- public void ResetFence (VkFence fence) {
- vkResetFences (dev, 1, ref fence);
- }
- public void WaitForFences (VkFence[] fences, ulong timeOut = UInt64.MaxValue) {
- vkWaitForFences (dev, (uint)fences.Length, fences.Pin(), 1, timeOut);
- fences.Unpin ();
- }
- public void ResetFences (params VkFence[] fences) {
- vkResetFences (dev, (uint)fences.Length, fences.Pin());
- fences.Unpin ();
- }
public void DestroyShaderModule (VkShaderModule module) {
vkDestroyShaderModule (VkDev, module, IntPtr.Zero);
module = 0;
}
+ ///
+ /// Wait for this logical device to enter the idle state.
+ ///
public void WaitIdle () {
Utils.CheckResult (vkDeviceWaitIdle (dev));
}
@@ -148,27 +127,8 @@ namespace vke {
Utils.CheckResult (vkCreateRenderPass (dev, ref info, IntPtr.Zero, out renderPass));
return renderPass;
}
- internal VkSwapchainKHR CreateSwapChain (VkSwapchainCreateInfoKHR infos) {
- VkSwapchainKHR newSwapChain;
- Utils.CheckResult (vkCreateSwapchainKHR (dev, ref infos, IntPtr.Zero, out newSwapChain));
- return newSwapChain;
- }
- internal void DestroySwapChain (VkSwapchainKHR swapChain) {
- vkDestroySwapchainKHR (dev, swapChain, IntPtr.Zero);
- }
- unsafe public VkImage[] GetSwapChainImages (VkSwapchainKHR swapchain) {
- uint imageCount = 0;
- Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, IntPtr.Zero));
- if (imageCount == 0)
- throw new Exception ("Swapchain image count is 0.");
- VkImage[] imgs = new VkImage[imageCount];
-
- Utils.CheckResult (vkGetSwapchainImagesKHR (dev, swapchain, out imageCount, imgs.Pin ()));
- imgs.Unpin ();
- return imgs;
- }
- unsafe public VkImageView CreateImageView (VkImage image, VkFormat format, VkImageViewType viewType = VkImageViewType.ImageView2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color) {
+ public VkImageView CreateImageView (VkImage image, VkFormat format, VkImageViewType viewType = VkImageViewType.ImageView2D, VkImageAspectFlags aspectFlags = VkImageAspectFlags.Color) {
VkImageView view;
VkImageViewCreateInfo infos = VkImageViewCreateInfo.New ();
infos.image = image;
diff --git a/vke/src/base/Fence.cs b/vke/src/base/Fence.cs
new file mode 100644
index 0000000..0eb031a
--- /dev/null
+++ b/vke/src/base/Fence.cs
@@ -0,0 +1,82 @@
+// Copyright (c) 2020 Jean-Philippe Bruyère
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Vulkan;
+using static Vulkan.Vk;
+
+namespace vke {
+ ///
+ /// Managed activable fence.
+ ///
+ public class Fence : Activable {
+ internal VkFence handle;
+ VkFenceCreateInfo info = VkFenceCreateInfo.New ();
+
+ public Fence (Device dev, bool signaled = false, string name = "fence") : base (dev, name) {
+ info.flags = signaled ? VkFenceCreateFlags.Signaled : 0;
+ Activate ();
+ }
+
+ protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo
+ => new VkDebugUtilsObjectNameInfoEXT (VkObjectType.Framebuffer, handle.Handle);
+
+ public sealed override void Activate () {
+ if (state != ActivableState.Activated) {
+ Utils.CheckResult (vkCreateFence (Dev.VkDev, ref info, IntPtr.Zero, out handle));
+ }
+ base.Activate ();
+ }
+ ///
+ /// Wait this fence to become signaled.
+ ///
+ /// Time out before cancelling the wait.
+ public void Wait (ulong timeOut = UInt64.MaxValue) {
+ vkWaitForFences (Dev.VkDev, 1, ref handle, 1, timeOut);
+ }
+ ///
+ /// put this fence in the unsignaled state.
+ ///
+ public void Reset () {
+ vkResetFences (Dev.VkDev, 1, ref handle);
+ }
+
+ public override string ToString () {
+ return string.Format ($"{base.ToString ()}[0x{handle.Handle.ToString ("x")}]");
+ }
+
+ public static implicit operator VkFence (Fence f) => f == null ? 0 : f.handle;
+
+ #region IDisposable Support
+ protected override void Dispose (bool disposing) {
+ if (state == ActivableState.Activated)
+ vkDestroyFence (Dev.VkDev, handle, IntPtr.Zero);
+ if (!disposing)
+ System.Diagnostics.Debug.WriteLine ("VKE Activable object disposed by finalizer");
+ base.Dispose (disposing);
+ }
+ #endregion
+ }
+
+
+ public class Fences : Collection, IDisposable {
+ public void Wait (ulong timeOut = UInt64.MaxValue) {
+ VkFence[] fences = Items.Cast ().ToArray ();
+ vkWaitForFences (Items[0].Dev.VkDev, (uint)Count, fences.Pin (), 1, timeOut);
+ fences.Unpin ();
+ }
+ public void Reset () {
+ VkFence[] fences = Items.Cast ().ToArray ();
+ vkResetFences (Items[0].Dev.VkDev, (uint)Count, fences.Pin ());
+ fences.Unpin ();
+ }
+
+ public void Dispose () {
+ foreach (Fence f in Items)
+ f.Dispose ();
+ ClearItems ();
+ }
+ }
+}
diff --git a/vke/src/base/FrameBuffer.cs b/vke/src/base/FrameBuffer.cs
index 94a69b9..82f214e 100644
--- a/vke/src/base/FrameBuffer.cs
+++ b/vke/src/base/FrameBuffer.cs
@@ -10,27 +10,30 @@ using static Vulkan.Vk;
namespace vke {
- public class FrameBuffer : Activable {
- internal VkFramebuffer handle;
- RenderPass renderPass;
-
+ ///
+ /// Managed activable for one Frame buffer
+ ///
+ public class FrameBuffer : Activable {
+ internal VkFramebuffer handle;
+ RenderPass renderPass;
+
public List attachments = new List ();
- VkFramebufferCreateInfo createInfo = VkFramebufferCreateInfo.New();
+ VkFramebufferCreateInfo createInfo = VkFramebufferCreateInfo.New ();
- public uint Width => createInfo.width;
- public uint Height => createInfo.height;
- public uint Layers => createInfo.layers;
+ public uint Width => createInfo.width;
+ public uint Height => createInfo.height;
+ public uint Layers => createInfo.layers;
protected override VkDebugUtilsObjectNameInfoEXT DebugUtilsInfo
=> new VkDebugUtilsObjectNameInfoEXT (VkObjectType.Framebuffer, handle.Handle);
#region CTORS
- public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, uint _layers = 1) : base(_renderPass.Dev) {
- renderPass = _renderPass;
- createInfo.width = _width;
- createInfo.height = _height;
- createInfo.layers = _layers;
- createInfo.renderPass = renderPass.handle;
- }
+ public FrameBuffer (RenderPass _renderPass, uint _width, uint _height, uint _layers = 1) : base (_renderPass.Dev) {
+ renderPass = _renderPass;
+ createInfo.width = _width;
+ createInfo.height = _height;
+ createInfo.layers = _layers;
+ createInfo.renderPass = renderPass.handle;
+ }
///