void CopyBufferToImage(CommandBuffer cmdBuffer, ImageData imageData, Buffer imageBuffer) { var subresource = new ImageSubresourceLayers(ImageAspectFlags.Color, 0, 0, 1); var imageCopy = new BufferImageCopy(0, 0, 0, subresource, new Offset3D(0, 0, 0), new Extent3D(imageData.Width, imageData.Height, 1)); cmdBuffer.CopyBufferToImage(imageBuffer, imageData.Image, ImageLayout.TransferDstOptimal, new BufferImageCopy[] { imageCopy }); }
void CopyImageToBuffer(CommandBuffer cmdBuffer, ImageData imageData, Buffer imageBuffer, uint width, uint height) { var subresource = new ImageSubresourceLayers(ImageAspectFlags.Color, 0, 0, 1); var imageCopy = new BufferImageCopy(0, width, height, subresource, new Offset3D(0, 0, 0), new Extent3D(width, height, 0)); cmdBuffer.CopyImageToBuffer(imageData.Image, ImageLayout.TransferSrcOptimal, imageBuffer, new[] { imageCopy }); }
private void CopyFromOrToBuffer( CommandBuffer commandBuffer, VkBuffer buffer, Image image, int size, bool to, int x, int y, int width, int height) { var aspectFlags = Info.Format.ConvertAspectFlags(); if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit)) { aspectFlags = ImageAspectFlags.ImageAspectDepthBit; } var sl = new ImageSubresourceLayers(aspectFlags, (uint)FirstLevel, (uint)FirstLayer, 1); var extent = new Extent3D((uint)width, (uint)height, 1); var region = new BufferImageCopy(0, (uint)width, (uint)height, sl, new Offset3D(x, y, 0), extent); if (to) { _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region); } else { _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region); } }
void CopyBufferToImage(Queue queue, CommandPool cmdPool, ImageData imageData, Buffer imageBuffer) { var cmdBuffers = AllocateCommandBuffers(cmdPool, 1); var cmdBuffer = cmdBuffers[0]; var beginInfo = new CommandBufferBeginInfo(); cmdBuffer.Begin(beginInfo); PipelineBarrierSetLayout(cmdBuffer, imageData.Image, ImageLayout.Preinitialized, ImageLayout.TransferDstOptimal, AccessFlags.HostWrite, AccessFlags.TransferWrite); var subresource = new ImageSubresourceLayers(ImageAspectFlags.Color, 0, 0, 1); var imageCopy = new BufferImageCopy(0, 0, 0, subresource, new Offset3D(0, 0, 0), new Extent3D(imageData.Width, imageData.Height, 1)); cmdBuffer.CopyBufferToImage(imageBuffer, imageData.Image, ImageLayout.TransferDstOptimal, new BufferImageCopy[] { imageCopy }); PipelineBarrierSetLayout(cmdBuffer, imageData.Image, ImageLayout.TransferDstOptimal, ImageLayout.ColorAttachmentOptimal, AccessFlags.TransferWrite, AccessFlags.ColorAttachmentWrite); cmdBuffer.End(); var submitInfo = new SubmitInfo(null, null, new[] { cmdBuffer }, null); queue.Submit(new[] { submitInfo }); submitInfo.Dispose(); queue.WaitIdle(); device.FreeCommandBuffers(cmdPool, new[] { cmdBuffer }); }
public void CmdCopyBufferToImage(VulkanBuffer srcBuffer, Image dstImage, ImageLayout dstImageLayout, BufferImageCopy?pRegion) { unsafe { BufferImageCopy valpRegion = pRegion ?? default(BufferImageCopy); BufferImageCopy *ptrpRegion = pRegion != null ? &valpRegion : (BufferImageCopy *)IntPtr.Zero; Interop.NativeMethods.vkCmdCopyBufferToImage(this.m, srcBuffer != null ? srcBuffer.m : default(UInt64), dstImage != null ? dstImage.m : default(UInt64), dstImageLayout, (UInt32)(pRegion != null ? 1 : 0), ptrpRegion); } }
public void CmdCopyImageToBuffer(Image srcImage, ImageLayout srcImageLayout, VulkanBuffer dstBuffer, BufferImageCopy?pRegion) { unsafe { BufferImageCopy valpRegion = pRegion ?? default(BufferImageCopy); BufferImageCopy *ptrpRegion = pRegion != null ? &valpRegion : (BufferImageCopy *)IntPtr.Zero; Interop.NativeMethods.vkCmdCopyImageToBuffer(this.m, srcImage != null ? srcImage.m : default(UInt64), srcImageLayout, dstBuffer != null ? dstBuffer.m : default(UInt64), (UInt32)(pRegion != null ? 1 : 0), ptrpRegion); } }
private void CopyFromOrToBuffer( CommandBuffer commandBuffer, VkBuffer buffer, Image image, int size, bool to, int dstLayer, int dstLevel, int x, int y, int width, int height) { var aspectFlags = Info.Format.ConvertAspectFlags(); if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit)) { aspectFlags = ImageAspectFlags.ImageAspectDepthBit; } var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1); var extent = new Extent3D((uint)width, (uint)height, 1); int rowLengthAlignment = Info.BlockWidth; // We expect all data being written into the texture to have a stride aligned by 4. if (!to && Info.BytesPerPixel < 4) { rowLengthAlignment = 4 / Info.BytesPerPixel; } var region = new BufferImageCopy( 0, (uint)AlignUpNpot(width, rowLengthAlignment), (uint)AlignUpNpot(height, Info.BlockHeight), sl, new Offset3D(x, y, 0), extent); if (to) { _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region); } else { _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region); } }
void IInternalTexture.Upload( HostBuffer stagingBuffer, TransientExecutor executor, Image image, ImageAspects aspects) { if (stagingBuffer == null) { throw new ArgumentNullException(nameof(stagingBuffer)); } if (executor == null) { throw new ArgumentNullException(nameof(executor)); } //Write all the faces to the staging buffer and create copy commands long offset = 0; BufferImageCopy[] copyRegions = new BufferImageCopy[faces.Length]; for (int i = 0; i < faces.Length; i++) { copyRegions[i] = new BufferImageCopy { BufferOffset = offset, BufferRowLength = 0, BufferImageHeight = 0, ImageSubresource = new ImageSubresourceLayers( aspectMask: aspects, mipLevel: 0, baseArrayLayer: i, layerCount: 1), ImageOffset = new Offset3D(x: 0, y: 0, z: 0), ImageExtent = new Extent3D( width: size.X, height: size.Y, depth: 1) }; offset += faces[i].Write(stagingBuffer, offset); } //Copy our staging buffer to the image executor.ExecuteBlocking(commandBuffer => { commandBuffer.CmdCopyBufferToImage( srcBuffer: stagingBuffer.VulkanBuffer, dstImage: image, dstImageLayout: ImageLayout.TransferDstOptimal, regions: copyRegions); }); }
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) { // 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.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 + 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, 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), }; lock (GraphicsDevice.QueueLock) { GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null); GraphicsDevice.NativeCommandQueue.WaitIdle(); commandBuffer.Reset(CommandBufferResetFlags.None); } }
public static ImageWithMemory CreateImageWithMemory( Bitmap texture, bool forceLinear = false, ImageUsageFlags imageUsageFlags = ImageUsageFlags.Sampled, ImageLayout imageLayout = ImageLayout.ShaderReadOnlyOptimal) { ImageWithMemory imageWithMemory = new ImageWithMemory(); System.Drawing.Imaging.BitmapData data = texture.LockBits(new System.Drawing.Rectangle(0, 0, texture.Width, texture.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); int length = data.Stride * data.Height; DeviceSize imageSize = length; byte[] bytes = new byte[length]; System.Runtime.InteropServices.Marshal.Copy(data.Scan0, bytes, 0, length); texture.UnlockBits(data); BufferWithMemory stagingBuffer; fixed(byte *source = &bytes[0]) { stagingBuffer = VContext.Instance.CreateBuffer(BufferUsageFlags.TransferSrc, imageSize, source); } List <BufferImageCopy> bufferCopyRegions = new List <BufferImageCopy>(); DeviceSize offset = 0; for (uint i = 0; i < 1; i++) { BufferImageCopy bufferCopyRegion = new BufferImageCopy() { ImageSubresource = new ImageSubresourceLayers() { AspectMask = ImageAspectFlags.Color, MipLevel = i, BaseArrayLayer = 0, LayerCount = 1 }, ImageExtent = new Extent3D() { Width = (uint)texture.Width, Height = (uint)texture.Height, Depth = 1, }, BufferOffset = offset }; bufferCopyRegions.Add(bufferCopyRegion); offset += imageSize; } imageWithMemory.Image = VContext.Instance.device.CreateImage ( new ImageCreateInfo() { ImageType = ImageType.Image2D, Format = VContext.ColorFormat, Extent = new Extent3D() { Width = (uint)texture.Width, Height = (uint)texture.Height, Depth = 1 }, MipLevels = 1, ArrayLayers = 1, Samples = SampleCountFlags.Count1, Tiling = ImageTiling.Optimal, Usage = ImageUsageFlags.Sampled | ImageUsageFlags.TransferDst, SharingMode = SharingMode.Exclusive, InitialLayout = ImageLayout.Undefined } ); MemoryRequirements textureMemoryRequirements = VContext.Instance.device.GetImageMemoryRequirements(imageWithMemory.Image); uint memoryTypeIndex = Util.GetMemoryTypeIndex(textureMemoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocal); imageWithMemory.Memory = VContext.Instance.device.AllocateMemory ( new MemoryAllocateInfo() { AllocationSize = textureMemoryRequirements.Size, MemoryTypeIndex = memoryTypeIndex } ); VContext.Instance.device.BindImageMemory(imageWithMemory.Image, imageWithMemory.Memory, 0); CommandBuffer commandBuffer = _commandBuffer.Value; commandBuffer.Begin(new CommandBufferBeginInfo()); ImageSubresourceRange subresourceRange = new ImageSubresourceRange() { AspectMask = ImageAspectFlags.Color, BaseMipLevel = 0, LevelCount = 1, LayerCount = 1, }; ImageMemoryBarrier undefinedToTranserDstBarrier = new ImageMemoryBarrier() { OldLayout = ImageLayout.Undefined, NewLayout = ImageLayout.TransferDstOptimal, Image = imageWithMemory.Image, SubresourceRange = subresourceRange, SrcAccessMask = 0, DstAccessMask = AccessFlags.TransferWrite }; commandBuffer.CmdPipelineBarrier( PipelineStageFlags.AllCommands, PipelineStageFlags.AllCommands, 0, null, null, undefinedToTranserDstBarrier); // Copy mip levels from staging buffer commandBuffer.CmdCopyBufferToImage( stagingBuffer.Buffer, imageWithMemory.Image, ImageLayout.TransferDstOptimal, bufferCopyRegions.ToArray()); // Change texture image layout to shader read after all mip levels have been copied ImageMemoryBarrier transferDstToShaderReadBarrier = new ImageMemoryBarrier() { OldLayout = ImageLayout.TransferDstOptimal, NewLayout = ImageLayout.ShaderReadOnlyOptimal, Image = imageWithMemory.Image, SubresourceRange = subresourceRange, SrcAccessMask = AccessFlags.TransferWrite, DstAccessMask = AccessFlags.ShaderRead }; commandBuffer.CmdPipelineBarrier( PipelineStageFlags.AllCommands, PipelineStageFlags.AllCommands, 0, null, null, transferDstToShaderReadBarrier); commandBuffer.End(); // Create a fence to make sure that the copies have finished before continuing Fence copyFence = VContext.Instance.device.CreateFence(new FenceCreateInfo()); SubmitInfo submitInfo = new SubmitInfo() { CommandBuffers = new CommandBuffer[] { commandBuffer } }; VContext.Instance.deviceQueue.Submit(submitInfo, copyFence); VContext.Instance.device.WaitForFences(new Fence[] { copyFence }, true, ulong.MaxValue); commandBuffer.Reset(CommandBufferResetFlags.ReleaseResources); VContext.Instance.device.DestroyFence(copyFence); VContext.Instance.device.FreeMemory(stagingBuffer.Memory); VContext.Instance.device.DestroyBuffer(stagingBuffer.Buffer); imageWithMemory.ImageView = VContext.Instance.CreateImageView(imageWithMemory.Image, VContext.ColorFormat, ImageAspectFlags.Color); return(imageWithMemory); }
public unsafe void CopyBufferToImage(Buffer sourceBuffer, Image destinationImage, ImageLayout destinationImageLayout, uint regionCount, BufferImageCopy* regions) { vkCmdCopyBufferToImage(this, sourceBuffer, destinationImage, destinationImageLayout, regionCount, regions); }
public unsafe void CopyImageToBuffer(Image sourceImage, ImageLayout sourceImageLayout, Buffer destinationBuffer, uint regionCount, BufferImageCopy* regions) { vkCmdCopyImageToBuffer(this, sourceImage, sourceImageLayout, destinationBuffer, regionCount, regions); }
public Texture2D( string name, Graphics graphics, TextureData2D data, bool premultiply = true ) { Name = name; Graphics = graphics; // Create image var image = Graphics.Device.CreateImage(new ImageCreateInfo { ImageType = ImageType.Image2D, Format = data.Format, MipLevels = data.MipMaps.Length, ArrayLayers = 1, Samples = SampleCounts.Count1, Tiling = ImageTiling.Optimal, SharingMode = SharingMode.Exclusive, InitialLayout = ImageLayout.Undefined, Extent = new Extent3D(data.MipMaps[0].Extent.Width, data.MipMaps[0].Extent.Height, 1), Usage = ImageUsages.Sampled | ImageUsages.TransferDst }); Image = new VKImage( image, data.Format, data.MipMaps[0].Extent, new ImageSubresourceRange(ImageAspects.Color, 0, data.MipMaps.Length, 0, 1 )); var memReq = Image.Image.GetMemoryRequirements(); DeviceMemory = Graphics.Device.AllocateMemory(new MemoryAllocateInfo( allocationSize: memReq.Size, memoryTypeIndex: Graphics.GetMemoryTypeIndex(memReq.MemoryTypeBits, MemoryProperties.DeviceLocal) )); Image.Image.BindMemory(DeviceMemory); // Copy data to staging buffer var staging = VKBuffer <byte> .StagingBuffer($"{nameof(Texture2D)} staging buffer", Graphics, data.Size); unsafe { var dest = staging.Map(0, data.Size); foreach (var mip in data.MipMaps) { fixed(byte *src = mip.Data) { if (premultiply) { switch (data.Format) { default: throw new NotImplementedException( $"Premultiplying is not implemented for format: {data.Format}" ); case Format.B8G8R8A8UNorm: for (var i = 0; i < mip.Size; i += 4) { var b = src[i]; var g = src[i + 1]; var r = src[i + 2]; var a = src[i + 3]; b = (byte)(b * (a / 255f)); g = (byte)(g * (a / 255f)); r = (byte)(r * (a / 255f)); dest[i] = b; dest[i + 1] = g; dest[i + 2] = r; dest[i + 3] = a; } break; } } else { System.Buffer.MemoryCopy(src, dest, mip.Size, mip.Size); } dest += mip.Size; } } staging.Unmap(); } // Create copy regions var regions = new BufferImageCopy[data.MipMaps.Length]; var offset = 0L; for (var i = 0; i < regions.Length; i++) { regions[i] = new BufferImageCopy { ImageSubresource = new ImageSubresourceLayers(ImageAspects.Color, i, 0, 1), ImageExtent = new Extent3D(data.MipMaps[0].Extent.Width, data.MipMaps[0].Extent.Height, 1), BufferOffset = offset }; offset += data.MipMaps[i].Size; } // Create command buffer var range = new ImageSubresourceRange(ImageAspects.Color, 0, data.MipMaps.Length, 0, 1); var buffer = Graphics.TransferQueueFamily.CreateCommandBuffers(CommandBufferLevel.Primary, 1)[0]; buffer.Begin(new CommandBufferBeginInfo(CommandBufferUsages.OneTimeSubmit)); buffer.CmdPipelineBarrier( PipelineStages.TopOfPipe, PipelineStages.Transfer, imageMemoryBarriers: new ImageMemoryBarrier[] { new ImageMemoryBarrier( Image.Image, range, Accesses.None, Accesses.TransferWrite, ImageLayout.Undefined, ImageLayout.TransferDstOptimal ) } ); buffer.CmdCopyBufferToImage(staging.Buffer, Image.Image, ImageLayout.TransferDstOptimal, regions); buffer.CmdPipelineBarrier( PipelineStages.Transfer, PipelineStages.FragmentShader, imageMemoryBarriers: new ImageMemoryBarrier[] { new ImageMemoryBarrier( Image.Image, range, Accesses.TransferWrite, Accesses.ShaderRead, ImageLayout.TransferDstOptimal, ImageLayout.ShaderReadOnlyOptimal ) } ); buffer.End(); // Submit the buffer var fence = Graphics.Device.CreateFence(new FenceCreateInfo()); Graphics.GraphicsQueueFamily.HighestPriority.Submit( new SubmitInfo( commandBuffers: new CommandBuffer[] { buffer } ), fence ); fence.Wait(); // Clean up fence.Dispose(); staging.Dispose(); }
private void CopyFromOrToBuffer( CommandBuffer commandBuffer, VkBuffer buffer, Image image, int size, bool to, int dstLayer, int dstLevel, int dstLayers, int dstLevels, bool singleSlice) { bool is3D = Info.Target == Target.Texture3D; int width = Info.Width; int height = Info.Height; int depth = is3D && !singleSlice ? Info.Depth : 1; int layer = is3D ? 0 : dstLayer; int layers = dstLayers; int levels = dstLevels; int offset = 0; for (int level = 0; level < levels; level++) { int mipSize = GetBufferDataLength(Info.GetMipSize(level)); int endOffset = offset + mipSize; if ((uint)endOffset > (uint)size) { break; } int rowLength = (Info.GetMipStride(level) / Info.BytesPerPixel) * Info.BlockWidth; var aspectFlags = Info.Format.ConvertAspectFlags(); if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit)) { aspectFlags = ImageAspectFlags.ImageAspectDepthBit; } var sl = new ImageSubresourceLayers( aspectFlags, (uint)(FirstLevel + dstLevel + level), (uint)(FirstLayer + layer), (uint)layers); var extent = new Extent3D((uint)width, (uint)height, (uint)depth); int z = is3D ? dstLayer : 0; var region = new BufferImageCopy((ulong)offset, (uint)rowLength, (uint)height, sl, new Offset3D(0, 0, z), extent); if (to) { _gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region); } else { _gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region); } offset += mipSize; width = Math.Max(1, width >> 1); height = Math.Max(1, height >> 1); if (Info.Target == Target.Texture3D) { depth = Math.Max(1, depth >> 1); } } }
internal static unsafe extern void vkCmdCopyImageToBuffer(CommandBuffer commandBuffer, Image sourceImage, ImageLayout sourceImageLayout, Buffer destinationBuffer, uint regionCount, BufferImageCopy* regions);
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); } }
internal static VulkanImage Texture2D(VulkanContext ctx, TextureData tex2D) { Buffer stagingBuffer = ctx.Device.CreateBuffer( new BufferCreateInfo(tex2D.Mipmaps[0].Size, BufferUsages.TransferSrc)); MemoryRequirements stagingMemReq = stagingBuffer.GetMemoryRequirements(); int heapIndex = ctx.MemoryProperties.MemoryTypes.IndexOf( stagingMemReq.MemoryTypeBits, MemoryProperties.HostVisible); DeviceMemory stagingMemory = ctx.Device.AllocateMemory( new MemoryAllocateInfo(stagingMemReq.Size, heapIndex)); stagingBuffer.BindMemory(stagingMemory); IntPtr ptr = stagingMemory.Map(0, stagingMemReq.Size); Interop.Write(ptr, tex2D.Mipmaps[0].Data); stagingMemory.Unmap(); // Setup buffer copy regions for each mip level. var bufferCopyRegions = new BufferImageCopy[tex2D.Mipmaps.Length]; int offset = 0; for (int i = 0; i < bufferCopyRegions.Length; i++) { bufferCopyRegions = new[] { new BufferImageCopy { ImageSubresource = new ImageSubresourceLayers(ImageAspects.Color, i, 0, 1), ImageExtent = tex2D.Mipmaps[0].Extent, BufferOffset = offset } }; offset += tex2D.Mipmaps[i].Size; } // Create optimal tiled target image. Image image = ctx.Device.CreateImage(new ImageCreateInfo { ImageType = ImageType.Image2D, Format = tex2D.Format, MipLevels = tex2D.Mipmaps.Length, ArrayLayers = 1, Samples = SampleCounts.Count1, Tiling = ImageTiling.Optimal, SharingMode = SharingMode.Exclusive, InitialLayout = ImageLayout.Undefined, Extent = tex2D.Mipmaps[0].Extent, Usage = ImageUsages.Sampled | ImageUsages.TransferDst }); MemoryRequirements imageMemReq = image.GetMemoryRequirements(); int imageHeapIndex = ctx.MemoryProperties.MemoryTypes.IndexOf( imageMemReq.MemoryTypeBits, MemoryProperties.DeviceLocal); DeviceMemory memory = ctx.Device.AllocateMemory(new MemoryAllocateInfo(imageMemReq.Size, imageHeapIndex)); image.BindMemory(memory); var subresourceRange = new ImageSubresourceRange(ImageAspects.Color, 0, tex2D.Mipmaps.Length, 0, 1); // Copy the data from staging buffers to device local buffers. CommandBuffer cmdBuffer = ctx.GraphicsCommandPool.AllocateBuffers(new CommandBufferAllocateInfo(CommandBufferLevel.Primary, 1))[0]; cmdBuffer.Begin(new CommandBufferBeginInfo(CommandBufferUsages.OneTimeSubmit)); cmdBuffer.CmdPipelineBarrier(PipelineStages.TopOfPipe, PipelineStages.TopOfPipe, imageMemoryBarriers: new[] { new ImageMemoryBarrier( image, subresourceRange, 0, Accesses.TransferWrite, ImageLayout.Undefined, ImageLayout.TransferDstOptimal) }); cmdBuffer.CmdCopyBufferToImage(stagingBuffer, image, ImageLayout.TransferDstOptimal, bufferCopyRegions); cmdBuffer.CmdPipelineBarrier(PipelineStages.TopOfPipe, PipelineStages.TopOfPipe, imageMemoryBarriers: new[] { new ImageMemoryBarrier( image, subresourceRange, Accesses.TransferWrite, Accesses.ShaderRead, ImageLayout.TransferDstOptimal, ImageLayout.ShaderReadOnlyOptimal) }); cmdBuffer.End(); // Submit. Fence fence = ctx.Device.CreateFence(); ctx.GraphicsQueue.Submit(new SubmitInfo(commandBuffers: new[] { cmdBuffer }), fence); fence.Wait(); // Cleanup staging resources. fence.Dispose(); stagingMemory.Dispose(); stagingBuffer.Dispose(); // Create image view. ImageView view = image.CreateView(new ImageViewCreateInfo(tex2D.Format, subresourceRange)); return(new VulkanImage(image, memory, view, tex2D.Format)); }
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); }
internal static unsafe extern void vkCmdCopyBufferToImage(CommandBuffer commandBuffer, Buffer sourceBuffer, Image destinationImage, ImageLayout destinationImageLayout, uint regionCount, BufferImageCopy* regions);