コード例 #1
0
        /// <summary>
        /// Records a buffer image barrier
        /// </summary>
        /// <returns>this</returns>
        public void BufferMemoryBarrier(Buffer buffer,
                                        VkAccessFlag srcAccess,
                                        uint srcQueue,
                                        VkAccessFlag dstAccess,
                                        uint dstQueue = Vulkan.QueueFamilyIgnored,
                                        VkPipelineStageFlag srcStage = VkPipelineStageFlag.AllCommands,
                                        VkPipelineStageFlag dstStage = VkPipelineStageFlag.AllCommands,
                                        VkDependencyFlag depFlag     = VkDependencyFlag.None,
                                        ulong offset = 0, ulong size = 0)
        {
            var temp = new VkBufferMemoryBarrier()
            {
                SType               = VkStructureType.BufferMemoryBarrier,
                PNext               = IntPtr.Zero,
                SrcAccessMask       = srcAccess,
                DstAccessMask       = dstAccess,
                Buffer              = buffer.Handle,
                SrcQueueFamilyIndex = srcQueue,
                DstQueueFamilyIndex = dstQueue,
                Offset              = offset,
                Size = size == 0 ? buffer.Size - offset : size
            };

            PipelineBarrier(srcStage, dstStage, depFlag, default(VkMemoryBarrier), temp,
                            default(VkImageMemoryBarrier));
        }
コード例 #2
0
        public void Barrier(PipelineStage srcStage, PipelineStage dstStage, BufferMemoryBarrier[] bufferBarriers, ImageMemoryBarrier[] imageBarriers)
        {
            if (locked)
            {
                var bufferBarrier = new VkBufferMemoryBarrier[bufferBarriers == null ? 0 : bufferBarriers.Length];
                if (bufferBarriers != null)
                {
                    for (int i = 0; i < bufferBarrier.Length; i++)
                    {
                        bufferBarrier[i] = new VkBufferMemoryBarrier()
                        {
                            sType  = VkStructureType.StructureTypeBufferMemoryBarrier,
                            buffer = bufferBarriers[i].Buffer.hndl,
                            srcQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, bufferBarriers[i].SrcFamily),
                            dstQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, bufferBarriers[i].DstFamily),
                            srcAccessMask       = (VkAccessFlags)bufferBarriers[i].Accesses,
                            dstAccessMask       = (VkAccessFlags)bufferBarriers[i].Stores,
                            offset = bufferBarriers[i].Offset,
                            size   = bufferBarriers[i].Size,
                        };
                    }
                }

                var imageBarrier = new VkImageMemoryBarrier[imageBarriers == null ? 0 : imageBarriers.Length];
                if (imageBarriers != null)
                {
                    for (int i = 0; i < imageBarrier.Length; i++)
                    {
                        imageBarrier[i] = new VkImageMemoryBarrier()
                        {
                            sType               = VkStructureType.StructureTypeImageMemoryBarrier,
                            oldLayout           = (VkImageLayout)imageBarriers[i].OldLayout,
                            newLayout           = (VkImageLayout)imageBarriers[i].NewLayout,
                            image               = imageBarriers[i].Image.hndl,
                            srcQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, imageBarriers[i].SrcFamily),
                            dstQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, imageBarriers[i].DstFamily),
                            srcAccessMask       = (VkAccessFlags)imageBarriers[i].Accesses,
                            dstAccessMask       = (VkAccessFlags)imageBarriers[i].Stores,
                            subresourceRange    = new VkImageSubresourceRange()
                            {
                                aspectMask     = (imageBarriers[i].Image.Format == ImageFormat.Depth32f ? VkImageAspectFlags.ImageAspectDepthBit : VkImageAspectFlags.ImageAspectColorBit),
                                baseArrayLayer = imageBarriers[i].BaseArrayLayer,
                                baseMipLevel   = imageBarriers[i].BaseMipLevel,
                                layerCount     = imageBarriers[i].LayerCount,
                                levelCount     = imageBarriers[i].LevelCount,
                            },
                        };
                    }
                }
                var imageBarrier_ptr  = imageBarrier.Pointer();
                var bufferBarrier_ptr = bufferBarrier.Pointer();
                vkCmdPipelineBarrier(hndl, (VkPipelineStageFlags)srcStage, (VkPipelineStageFlags)dstStage, 0, 0, IntPtr.Zero, (uint)bufferBarrier.Length, bufferBarrier_ptr, (uint)imageBarrier.Length, imageBarrier_ptr);
                IsEmpty = false;
            }
            else
            {
                throw new Exception("Command buffer not built.");
            }
        }
