private void RecordComputeCommandBuffer() { // Record particle movements. var graphicsToComputeBarrier = new BufferMemoryBarrier(_storageBuffer, Accesses.VertexAttributeRead, Accesses.ShaderWrite, Context.GraphicsQueue.FamilyIndex, Context.ComputeQueue.FamilyIndex); var computeToGraphicsBarrier = new BufferMemoryBarrier(_storageBuffer, Accesses.ShaderWrite, Accesses.VertexAttributeRead, Context.ComputeQueue.FamilyIndex, Context.GraphicsQueue.FamilyIndex); _computeCmdBuffer.Begin(); // Add memory barrier to ensure that the (graphics) vertex shader has fetched attributes // before compute starts to write to the buffer. _computeCmdBuffer.CmdPipelineBarrier(PipelineStages.VertexInput, PipelineStages.ComputeShader, bufferMemoryBarriers: new[] { graphicsToComputeBarrier }); _computeCmdBuffer.CmdBindPipeline(PipelineBindPoint.Compute, _computePipeline); _computeCmdBuffer.CmdBindDescriptorSet(PipelineBindPoint.Compute, _computePipelineLayout, _computeDescriptorSet); _computeCmdBuffer.CmdDispatch(_storageBuffer.Count / 256, 1, 1); // Add memory barrier to ensure that compute shader has finished writing to the buffer. // Without this the (rendering) vertex shader may display incomplete results (partial // data from last frame). _computeCmdBuffer.CmdPipelineBarrier(PipelineStages.ComputeShader, PipelineStages.VertexInput, bufferMemoryBarriers: new[] { computeToGraphicsBarrier }); _computeCmdBuffer.End(); }
public static unsafe void InsertBufferBarrier( VulkanRenderer gd, CommandBuffer commandBuffer, VkBuffer buffer, AccessFlags srcAccessMask, AccessFlags dstAccessMask, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, int offset, int size) { BufferMemoryBarrier memoryBarrier = new BufferMemoryBarrier() { SType = StructureType.BufferMemoryBarrier, SrcAccessMask = srcAccessMask, DstAccessMask = dstAccessMask, SrcQueueFamilyIndex = Vk.QueueFamilyIgnored, DstQueueFamilyIndex = Vk.QueueFamilyIgnored, Buffer = buffer, Offset = (ulong)offset, Size = (ulong)size }; gd.Api.CmdPipelineBarrier( commandBuffer, srcStageMask, dstStageMask, 0, 0, null, 1, memoryBarrier, 0, null); }
private unsafe void InitializeImage(DataBox[] dataBoxes) { var commandBuffer = GraphicsDevice.NativeCopyCommandBuffer; var beginInfo = new CommandBufferBeginInfo { StructureType = StructureType.CommandBufferBeginInfo }; commandBuffer.Begin(ref beginInfo); if (dataBoxes != null && dataBoxes.Length > 0) { int totalSize = dataBoxes.Length * 4; for (int i = 0; i < dataBoxes.Length; i++) { totalSize += dataBoxes[i].SlicePitch; } SharpVulkan.Buffer uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset); // Upload buffer barrier var bufferMemoryBarrier = new BufferMemoryBarrier(uploadResource, AccessFlags.HostWrite, AccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize); // Image barrier var initialBarrier = new ImageMemoryBarrier(NativeImage, ImageLayout.Undefined, ImageLayout.TransferDestinationOptimal, AccessFlags.None, AccessFlags.TransferWrite, new ImageSubresourceRange(NativeImageAspect)); commandBuffer.PipelineBarrier(PipelineStageFlags.TopOfPipe, PipelineStageFlags.Transfer, DependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier); // Copy data boxes to upload buffer var copies = new BufferImageCopy[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); SubresourceLayout layout; GraphicsDevice.NativeDevice.GetImageSubresourceLayout(NativeImage, new ImageSubresource(NativeImageAspect, (uint)arraySlice, (uint)mipSlice), out layout); var alignment = ((uploadOffset + 3) & ~3) - uploadOffset; uploadMemory += alignment; uploadOffset += alignment; Utilities.CopyMemory(uploadMemory, dataBoxes[i].DataPointer, slicePitch); // TODO VULKAN: Check if pitches are valid copies[i] = new BufferImageCopy { BufferOffset = (ulong)uploadOffset, ImageSubresource = new ImageSubresourceLayers(ImageAspectFlags.Color, (uint)arraySlice, 1, (uint)mipSlice), BufferRowLength = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize), BufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch), ImageOffset = new Offset3D(0, 0, arraySlice), ImageExtent = new Extent3D((uint)mipMapDescription.Width, (uint)mipMapDescription.Height, 1) }; uploadMemory += slicePitch; uploadOffset += slicePitch; } // Copy from upload buffer to image fixed(BufferImageCopy *copiesPointer = &copies[0]) { commandBuffer.CopyBufferToImage(uploadResource, NativeImage, ImageLayout.TransferDestinationOptimal, (uint)copies.Length, copiesPointer); } IsInitialized = true; } // Transition to default layout var imageMemoryBarrier = new ImageMemoryBarrier(NativeImage, dataBoxes == null || dataBoxes.Length == 0 ? ImageLayout.Undefined : ImageLayout.TransferDestinationOptimal, NativeLayout, dataBoxes == null || dataBoxes.Length == 0 ? AccessFlags.None : AccessFlags.TransferWrite, NativeAccessMask, new ImageSubresourceRange(NativeImageAspect)); commandBuffer.PipelineBarrier(PipelineStageFlags.Transfer, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); // Close and submit commandBuffer.End(); var submitInfo = new SubmitInfo { StructureType = StructureType.SubmitInfo, CommandBufferCount = 1, CommandBuffers = new IntPtr(&commandBuffer), }; GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null); GraphicsDevice.NativeCommandQueue.WaitIdle(); commandBuffer.Reset(CommandBufferResetFlags.None); }
/// <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 BufferCreateInfo { StructureType = StructureType.BufferCreateInfo, Size = (ulong)bufferDescription.SizeInBytes, Flags = BufferCreateFlags.None, }; createInfo.Usage |= BufferUsageFlags.TransferSource; // We always fill using transfer //if (bufferDescription.Usage != GraphicsResourceUsage.Immutable) createInfo.Usage |= BufferUsageFlags.TransferDestination; if (Usage == GraphicsResourceUsage.Staging) { NativeAccessMask = AccessFlags.HostRead | AccessFlags.HostWrite; NativePipelineStageMask |= PipelineStageFlags.Host; } else { if ((ViewFlags & BufferFlags.VertexBuffer) != 0) { createInfo.Usage |= BufferUsageFlags.VertexBuffer; NativeAccessMask |= AccessFlags.VertexAttributeRead; NativePipelineStageMask |= PipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.IndexBuffer) != 0) { createInfo.Usage |= BufferUsageFlags.IndexBuffer; NativeAccessMask |= AccessFlags.IndexRead; NativePipelineStageMask |= PipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.ConstantBuffer) != 0) { createInfo.Usage |= BufferUsageFlags.UniformBuffer; NativeAccessMask |= AccessFlags.UniformRead; NativePipelineStageMask |= PipelineStageFlags.VertexShader | PipelineStageFlags.FragmentShader; } if ((ViewFlags & BufferFlags.ShaderResource) != 0) { createInfo.Usage |= BufferUsageFlags.UniformTexelBuffer; NativeAccessMask |= AccessFlags.ShaderRead; NativePipelineStageMask |= PipelineStageFlags.VertexShader | PipelineStageFlags.FragmentShader; if ((ViewFlags & BufferFlags.UnorderedAccess) != 0) { createInfo.Usage |= BufferUsageFlags.StorageTexelBuffer; NativeAccessMask |= AccessFlags.ShaderWrite; } } } // Create buffer NativeBuffer = GraphicsDevice.NativeDevice.CreateBuffer(ref createInfo); // Allocate memory var memoryProperties = MemoryPropertyFlags.DeviceLocal; if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic) { memoryProperties = MemoryPropertyFlags.HostVisible | MemoryPropertyFlags.HostCoherent; } MemoryRequirements memoryRequirements; GraphicsDevice.NativeDevice.GetBufferMemoryRequirements(NativeBuffer, out memoryRequirements); AllocateMemory(memoryProperties, memoryRequirements); if (NativeMemory != DeviceMemory.Null) { GraphicsDevice.NativeDevice.BindBufferMemory(NativeBuffer, NativeMemory, 0); } if (SizeInBytes > 0) { // Begin copy command buffer var commandBufferAllocateInfo = new CommandBufferAllocateInfo { StructureType = StructureType.CommandBufferAllocateInfo, CommandPool = GraphicsDevice.NativeCopyCommandPool, CommandBufferCount = 1, Level = CommandBufferLevel.Primary }; CommandBuffer commandBuffer; lock (GraphicsDevice.QueueLock) { GraphicsDevice.NativeDevice.AllocateCommandBuffers(ref commandBufferAllocateInfo, &commandBuffer); } var beginInfo = new CommandBufferBeginInfo { StructureType = StructureType.CommandBufferBeginInfo, Flags = CommandBufferUsageFlags.OneTimeSubmit }; commandBuffer.Begin(ref beginInfo); // Copy to upload buffer if (dataPointer != IntPtr.Zero) { if (Usage == GraphicsResourceUsage.Dynamic) { var uploadMemory = GraphicsDevice.NativeDevice.MapMemory(NativeMemory, 0, (ulong)SizeInBytes, MemoryMapFlags.None); Utilities.CopyMemory(uploadMemory, dataPointer, SizeInBytes); GraphicsDevice.NativeDevice.UnmapMemory(NativeMemory); } else { var sizeInBytes = bufferDescription.SizeInBytes; SharpVulkan.Buffer uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(sizeInBytes, out uploadResource, out uploadOffset); Utilities.CopyMemory(uploadMemory, dataPointer, sizeInBytes); // Barrier var memoryBarrier = new BufferMemoryBarrier(uploadResource, AccessFlags.HostWrite, AccessFlags.TransferRead, (ulong)uploadOffset, (ulong)sizeInBytes); commandBuffer.PipelineBarrier(PipelineStageFlags.Host, PipelineStageFlags.Transfer, DependencyFlags.None, 0, null, 1, &memoryBarrier, 0, null); // Copy var bufferCopy = new BufferCopy { SourceOffset = (uint)uploadOffset, DestinationOffset = 0, Size = (uint)sizeInBytes }; commandBuffer.CopyBuffer(uploadResource, NativeBuffer, 1, &bufferCopy); } } else { commandBuffer.FillBuffer(NativeBuffer, 0, (uint)bufferDescription.SizeInBytes, 0); } // Barrier var bufferMemoryBarrier = new BufferMemoryBarrier(NativeBuffer, AccessFlags.TransferWrite, NativeAccessMask); commandBuffer.PipelineBarrier(PipelineStageFlags.Transfer, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 0, null); // Close and submit commandBuffer.End(); var submitInfo = new SubmitInfo { StructureType = StructureType.SubmitInfo, CommandBufferCount = 1, CommandBuffers = new IntPtr(&commandBuffer), }; lock (GraphicsDevice.QueueLock) { GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null); GraphicsDevice.NativeCommandQueue.WaitIdle(); //commandBuffer.Reset(CommandBufferResetFlags.None); GraphicsDevice.NativeDevice.FreeCommandBuffers(GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer); } InitializeViews(); } }
private unsafe void InitializeImage(DataBox[] dataBoxes) { // Begin copy command buffer var commandBufferAllocateInfo = new CommandBufferAllocateInfo { StructureType = StructureType.CommandBufferAllocateInfo, CommandPool = GraphicsDevice.NativeCopyCommandPool, CommandBufferCount = 1, Level = CommandBufferLevel.Primary }; CommandBuffer commandBuffer; lock (GraphicsDevice.QueueLock) { GraphicsDevice.NativeDevice.AllocateCommandBuffers(ref commandBufferAllocateInfo, &commandBuffer); } var beginInfo = new CommandBufferBeginInfo { StructureType = StructureType.CommandBufferBeginInfo, Flags = CommandBufferUsageFlags.OneTimeSubmit }; commandBuffer.Begin(ref 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; } SharpVulkan.Buffer uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset); // Upload buffer barrier var bufferMemoryBarrier = new BufferMemoryBarrier(uploadResource, AccessFlags.HostWrite, AccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize); // Image barrier var initialBarrier = new ImageMemoryBarrier(NativeImage, ImageLayout.Undefined, ImageLayout.TransferDestinationOptimal, AccessFlags.None, AccessFlags.TransferWrite, new ImageSubresourceRange(NativeImageAspect)); commandBuffer.PipelineBarrier(PipelineStageFlags.Host, PipelineStageFlags.Transfer, DependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier); // Copy data boxes to upload buffer var copies = new BufferImageCopy[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 BufferImageCopy { BufferOffset = (ulong)uploadOffset, ImageSubresource = new ImageSubresourceLayers(ImageAspectFlags.Color, (uint)arraySlice, 1, (uint)mipSlice), BufferRowLength = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize), BufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch), ImageOffset = new Offset3D(0, 0, 0), ImageExtent = new Extent3D((uint)mipMapDescription.Width, (uint)mipMapDescription.Height, (uint)mipMapDescription.Depth) }; uploadMemory += slicePitch; uploadOffset += slicePitch; } // Copy from upload buffer to image fixed(BufferImageCopy *copiesPointer = &copies[0]) { commandBuffer.CopyBufferToImage(uploadResource, NativeImage, ImageLayout.TransferDestinationOptimal, (uint)copies.Length, copiesPointer); } IsInitialized = true; } // Transition to default layout var imageMemoryBarrier = new ImageMemoryBarrier(NativeImage, dataBoxes == null || dataBoxes.Length == 0 ? ImageLayout.Undefined : ImageLayout.TransferDestinationOptimal, NativeLayout, dataBoxes == null || dataBoxes.Length == 0 ? AccessFlags.None : AccessFlags.TransferWrite, NativeAccessMask, new ImageSubresourceRange(NativeImageAspect)); commandBuffer.PipelineBarrier(PipelineStageFlags.Transfer, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); // Close and submit commandBuffer.End(); var submitInfo = new SubmitInfo { StructureType = StructureType.SubmitInfo, CommandBufferCount = 1, CommandBuffers = new IntPtr(&commandBuffer), }; lock (GraphicsDevice.QueueLock) { GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null); GraphicsDevice.NativeCommandQueue.WaitIdle(); GraphicsDevice.NativeDevice.FreeCommandBuffers(GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer); } }
public void CmdPipelineBarrier(PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, DependencyFlags dependencyFlag, MemoryBarrier pMemoryBarrier, BufferMemoryBarrier pBufferMemoryBarrier, ImageMemoryBarrier pImageMemoryBarrier) { unsafe { Interop.NativeMethods.vkCmdPipelineBarrier(this.m, srcStageMask, dstStageMask, dependencyFlag, (UInt32)(pMemoryBarrier != null ? 1 : 0), pMemoryBarrier != null ? pMemoryBarrier.m : (Interop.MemoryBarrier *) default(IntPtr), (UInt32)(pBufferMemoryBarrier != null ? 1 : 0), pBufferMemoryBarrier != null ? pBufferMemoryBarrier.m : (Interop.BufferMemoryBarrier *) default(IntPtr), (UInt32)(pImageMemoryBarrier != null ? 1 : 0), pImageMemoryBarrier != null ? pImageMemoryBarrier.m : (Interop.ImageMemoryBarrier *) default(IntPtr)); } }
public void CmdWaitEvent(Event pEvent, PipelineStageFlags srcStageMask, PipelineStageFlags dstStageMask, MemoryBarrier pMemoryBarrier, BufferMemoryBarrier pBufferMemoryBarrier, ImageMemoryBarrier pImageMemoryBarrier) { unsafe { fixed(UInt64 *ptrpEvent = &pEvent.m) { Interop.NativeMethods.vkCmdWaitEvents(this.m, (UInt32)(pEvent != null ? 1 : 0), ptrpEvent, srcStageMask, dstStageMask, (UInt32)(pMemoryBarrier != null ? 1 : 0), pMemoryBarrier != null ? pMemoryBarrier.m : (Interop.MemoryBarrier *) default(IntPtr), (UInt32)(pBufferMemoryBarrier != null ? 1 : 0), pBufferMemoryBarrier != null ? pBufferMemoryBarrier.m : (Interop.BufferMemoryBarrier *) default(IntPtr), (UInt32)(pImageMemoryBarrier != null ? 1 : 0), pImageMemoryBarrier != null ? pImageMemoryBarrier.m : (Interop.ImageMemoryBarrier *) default(IntPtr)); } } }