private void setImageMemoryBarrier(VkCommandBuffer command, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, VkImage image, VkImageAspectFlags aspectFlags) { var imageMemoryBarrier = new VkImageMemoryBarrier() { srcAccessMask = srcAccessMask, dstAccessMask = dstAccessMask, oldLayout = oldLayout, newLayout = newLayout, srcQueueFamilyIndex = ~0u, dstQueueFamilyIndex = ~0u, subresourceRange = new VkImageSubresourceRange { aspectMask = aspectFlags, baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1, }, image = image }; VulkanAPI.vkCmdPipelineBarrier( command, VkPipelineStageFlags.VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkPipelineStageFlags.VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, null, // MemoryBarriers null, // BufferMemoryBarriers new VkImageMemoryBarrier[] { imageMemoryBarrier } ); }
public void SetLayout( CommandBuffer cmdbuffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands, uint srcQueueFamilyIndex = Vk.QueueFamilyIgnored, uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) { VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); imageMemoryBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex; imageMemoryBarrier.dstQueueFamilyIndex = dstQueueFamilyIndex; imageMemoryBarrier.oldLayout = oldImageLayout; imageMemoryBarrier.newLayout = newImageLayout; imageMemoryBarrier.image = handle; imageMemoryBarrier.subresourceRange = subresourceRange; imageMemoryBarrier.srcAccessMask = srcAccessMask; imageMemoryBarrier.dstAccessMask = dstAccessMask; Vk.vkCmdPipelineBarrier( cmdbuffer.Handle, srcStageMask, dstStageMask, 0, 0, IntPtr.Zero, 0, IntPtr.Zero, 1, ref imageMemoryBarrier); }
public unsafe VkMemoryBarrier(VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) { this.sType = VkStructureType.MemoryBarrier; this.pNext = null; this.srcAccessMask = (VkAccessFlags)srcAccessMask; this.dstAccessMask = (VkAccessFlags)dstAccessMask; }
public void SetMemoryBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkDependencyFlags dependencyFlags = VkDependencyFlags.ByRegion) { VkMemoryBarrier memoryBarrier = VkMemoryBarrier.New(); memoryBarrier.srcAccessMask = srcAccessMask; memoryBarrier.dstAccessMask = dstAccessMask; Vk.vkCmdPipelineBarrier(Handle, srcStageMask, dstStageMask, dependencyFlags, 1, ref memoryBarrier, 0, IntPtr.Zero, 0, IntPtr.Zero); }
public void SetFullHandles(VkImage image, VkImageView attachmentView, VkImageLayout layout, VkAccessFlags accessMask, VkFormat nativeFormat, VkImageAspectFlags aspect) { NativeImage = image; NativeColorAttachmentView = attachmentView; NativeLayout = layout; NativeAccessMask = accessMask; NativeFormat = nativeFormat; NativeImageAspect = aspect; }
private void barrier(VkPipelineStageFlags src_stages, VkAccessFlags src_access, VkPipelineStageFlags dst_stages, VkAccessFlags dst_access) { VkMemoryBarrier barrier = new() { sType = VkStructureType.MemoryBarrier, }; barrier.srcAccessMask = src_access; barrier.dstAccessMask = dst_access; vkCmdPipelineBarrier(handle, src_stages, dst_stages, 0, 1, &barrier, 0, null, 0, null); }
public void AddDependency(uint srcSubpass, uint dstSubpass, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkDependencyFlags dependencyFlags = VkDependencyFlags.ByRegion) { dependencies.Add(new VkSubpassDependency { srcSubpass = srcSubpass, dstSubpass = dstSubpass, srcStageMask = srcStageMask, dstStageMask = dstStageMask, srcAccessMask = srcAccessMask, dstAccessMask = dstAccessMask, dependencyFlags = dependencyFlags }); }
public unsafe VkImageMemoryBarrier(VkImage image, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, VkImageAspectFlags aspectMask = VkImageAspectFlags.Color, uint baseMipLevel = 0, uint levelCount = uint.MaxValue) { this.sType = VkStructureType.ImageMemoryBarrier; this.pNext = null; this.srcAccessMask = (VkAccessFlags)srcAccessMask; this.dstAccessMask = (VkAccessFlags)dstAccessMask; this.oldLayout = (VkImageLayout)oldLayout; this.newLayout = (VkImageLayout)newLayout; this.srcQueueFamilyIndex = uint.MaxValue; this.dstQueueFamilyIndex = uint.MaxValue; this.image = image; this.subresourceRange.aspectMask = (VkImageAspectFlags)aspectMask; this.subresourceRange.baseMipLevel = baseMipLevel; this.subresourceRange.baseArrayLayer = 0; this.subresourceRange.levelCount = levelCount; this.subresourceRange.layerCount = uint.MaxValue; }
public unsafe VkBufferMemoryBarrier( VkBuffer buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, ulong offset = 0, ulong size = Vulkan.WholeSize, uint srcQueueFamilyIndex = Vulkan.QueueFamilyIgnored, uint dstQueueFamilyIndex = Vulkan.QueueFamilyIgnored, void *pNext = default) { sType = VkStructureType.BufferMemoryBarrier; this.pNext = pNext; this.srcAccessMask = srcAccessMask; this.dstAccessMask = dstAccessMask; this.srcQueueFamilyIndex = srcQueueFamilyIndex; this.dstQueueFamilyIndex = dstQueueFamilyIndex; this.buffer = buffer; this.offset = offset; this.size = size; }
public VkBufferMemoryBarrier( VkBuffer buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, ulong offset = 0, ulong size = VK_WHOLE_SIZE, uint srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, uint dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, void *pNext = default) { sType = VkStructureType.BufferMemoryBarrier; this.pNext = pNext; this.srcAccessMask = srcAccessMask; this.dstAccessMask = dstAccessMask; this.srcQueueFamilyIndex = srcQueueFamilyIndex; this.dstQueueFamilyIndex = dstQueueFamilyIndex; this.buffer = buffer; this.offset = offset; this.size = size; }
public VkImageMemoryBarrier( VkImage image, VkImageSubresourceRange subresourceRange, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, uint srcQueueFamilyIndex = VulkanNative.QueueFamilyIgnored, uint dstQueueFamilyIndex = VulkanNative.QueueFamilyIgnored) { sType = VkStructureType.ImageMemoryBarrier; pNext = null; this.srcAccessMask = srcAccessMask; this.dstAccessMask = dstAccessMask; this.oldLayout = oldLayout; this.newLayout = newLayout; this.srcQueueFamilyIndex = srcQueueFamilyIndex; this.dstQueueFamilyIndex = dstQueueFamilyIndex; this.image = image; this.subresourceRange = subresourceRange; }
public void SetLayout( CommandBuffer cmdbuffer, VkImageAspectFlags aspectMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands, uint srcQueueFamilyIndex = Vk.QueueFamilyIgnored, uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) { VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange { aspectMask = aspectMask, baseMipLevel = 0, levelCount = CreateInfo.mipLevels, layerCount = CreateInfo.arrayLayers, }; SetLayout(cmdbuffer, srcAccessMask, dstAccessMask, oldImageLayout, newImageLayout, subresourceRange, srcStageMask, dstStageMask, srcQueueFamilyIndex, dstQueueFamilyIndex); }
public unsafe VkImageMemoryBarrier( VkImage image, VkImageSubresourceRange subresourceRange, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, uint srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, uint dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, void *pNext = default) { sType = VkStructureType.ImageMemoryBarrier; this.pNext = pNext; this.srcAccessMask = srcAccessMask; this.dstAccessMask = dstAccessMask; this.oldLayout = oldLayout; this.newLayout = newLayout; this.srcQueueFamilyIndex = srcQueueFamilyIndex; this.dstQueueFamilyIndex = dstQueueFamilyIndex; this.image = image; this.subresourceRange = subresourceRange; }
/// <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 possible later easy batching or physics mesh generation if (dataPointer != IntPtr.Zero && (ViewFlags == BufferFlags.VertexBuffer && (CaptureAllModelBuffers || bufferDescription.SizeInBytes <= CaptureVertexBuffersOfSize) || ViewFlags == BufferFlags.IndexBuffer && (CaptureAllModelBuffers || 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; 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); if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic) { AllocateMemory(memoryProperties, memoryRequirements); // special case that doesn't use a pool } else if (VulkanMemoryPool.TryAllocateMemoryForBuffer(createInfo.size, GraphicsDevice.NativeDevice, GraphicsDevice.NativePhysicalDevice, ref memoryRequirements, ref memoryProperties, out var memOffset, out var devmem)) { NativeMemory = devmem; NativeMemoryOffset = memOffset; }
/// <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(); } }
private void InitializeFromImpl(DataBox[] dataBoxes = null) { NativeFormat = VulkanConvertExtensions.ConvertPixelFormat(ViewFormat); HasStencil = IsStencilFormat(ViewFormat); NativeImageAspect = IsDepthStencil ? VkImageAspectFlags.Depth : VkImageAspectFlags.Color; if (HasStencil) { NativeImageAspect |= VkImageAspectFlags.Stencil; } // For depth-stencil formats, automatically fall back to a supported one if (IsDepthStencil && HasStencil) { NativeFormat = GetFallbackDepthStencilFormat(GraphicsDevice, NativeFormat); } if (Usage == GraphicsResourceUsage.Staging) { if (NativeImage != VkImage.Null) { throw new InvalidOperationException(); } if (isNotOwningResources) { throw new InvalidOperationException(); } NativeAccessMask = VkAccessFlags.HostRead | VkAccessFlags.HostWrite; NativePipelineStageMask = VkPipelineStageFlags.Host; if (ParentTexture != null) { // Create only a view NativeBuffer = ParentTexture.NativeBuffer; NativeMemory = ParentTexture.NativeMemory; } else { CreateBuffer(); if (dataBoxes != null && dataBoxes.Length > 0) { throw new InvalidOperationException(); } } } else { if (NativeImage != VkImage.Null) { throw new InvalidOperationException(); } NativeLayout = IsRenderTarget ? VkImageLayout.ColorAttachmentOptimal : IsDepthStencil ? VkImageLayout.DepthStencilAttachmentOptimal : IsShaderResource ? VkImageLayout.ShaderReadOnlyOptimal : VkImageLayout.General; if (NativeLayout == VkImageLayout.TransferDstOptimal) { NativeAccessMask = VkAccessFlags.TransferRead; } if (NativeLayout == VkImageLayout.ColorAttachmentOptimal) { NativeAccessMask = VkAccessFlags.ColorAttachmentWrite; } if (NativeLayout == VkImageLayout.DepthStencilAttachmentOptimal) { NativeAccessMask = VkAccessFlags.DepthStencilAttachmentWrite; } if (NativeLayout == VkImageLayout.ShaderReadOnlyOptimal) { NativeAccessMask = VkAccessFlags.ShaderRead | VkAccessFlags.InputAttachmentRead; } NativePipelineStageMask = IsRenderTarget ? VkPipelineStageFlags.ColorAttachmentOutput : IsDepthStencil ? VkPipelineStageFlags.ColorAttachmentOutput | VkPipelineStageFlags.EarlyFragmentTests | VkPipelineStageFlags.LateFragmentTests : IsShaderResource ? VkPipelineStageFlags.VertexInput | VkPipelineStageFlags.FragmentShader : VkPipelineStageFlags.None; if (ParentTexture != null) { // Create only a view NativeImage = ParentTexture.NativeImage; NativeMemory = ParentTexture.NativeMemory; } else { if (!isNotOwningResources) { CreateImage(); InitializeImage(dataBoxes); } } if (!isNotOwningResources) { NativeImageView = GetImageView(ViewType, ArraySlice, MipLevel); NativeColorAttachmentView = GetColorAttachmentView(ViewType, ArraySlice, MipLevel); NativeDepthStencilView = GetDepthStencilView(); } } }
// Record a buffer copy operation into the command buffer public void RecordBufferCopy(VkCommandBuffer cmd, ResourceType?dstBufferType, ulong dataSize, VkBuffer srcBuffer, ulong srcOffset, VkBuffer dstBuffer, ulong dstOffset) { // Get pipeline barrier values VkPipelineStageFlags srcStage = 0, dstStage = 0; VkAccessFlags srcAccess = 0, dstAccess = 0; if (dstBufferType.HasValue) { GetBarrierStages(dstBufferType.Value, out srcStage, out dstStage); GetAccessFlags(dstBufferType.Value, out srcAccess, out dstAccess); } // Start command VkCommandBufferBeginInfo cbbi = new(VkCommandBufferUsageFlags.OneTimeSubmit, null); cmd.BeginCommandBuffer(&cbbi); // Src barrier if (dstBufferType.HasValue) { VkBufferMemoryBarrier srcBarrier = new( srcAccessMask : srcAccess, dstAccessMask : VkAccessFlags.TransferWrite, srcQueueFamilyIndex : VkConstants.QUEUE_FAMILY_IGNORED, dstQueueFamilyIndex : VkConstants.QUEUE_FAMILY_IGNORED, buffer : dstBuffer, offset : dstOffset, size : dataSize ); cmd.CmdPipelineBarrier( srcStage, VkPipelineStageFlags.Transfer, VkDependencyFlags.ByRegion, 0, null, 1, &srcBarrier, 0, null ); } // Create copy command VkBufferCopy bc = new(srcOffset, dstOffset, dataSize); cmd.CmdCopyBuffer(srcBuffer, dstBuffer, 1, &bc); // Last barrier if (dstBufferType.HasValue) { VkBufferMemoryBarrier dstBarrier = new( srcAccessMask : VkAccessFlags.TransferWrite, dstAccessMask : dstAccess, srcQueueFamilyIndex : VkConstants.QUEUE_FAMILY_IGNORED, dstQueueFamilyIndex : VkConstants.QUEUE_FAMILY_IGNORED, buffer : dstBuffer, offset : dstOffset, size : dataSize ); cmd.CmdPipelineBarrier( VkPipelineStageFlags.Transfer, dstStage, VkDependencyFlags.ByRegion, 0, null, 1, &dstBarrier, 0, null ); } // End cmd.EndCommandBuffer().Throw("Failed to record buffer upload commands"); }
/// <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(); } }
internal void Recreate() { VkBufferCreateInfo buffer_info = new VkBufferCreateInfo() { sType = VkStructureType.BufferCreateInfo, pNext = null, size = (ulong)BufferDescription.SizeInBytes, flags = VkBufferCreateFlags.None, //sharingMode = VkSharingMode.Exclusive }; buffer_info.usage |= VkBufferUsageFlags.TransferSrc; if (Usage == ResourceUsage.GPU_Only) { access = VkAccessFlags.HostRead | VkAccessFlags.HostWrite; } else { if ((Flags /*.HasFlag()*/ & BufferFlags.VertexBuffer) != 0) { buffer_info.usage |= VkBufferUsageFlags.VertexBuffer; access |= VkAccessFlags.VertexAttributeRead; } if ((Flags & BufferFlags.IndexBuffer) is not 0) { buffer_info.usage |= VkBufferUsageFlags.IndexBuffer; access |= VkAccessFlags.IndexRead; } if ((Flags & BufferFlags.ConstantBuffer) is not 0) { buffer_info.usage |= VkBufferUsageFlags.UniformBuffer; access |= VkAccessFlags.UniformRead; } if ((Flags & BufferFlags.ShaderResource) is not 0) { buffer_info.usage |= VkBufferUsageFlags.UniformTexelBuffer; access |= VkAccessFlags.ShaderRead; } if ((Flags & BufferFlags.UnorderedAccess) is not 0) { buffer_info.usage |= VkBufferUsageFlags.StorageTexelBuffer; access |= VkAccessFlags.ShaderWrite; } if ((Flags & BufferFlags.StructuredBuffer) is not 0) { buffer_info.usage |= VkBufferUsageFlags.StorageBuffer; access |= VkAccessFlags.ShaderWrite; } } vkCreateBuffer(NativeDevice.handle, &buffer_info, null, out handle); // Allocate memory var memoryProperties = VkMemoryPropertyFlags.DeviceLocal; if (BufferDescription.Usage is ResourceUsage.GPU_Only || Usage == ResourceUsage.CPU_To_GPU) { memoryProperties = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent; } if (Usage == ResourceUsage.GPU_To_CPU) { memoryProperties = VkMemoryPropertyFlags.HostVisible; } vkGetBufferMemoryRequirements(NativeDevice.handle, handle, out VkMemoryRequirements memReqs); VkMemoryAllocateInfo MemoryAlloc_info = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = memReqs.size, memoryTypeIndex = NativeDevice.get_memory_type(memReqs.memoryTypeBits, memoryProperties), }; VkDeviceMemory _memory; vkAllocateMemory(NativeDevice.handle, &MemoryAlloc_info, null, out _memory); memory = _memory; size = memReqs.size; vkBindBufferMemory(NativeDevice.handle, handle, memory, 0); }