コード例 #3
0
 /// <summary>
 /// To record a pipeline barrier, call:
 /// </summary>
 /// <param name="srcStageMask">is a bitmask of <c>VkPipelineStageFlagBits</c> specifying the <a href='https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-pipeline-stages-masks'> source stage mask</a>.</param>
 /// <param name="dstStageMask">is a bitmask of <c>VkPipelineStageFlagBits</c> specifying the <a href='https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-pipeline-stages-masks'> destination stage mask</a>.</param>
 /// <param name="dependencyFlags">is a bitmask of <c>VkDependencyFlagBits</c> specifying how execution and memory dependencies are formed.</param>
 /// <param name="barrier">is a pointer to an array of <see cref="VkMemoryBarrier"/> structures.</param>
 /// <param name="bufferBarrier">is a pointer to an array of <see cref="VkBufferMemoryBarrier"/> structures.</param>
 /// <param name="imageBarrier">is a pointer to an array of <see cref="VkImageMemoryBarrier"/> structures.</param>
 public void PipelineBarrier(VkPipelineStageFlag srcStageMask,
                             VkPipelineStageFlag dstStageMask,
                             VkDependencyFlag dependencyFlags, VkMemoryBarrier barrier = default(VkMemoryBarrier),
                             VkBufferMemoryBarrier bufferBarrier = default(VkBufferMemoryBarrier),
                             VkImageMemoryBarrier imageBarrier   = default(VkImageMemoryBarrier))
 {
     unsafe
     {
         VkCommandBuffer.vkCmdPipelineBarrier(Handle, srcStageMask, dstStageMask, dependencyFlags,
                                              barrier.SType != VkStructureType.BufferMemoryBarrier ? 0 : 1u, &barrier,
                                              bufferBarrier.SType != VkStructureType.BufferMemoryBarrier ? 0 : 1u, &bufferBarrier,
                                              imageBarrier.SType != VkStructureType.ImageMemoryBarrier ? 0 : 1u, &imageBarrier);
     }
 }
コード例 #4
0
        public void WaitEvents(List <Event> events, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
                               List <MemoryBarrier> memoryBarriers, List <BufferMemoryBarrier> bufferMemoryBarriers, List <ImageMemoryBarrier> imageMemoryBarriers)
        {
            unsafe
            {
                var eventsNative = stackalloc VkEvent[events.Count];
                Interop.Marshal <VkEvent, Event>(events, eventsNative);

                int mbCount = 0;
                int bbCount = 0;
                int ibCount = 0;

                if (memoryBarriers != null)
                {
                    mbCount = memoryBarriers.Count;
                }
                if (bufferMemoryBarriers != null)
                {
                    bbCount = bufferMemoryBarriers.Count;
                }
                if (imageMemoryBarriers != null)
                    ibCount = imageMemoryBarriers.Count; }

                var mbNative = stackalloc VkMemoryBarrier[mbCount];
                var bbNative = stackalloc VkBufferMemoryBarrier[bbCount];
                var ibNative = stackalloc VkImageMemoryBarrier[ibCount];

                for (int i = 0; i < mbCount; i++)
                {
                    var mb = memoryBarriers[i];
                    mbNative[i]               = new VkMemoryBarrier();
                    mbNative[i].sType         = VkStructureType.MemoryBarrier;
                    mbNative[i].srcAccessMask = mb.srcAccessMask;
                    mbNative[i].dstAccessMask = mb.dstAccessMask;
                }

                for (int i = 0; i < bbCount; i++)
                {
                    var bb = bufferMemoryBarriers[i];
                    bbNative[i]                     = new VkBufferMemoryBarrier();
                    bbNative[i].sType               = VkStructureType.BufferMemoryBarrier;
                    bbNative[i].srcAccessMask       = bb.srcAccessMask;
                    bbNative[i].dstAccessMask       = bb.dstAccessMask;
                    bbNative[i].srcQueueFamilyIndex = bb.srcQueueFamilyIndex;
                    bbNative[i].dstQueueFamilyIndex = bb.dstQueueFamilyIndex;
                    bbNative[i].buffer              = bb.buffer.Native;
                    bbNative[i].offset              = bb.offset;
                    bbNative[i].size                = bb.size;
                }

                for (int i = 0; i < ibCount; i++)
                {
                    var ib = imageMemoryBarriers[i];
                    ibNative[i]                     = new VkImageMemoryBarrier();
                    ibNative[i].sType               = VkStructureType.ImageMemoryBarrier;
                    ibNative[i].srcAccessMask       = ib.srcAccessMask;
                    ibNative[i].dstAccessMask       = ib.dstAccessMask;
                    ibNative[i].oldLayout           = ib.oldLayout;
                    ibNative[i].newLayout           = ib.newLayout;
                    ibNative[i].srcQueueFamilyIndex = ib.srcQueueFamilyIndex;
                    ibNative[i].dstQueueFamilyIndex = ib.dstQueueFamilyIndex;
                    ibNative[i].image               = ib.image.Native;
                    ibNative[i].subresourceRange    = ib.subresourceRange;
                }

                Device.Commands.cmdWaitEvents(commandBuffer,
                                              (uint)events.Count, (IntPtr)eventsNative,
                                              srcStageMask, dstStageMask,
                                              (uint)mbCount, (IntPtr)mbNative,
                                              (uint)bbCount, (IntPtr)bbNative,
                                              (uint)ibCount, (IntPtr)ibNative);
            }
コード例 #5
0
        /// <summary>
        /// Explicitly recreate buffer with given data. Usually called after a <see cref="GraphicsDevice"/> reset.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataPointer"></param>
        public unsafe void Recreate(IntPtr dataPointer)
        {
            var createInfo = new VkBufferCreateInfo
            {
                sType = VkStructureType.BufferCreateInfo,
                size  = (ulong)bufferDescription.SizeInBytes,
                flags = VkBufferCreateFlags.None,
            };

            createInfo.usage |= VkBufferUsageFlags.TransferSrc;

            // We always fill using transfer
            //if (bufferDescription.Usage != GraphicsResourceUsage.Immutable)
            createInfo.usage |= VkBufferUsageFlags.TransferDst;

            if (Usage == GraphicsResourceUsage.Staging)
            {
                NativeAccessMask         = VkAccessFlags.HostRead | VkAccessFlags.HostWrite;
                NativePipelineStageMask |= VkPipelineStageFlags.Host;
            }
            else
            {
                if ((ViewFlags & BufferFlags.VertexBuffer) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.VertexBuffer;
                    NativeAccessMask        |= VkAccessFlags.VertexAttributeRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexInput;
                }

                if ((ViewFlags & BufferFlags.IndexBuffer) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.IndexBuffer;
                    NativeAccessMask        |= VkAccessFlags.IndexRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexInput;
                }

                if ((ViewFlags & BufferFlags.ConstantBuffer) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.UniformBuffer;
                    NativeAccessMask        |= VkAccessFlags.UniformRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader;
                }

                if ((ViewFlags & BufferFlags.ShaderResource) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.UniformTexelBuffer;
                    NativeAccessMask        |= VkAccessFlags.ShaderRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader;

                    if ((ViewFlags & BufferFlags.UnorderedAccess) != 0)
                    {
                        createInfo.usage |= VkBufferUsageFlags.StorageTexelBuffer;
                        NativeAccessMask |= VkAccessFlags.ShaderWrite;
                    }
                }
            }

            // Create buffer
            vkCreateBuffer(GraphicsDevice.NativeDevice, &createInfo, null, out NativeBuffer);

            // Allocate memory
            var memoryProperties = VkMemoryPropertyFlags.DeviceLocal;

            if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic)
            {
                memoryProperties = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent;
            }

            vkGetBufferMemoryRequirements(GraphicsDevice.NativeDevice, NativeBuffer, out var memoryRequirements);

            AllocateMemory(memoryProperties, memoryRequirements);

            if (NativeMemory != VkDeviceMemory.Null)
            {
                vkBindBufferMemory(GraphicsDevice.NativeDevice, NativeBuffer, NativeMemory, 0);
            }

            if (SizeInBytes > 0)
            {
                // Begin copy command buffer
                var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo
                {
                    sType              = VkStructureType.CommandBufferAllocateInfo,
                    commandPool        = GraphicsDevice.NativeCopyCommandPool,
                    commandBufferCount = 1,
                    level              = VkCommandBufferLevel.Primary
                };
                VkCommandBuffer commandBuffer;

                lock (GraphicsDevice.QueueLock)
                {
                    vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer);
                }

                var beginInfo = new VkCommandBufferBeginInfo {
                    sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit
                };
                vkBeginCommandBuffer(commandBuffer, &beginInfo);

                // Copy to upload buffer
                if (dataPointer != IntPtr.Zero)
                {
                    if (Usage == GraphicsResourceUsage.Dynamic)
                    {
                        void *uploadMemory;
                        vkMapMemory(GraphicsDevice.NativeDevice, NativeMemory, 0, (ulong)SizeInBytes, VkMemoryMapFlags.None, &uploadMemory);
                        Utilities.CopyMemory((IntPtr)uploadMemory, dataPointer, SizeInBytes);
                        vkUnmapMemory(GraphicsDevice.NativeDevice, NativeMemory);
                    }
                    else
                    {
                        var      sizeInBytes = bufferDescription.SizeInBytes;
                        VkBuffer uploadResource;
                        int      uploadOffset;
                        var      uploadMemory = GraphicsDevice.AllocateUploadBuffer(sizeInBytes, out uploadResource, out uploadOffset);

                        Utilities.CopyMemory(uploadMemory, dataPointer, sizeInBytes);

                        // Barrier
                        var memoryBarrier = new VkBufferMemoryBarrier(uploadResource, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, (ulong)uploadOffset, (ulong)sizeInBytes);
                        vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &memoryBarrier, 0, null);

                        // Copy
                        var bufferCopy = new VkBufferCopy
                        {
                            srcOffset = (uint)uploadOffset,
                            dstOffset = 0,
                            size      = (uint)sizeInBytes
                        };
                        vkCmdCopyBuffer(commandBuffer, uploadResource, NativeBuffer, 1, &bufferCopy);
                    }
                }
                else
                {
                    vkCmdFillBuffer(commandBuffer, NativeBuffer, 0, (uint)bufferDescription.SizeInBytes, 0);
                }

                // Barrier
                var bufferMemoryBarrier = new VkBufferMemoryBarrier(NativeBuffer, VkAccessFlags.TransferWrite, NativeAccessMask);
                vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 0, null);

                // Close and submit
                vkEndCommandBuffer(commandBuffer);

                var submitInfo = new VkSubmitInfo
                {
                    sType = VkStructureType.SubmitInfo,
                    commandBufferCount = 1,
                    pCommandBuffers    = &commandBuffer,
                };

                lock (GraphicsDevice.QueueLock)
                {
                    vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, VkFence.Null);
                    vkQueueWaitIdle(GraphicsDevice.NativeCommandQueue);
                    //commandBuffer.Reset(VkCommandBufferResetFlags.None);
                    vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer);
                }

                InitializeViews();
            }
        }
コード例 #6
0
        private unsafe void InitializeImage(DataBox[] dataBoxes)
        {
            // Begin copy command buffer
            var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo
            {
                sType              = VkStructureType.CommandBufferAllocateInfo,
                commandPool        = GraphicsDevice.NativeCopyCommandPool,
                commandBufferCount = 1,
                level              = VkCommandBufferLevel.Primary
            };
            VkCommandBuffer commandBuffer;

            lock (GraphicsDevice.QueueLock)
            {
                vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer);
            }

            var beginInfo = new VkCommandBufferBeginInfo {
                sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit
            };

            vkBeginCommandBuffer(commandBuffer, &beginInfo);

            if (dataBoxes != null && dataBoxes.Length > 0)
            {
                // Buffer-to-image copies need to be aligned to the pixel size and 4 (always a power of 2)
                var blockSize     = Format.IsCompressed() ? NativeFormat.BlockSizeInBytes() : TexturePixelSize;
                var alignmentMask = (blockSize < 4 ? 4 : blockSize) - 1;

                int totalSize = dataBoxes.Length * alignmentMask;
                for (int i = 0; i < dataBoxes.Length; i++)
                {
                    totalSize += dataBoxes[i].SlicePitch;
                }

                VkBuffer uploadResource;
                int      uploadOffset;
                var      uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset);

                // Upload buffer barrier
                var bufferMemoryBarrier = new VkBufferMemoryBarrier(uploadResource, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize);

                // Image barrier
                var initialBarrier = new VkImageMemoryBarrier(NativeImage, new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue), VkAccessFlags.None, VkAccessFlags.TransferWrite, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal);
                vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier);

                // Copy data boxes to upload buffer
                var copies = new VkBufferImageCopy[dataBoxes.Length];
                for (int i = 0; i < copies.Length; i++)
                {
                    var slicePitch = dataBoxes[i].SlicePitch;

                    int arraySlice        = i / MipLevels;
                    int mipSlice          = i % MipLevels;
                    var mipMapDescription = GetMipMapDescription(mipSlice);

                    var alignment = ((uploadOffset + alignmentMask) & ~alignmentMask) - uploadOffset;
                    uploadMemory += alignment;
                    uploadOffset += alignment;

                    Utilities.CopyMemory(uploadMemory, dataBoxes[i].DataPointer, slicePitch);

                    // TODO VULKAN: Check if pitches are valid
                    copies[i] = new VkBufferImageCopy
                    {
                        bufferOffset      = (ulong)uploadOffset,
                        imageSubresource  = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)mipSlice, (uint)arraySlice, 1),
                        bufferRowLength   = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize),
                        bufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch),
                        imageOffset       = new Vortice.Mathematics.Point3(0, 0, 0),
                        imageExtent       = new Vortice.Mathematics.Size3(mipMapDescription.Width, mipMapDescription.Height, mipMapDescription.Depth)
                    };

                    uploadMemory += slicePitch;
                    uploadOffset += slicePitch;
                }

                // Copy from upload buffer to image
                fixed(VkBufferImageCopy *copiesPointer = &copies[0])
                {
                    vkCmdCopyBufferToImage(commandBuffer, uploadResource, NativeImage, VkImageLayout.TransferDstOptimal, (uint)copies.Length, copiesPointer);
                }

                IsInitialized = true;
            }

            // Transition to default layout
            var imageMemoryBarrier = new VkImageMemoryBarrier(NativeImage,
                                                              new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue),
                                                              dataBoxes == null || dataBoxes.Length == 0 ? VkAccessFlags.None : VkAccessFlags.TransferWrite, NativeAccessMask,
                                                              dataBoxes == null || dataBoxes.Length == 0 ? VkImageLayout.Undefined : VkImageLayout.TransferDstOptimal, NativeLayout);

            vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier);

            // Close and submit
            vkEndCommandBuffer(commandBuffer);

            var submitInfo = new VkSubmitInfo
            {
                sType = VkStructureType.SubmitInfo,
                commandBufferCount = 1,
                pCommandBuffers    = &commandBuffer,
            };

            lock (GraphicsDevice.QueueLock)
            {
                vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, VkFence.Null);
                vkQueueWaitIdle(GraphicsDevice.NativeCommandQueue);
                vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer);
            }
        }
コード例 #7
0
        /// <summary>
        /// Explicitly recreate buffer with given data. Usually called after a <see cref="GraphicsDevice"/> reset.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataPointer"></param>
        public unsafe void Recreate(IntPtr dataPointer)
        {
            // capture vertex information for things less than ~512 verts for possible later easy batching
            if (dataPointer != IntPtr.Zero &&
                (ViewFlags == BufferFlags.VertexBuffer && bufferDescription.SizeInBytes <= CaptureVertexBuffersOfSize ||
                 ViewFlags == BufferFlags.IndexBuffer && bufferDescription.SizeInBytes <= CaptureIndexBuffersOfSize))
            {
                VertIndexData = new byte[Description.SizeInBytes];
                fixed(byte *vid = &VertIndexData[0])
                {
                    Utilities.CopyMemory((IntPtr)vid, dataPointer, VertIndexData.Length);
                }
            }
            else
            {
                VertIndexData = null;
            }

            var createInfo = new VkBufferCreateInfo
            {
                sType = VkStructureType.BufferCreateInfo,
                size  = (ulong)bufferDescription.SizeInBytes,
                flags = VkBufferCreateFlags.None,
            };

            createInfo.usage |= VkBufferUsageFlags.TransferSrc;

            // We always fill using transfer
            //if (bufferDescription.Usage != GraphicsResourceUsage.Immutable)
            createInfo.usage |= VkBufferUsageFlags.TransferDst;

            if (Usage == GraphicsResourceUsage.Staging)
            {
                NativeAccessMask         = VkAccessFlags.HostRead | VkAccessFlags.HostWrite;
                NativePipelineStageMask |= VkPipelineStageFlags.Host;
            }
            else
            {
                if ((ViewFlags & BufferFlags.VertexBuffer) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.VertexBuffer;
                    NativeAccessMask        |= VkAccessFlags.VertexAttributeRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexInput;
                }

                if ((ViewFlags & BufferFlags.IndexBuffer) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.IndexBuffer;
                    NativeAccessMask        |= VkAccessFlags.IndexRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexInput;
                }

                if ((ViewFlags & BufferFlags.ConstantBuffer) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.UniformBuffer;
                    NativeAccessMask        |= VkAccessFlags.UniformRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader;
                }

                if ((ViewFlags & BufferFlags.ShaderResource) != 0)
                {
                    createInfo.usage        |= VkBufferUsageFlags.UniformTexelBuffer;
                    NativeAccessMask        |= VkAccessFlags.ShaderRead;
                    NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader;

                    if ((ViewFlags & BufferFlags.UnorderedAccess) != 0)
                    {
                        createInfo.usage |= VkBufferUsageFlags.StorageTexelBuffer;
                        NativeAccessMask |= VkAccessFlags.ShaderWrite;
                    }
                }
            }

            // Create buffer
            vkCreateBuffer(GraphicsDevice.NativeDevice, &createInfo, null, out NativeBuffer);

            // Allocate memory
            var memoryProperties = VkMemoryPropertyFlags.DeviceLocal;

            if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic)
            {
                memoryProperties = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent;
            }

            vkGetBufferMemoryRequirements(GraphicsDevice.NativeDevice, NativeBuffer, out var memoryRequirements);

            AllocateMemory(memoryProperties, memoryRequirements);

            if (NativeMemory != VkDeviceMemory.Null)
            {
                vkBindBufferMemory(GraphicsDevice.NativeDevice, NativeBuffer, NativeMemory, 0);
            }

            if (SizeInBytes > 0)
            {
                // Begin copy command buffer
                var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo
                {
                    sType              = VkStructureType.CommandBufferAllocateInfo,
                    commandPool        = GraphicsDevice.NativeCopyCommandPool,
                    commandBufferCount = 1,
                    level              = VkCommandBufferLevel.Primary
                };
                VkCommandBuffer commandBuffer;

                lock (BufferLocker)
                {
                    vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer);
                }

                var beginInfo = new VkCommandBufferBeginInfo {
                    sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit
                };
                vkBeginCommandBuffer(commandBuffer, &beginInfo);

                GraphicsDevice.UploadBuffer?uploadBuffer = null;

                // Copy to upload buffer
                if (dataPointer != IntPtr.Zero)
                {
                    if (Usage == GraphicsResourceUsage.Dynamic)
                    {
                        void *uploadMemory;
                        vkMapMemory(GraphicsDevice.NativeDevice, NativeMemory, 0, (ulong)SizeInBytes, VkMemoryMapFlags.None, &uploadMemory);
                        Utilities.CopyMemory((IntPtr)uploadMemory, dataPointer, SizeInBytes);
                        lock (BufferLocker)
                        {
                            vkUnmapMemory(GraphicsDevice.NativeDevice, NativeMemory);
                        }
                    }
                    else
                    {
                        var sizeInBytes = bufferDescription.SizeInBytes;
                        int uploadOffset;
                        GraphicsDevice.AllocateOneTimeUploadBuffer(sizeInBytes, out var upBuf);
                        uploadBuffer = upBuf;

                        Utilities.CopyMemory(uploadBuffer.Value.address, dataPointer, sizeInBytes);

                        // Barrier
                        var memoryBarrier = new VkBufferMemoryBarrier(uploadBuffer.Value.buffer, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, 0, (ulong)sizeInBytes);
                        vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &memoryBarrier, 0, null);

                        // Copy
                        var bufferCopy = new VkBufferCopy
                        {
                            srcOffset = 0,
                            dstOffset = 0,
                            size      = (uint)sizeInBytes
                        };

                        vkCmdCopyBuffer(commandBuffer, uploadBuffer.Value.buffer, NativeBuffer, 1, &bufferCopy);
                    }
                }
                else
                {
                    vkCmdFillBuffer(commandBuffer, NativeBuffer, 0, (uint)bufferDescription.SizeInBytes, 0);
                }

                // Barrier
                var bufferMemoryBarrier = new VkBufferMemoryBarrier(NativeBuffer, VkAccessFlags.TransferWrite, NativeAccessMask);
                vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 0, null);

                var submitInfo = new VkSubmitInfo
                {
                    sType = VkStructureType.SubmitInfo,
                    commandBufferCount = 1,
                    pCommandBuffers    = &commandBuffer,
                };

                var fenceCreateInfo = new VkFenceCreateInfo {
                    sType = VkStructureType.FenceCreateInfo
                };
                vkCreateFence(GraphicsDevice.NativeDevice, &fenceCreateInfo, null, out var fence);

                // Close and submit
                vkEndCommandBuffer(commandBuffer);

                using (GraphicsDevice.QueueLock.ReadLock())
                {
                    vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, fence);
                }

                vkWaitForFences(GraphicsDevice.NativeDevice, 1, &fence, true, ulong.MaxValue);

                vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer);
                vkDestroyFence(GraphicsDevice.NativeDevice, fence, null);

                if (uploadBuffer.HasValue)
                {
                    GraphicsDevice.FreeOneTimeUploadBuffer(uploadBuffer.Value);
                }

                InitializeViews();
            }
        }