private VulkanImage(VulkanContext ctx, VkImage image, VkDeviceMemory memory, VkImageView view, VkFormat format) { Image = image; Memory = memory; View = view; Format = format; this.ctx = ctx; }
public static VulkanBuffer Vertex <T>(VulkanContext ctx, T[] vertices) where T : struct { long size = vertices.Length * Interop.SizeOf <T>(); // Create a staging buffer that is writable by host. Buffer stagingBuffer = ctx.Device.CreateBuffer(new BufferCreateInfo(size, BufferUsages.TransferSrc)); MemoryRequirements stagingReq = stagingBuffer.GetMemoryRequirements(); int stagingMemoryTypeIndex = ctx.MemoryProperties.MemoryTypes.IndexOf( stagingReq.MemoryTypeBits, MemoryProperties.HostVisible | MemoryProperties.HostCoherent); DeviceMemory stagingMemory = ctx.Device.AllocateMemory(new MemoryAllocateInfo(stagingReq.Size, stagingMemoryTypeIndex)); IntPtr vertexPtr = stagingMemory.Map(0, stagingReq.Size); Interop.Write(vertexPtr, vertices); stagingMemory.Unmap(); stagingBuffer.BindMemory(stagingMemory); // Create a device local buffer where the vertex data will be copied and which will be used for rendering. Buffer buffer = ctx.Device.CreateBuffer(new BufferCreateInfo(size, BufferUsages.VertexBuffer | BufferUsages.TransferDst)); MemoryRequirements req = buffer.GetMemoryRequirements(); int memoryTypeIndex = ctx.MemoryProperties.MemoryTypes.IndexOf( req.MemoryTypeBits, MemoryProperties.DeviceLocal); DeviceMemory memory = ctx.Device.AllocateMemory(new MemoryAllocateInfo(req.Size, memoryTypeIndex)); buffer.BindMemory(memory); // 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.CmdCopyBuffer(stagingBuffer, buffer, new BufferCopy(size)); cmdBuffer.End(); // Submit. Fence fence = ctx.Device.CreateFence(); ctx.GraphicsQueue.Submit(new SubmitInfo(commandBuffers: new[] { cmdBuffer }), fence); fence.Wait(); // Cleanup. fence.Dispose(); cmdBuffer.Dispose(); stagingBuffer.Dispose(); stagingMemory.Dispose(); return(new VulkanBuffer(buffer, memory, vertices.Length)); }
public static VulkanImage DepthStencil(VulkanContext device, int width, int height) { Format[] validFormats = { Format.D32SFloatS8UInt, Format.D32SFloat, Format.D24UNormS8UInt, Format.D16UNormS8UInt, Format.D16UNorm }; Format?potentialFormat = validFormats.FirstOrDefault( validFormat => { FormatProperties formatProps = device.PhysicalDevice.GetFormatProperties(validFormat); return((formatProps.OptimalTilingFeatures & FormatFeatures.DepthStencilAttachment) > 0); }); if (!potentialFormat.HasValue) { throw new InvalidOperationException("Required depth stencil format not supported."); } Format format = potentialFormat.Value; Image image = device.Device.CreateImage(new ImageCreateInfo { ImageType = ImageType.Image2D, Format = format, Extent = new Extent3D(width, height, 1), MipLevels = 1, ArrayLayers = 1, Samples = SampleCounts.Count1, Tiling = ImageTiling.Optimal, Usage = ImageUsages.DepthStencilAttachment | ImageUsages.TransferSrc }); MemoryRequirements memReq = image.GetMemoryRequirements(); int heapIndex = device.MemoryProperties.MemoryTypes.IndexOf( memReq.MemoryTypeBits, MemoryProperties.DeviceLocal); DeviceMemory memory = device.Device.AllocateMemory(new MemoryAllocateInfo(memReq.Size, heapIndex)); image.BindMemory(memory); ImageView view = image.CreateView(new ImageViewCreateInfo(format, new ImageSubresourceRange(ImageAspects.Depth | ImageAspects.Stencil, 0, 1, 0, 1))); return(new VulkanImage(image, memory, view, format)); }
public static VulkanBuffer DynamicUniform <T>(VulkanContext ctx, int count) where T : struct { long size = Interop.SizeOf <T>() * count; Buffer buffer = ctx.Device.CreateBuffer(new BufferCreateInfo(size, BufferUsages.UniformBuffer)); MemoryRequirements memoryRequirements = buffer.GetMemoryRequirements(); // We require host visible memory so we can map it and write to it directly. // We require host coherent memory so that writes are visible to the GPU right after unmapping it. int memoryTypeIndex = ctx.MemoryProperties.MemoryTypes.IndexOf( memoryRequirements.MemoryTypeBits, MemoryProperties.HostVisible | MemoryProperties.HostCoherent); DeviceMemory memory = ctx.Device.AllocateMemory(new MemoryAllocateInfo(memoryRequirements.Size, memoryTypeIndex)); buffer.BindMemory(memory); return(new VulkanBuffer(buffer, memory, count)); }
public static VulkanBuffer DynamicUniform <T>(VulkanContext ctx, int count) where T : struct { long size = Unsafe.SizeOf <T>() * count; VkBufferCreateInfo createInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, size = (ulong)size, usage = VkBufferUsageFlags.UniformBuffer }; VkBuffer buffer; VkResult result = vkCreateBuffer(ctx.Device, &createInfo, null, out buffer); result.CheckResult(); VkMemoryRequirements memoryRequirements; vkGetBufferMemoryRequirements(ctx.Device, buffer, out memoryRequirements); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); uint memoryTypeIndex = BufferHelper.GetMemoryTypeIndex(memoryRequirements.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, memoryProperties); // We require host visible memory so we can map it and write to it directly. // We require host coherent memory so that writes are visible to the GPU right after unmapping it. VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = memoryRequirements.size, memoryTypeIndex = memoryTypeIndex }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &memAllocInfo, null, &memory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, buffer, memory, 0); result.CheckResult(); return(new VulkanBuffer(ctx.Device, ctx.GraphicsCommandPool, buffer, memory, count)); }
public ContentManager(IVulkanAppHost host, VulkanContext ctx, string contentRoot) { _host = host; _ctx = ctx; _contentRoot = contentRoot; }
public static VulkanBuffer Storage <T>(VulkanContext ctx, T[] data) where T : unmanaged { return(GetBuffer <T>(ctx, data, VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.StorageBuffer)); }
public static VulkanBuffer Vertex <T>(VulkanContext ctx, T[] vertices) where T : unmanaged { return(GetBuffer <T>(ctx, vertices, VkBufferUsageFlags.VertexBuffer)); }
public static VulkanBuffer Index(VulkanContext ctx, int[] indices) { return(GetBuffer(ctx, indices, VkBufferUsageFlags.IndexBuffer)); }
private static VulkanBuffer GetBuffer <T>(VulkanContext ctx, T[] data, VkBufferUsageFlags usage) where T : unmanaged { long size = data.Length * Unsafe.SizeOf <T>(); // Create a staging buffer that is writable by host. var stagingCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, usage = VkBufferUsageFlags.TransferSrc, sharingMode = VkSharingMode.Exclusive, size = (ulong)size }; VkBuffer stagingBuffer; VkResult result = vkCreateBuffer( ctx.Device, &stagingCreateInfo, null, out stagingBuffer); result.CheckResult(); VkMemoryRequirements stagingReq; vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out stagingReq); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); uint stagingMemoryTypeIndex = BufferHelper.GetMemoryTypeIndex(stagingReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, memoryProperties); VkMemoryAllocateInfo allocateInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = stagingReq.size, memoryTypeIndex = stagingMemoryTypeIndex }; VkDeviceMemory stagingMemory; result = vkAllocateMemory(ctx.Device, &allocateInfo, null, &stagingMemory); result.CheckResult(); void *vertexPtr; result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)stagingReq.size, 0, &vertexPtr); result.CheckResult(); fixed(T *dataPtr = &data[0]) { System.Buffer.MemoryCopy(dataPtr, vertexPtr, size, size); } vkUnmapMemory(ctx.Device, stagingMemory); result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0); // Create a device local buffer where the data will be copied and which will be used for rendering. var bufferCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, usage = usage | VkBufferUsageFlags.TransferDst, sharingMode = VkSharingMode.Exclusive, size = (ulong)size }; VkBuffer buffer; result = vkCreateBuffer( ctx.Device, &bufferCreateInfo, null, out buffer); result.CheckResult(); VkMemoryRequirements req; vkGetBufferMemoryRequirements(ctx.Device, buffer, out req); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memProps); uint memoryTypeIndex = BufferHelper.GetMemoryTypeIndex(req.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, memProps); VkMemoryAllocateInfo bufferAllocInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = req.size, memoryTypeIndex = memoryTypeIndex }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &bufferAllocInfo, null, &memory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, buffer, memory, 0); // Copy the data from staging buffers to device local buffers. VkCommandBufferAllocateInfo allocInfo = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = ctx.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1, }; VkCommandBuffer cmdBuffer; vkAllocateCommandBuffers(ctx.Device, &allocInfo, &cmdBuffer); VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit, }; result = vkBeginCommandBuffer(cmdBuffer, &beginInfo); result.CheckResult(); VkBufferCopy bufferCopy = new VkBufferCopy { size = (ulong)size }; vkCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, 1, &bufferCopy); result = vkEndCommandBuffer(cmdBuffer); result.CheckResult(); // Submit. VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, pNext = null }; VkFence fence; result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence); result.CheckResult(); VkSubmitInfo submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, pNext = null, commandBufferCount = 1, pCommandBuffers = &cmdBuffer }; result = vkQueueSubmit(ctx.GraphicsQueue, 1, &submitInfo, fence); result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); // Cleanup. vkDestroyFence(ctx.Device, fence, null); vkFreeCommandBuffers(ctx.Device, ctx.GraphicsCommandPool, 1, &cmdBuffer); vkDestroyBuffer(ctx.Device, stagingBuffer, null); vkFreeMemory(ctx.Device, stagingMemory, null); return(new VulkanBuffer(ctx.Device, ctx.GraphicsCommandPool, buffer, memory, data.Length)); }
public static VulkanImage DepthStencil(VulkanContext device, int width, int height) { VkFormat[] validFormats = { VkFormat.D32SFloatS8UInt, VkFormat.D32SFloat, VkFormat.D24UNormS8UInt, VkFormat.D16UNormS8UInt, VkFormat.D16UNorm }; VkFormat?potentialFormat = validFormats.FirstOrDefault( validFormat => { VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(device.PhysicalDevice, validFormat, out formatProps); return((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.DepthStencilAttachment) > 0); }); if (!potentialFormat.HasValue) { throw new InvalidOperationException("Required depth stencil format not supported."); } VkFormat format = potentialFormat.Value; VkImageCreateInfo imageCreateInfo = new VkImageCreateInfo { sType = VkStructureType.ImageCreateInfo, pNext = null, imageType = VkImageType.Image2D, format = format, extent = new Vortice.Mathematics.Size3 { Width = width, Height = height, Depth = 1 }, mipLevels = 1, arrayLayers = 1, samples = VkSampleCountFlags.Count1, tiling = VkImageTiling.Optimal, usage = VkImageUsageFlags.DepthStencilAttachment | VkImageUsageFlags.TransferSrc }; VkImage image; VkResult result = vkCreateImage(device.Device, &imageCreateInfo, null, out image); result.CheckResult(); VkMemoryRequirements memReq; vkGetImageMemoryRequirements(device.Device, image, out memReq); vkGetPhysicalDeviceMemoryProperties(device.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); uint heapIndex = BufferHelper.GetMemoryTypeIndex(memReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, memoryProperties); VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = memReq.size, memoryTypeIndex = heapIndex }; VkDeviceMemory memory; result = vkAllocateMemory(device.Device, &memAllocInfo, null, &memory); result.CheckResult(); result = vkBindImageMemory(device.Device, image, memory, 0); result.CheckResult(); VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, pNext = null, format = format, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Depth | VkImageAspectFlags.Stencil, 0, 1, 0, 1), image = image, viewType = VkImageViewType.Image2D }; VkImageView view; result = vkCreateImageView(device.Device, &imageViewCreateInfo, null, out view); result.CheckResult(); return(new VulkanImage(device, image, memory, view, format)); }
internal static VulkanImage Texture2D(VulkanContext ctx, TextureData tex2D) { ulong size = (ulong)tex2D.Mipmaps[0].Size; VkBuffer stagingBuffer; var bufferCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, size = (ulong)tex2D.Mipmaps[0].Size, usage = VkBufferUsageFlags.TransferSrc }; vkCreateBuffer(ctx.Device, &bufferCreateInfo, null, out stagingBuffer); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out VkMemoryRequirements stagingMemReq); uint heapIndex = BufferHelper.GetMemoryTypeIndex(stagingMemReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible, memoryProperties); VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = stagingMemReq.size, memoryTypeIndex = heapIndex }; VkDeviceMemory stagingMemory; VkResult result = vkAllocateMemory(ctx.Device, &memAllocInfo, null, &stagingMemory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0); result.CheckResult(); void *vertexPtr; result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)tex2D.Mipmaps[0].Size, 0, &vertexPtr); result.CheckResult(); fixed(byte *dataPtr = &tex2D.Mipmaps[0].Data[0]) { Buffer.MemoryCopy(dataPtr, vertexPtr, size, size); } vkUnmapMemory(ctx.Device, stagingMemory); // Setup buffer copy regions for each mip level. var bufferCopyRegions = new VkBufferImageCopy[tex2D.Mipmaps.Length]; // TODO: stackalloc int offset = 0; for (int i = 0; i < bufferCopyRegions.Length; i++) { // TODO: from VulkanCore, doesn't look correct (reassigns bufferCopyRegions in each loop) bufferCopyRegions = new[] { new VkBufferImageCopy { imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)i, 0, 1), imageExtent = tex2D.Mipmaps[0].Extent, bufferOffset = (ulong)offset } }; offset += tex2D.Mipmaps[i].Size; } // Create optimal tiled target image. var createInfo = new VkImageCreateInfo { sType = VkStructureType.ImageCreateInfo, pNext = null, imageType = VkImageType.Image2D, format = tex2D.Format, mipLevels = (uint)tex2D.Mipmaps.Length, arrayLayers = 1, samples = VkSampleCountFlags.Count1, tiling = VkImageTiling.Optimal, sharingMode = VkSharingMode.Exclusive, initialLayout = VkImageLayout.Undefined, extent = tex2D.Mipmaps[0].Extent, usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst }; VkImage image; result = vkCreateImage(ctx.Device, &createInfo, null, out image); result.CheckResult(); VkMemoryRequirements imageMemReq; vkGetImageMemoryRequirements(ctx.Device, image, out imageMemReq); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties imageMemoryProperties); uint imageHeapIndex = BufferHelper.GetMemoryTypeIndex(imageMemReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, imageMemoryProperties); var allocInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = imageMemReq.size, memoryTypeIndex = imageHeapIndex, }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &allocInfo, null, &memory); result.CheckResult(); result = vkBindImageMemory(ctx.Device, image, memory, 0); result.CheckResult(); var subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, (uint)tex2D.Mipmaps.Length, 0, 1); // Copy the data from staging buffers to device local buffers. var allocInfo2 = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = ctx.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1, }; VkCommandBuffer cmdBuffer; vkAllocateCommandBuffers(ctx.Device, &allocInfo2, &cmdBuffer); VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit, }; vkBeginCommandBuffer(cmdBuffer, &beginInfo); VkImageMemoryBarrier imageMemoryBarrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = 0, dstAccessMask = VkAccessFlags.TransferWrite, oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.TransferDstOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); fixed(VkBufferImageCopy *regionsPtr = bufferCopyRegions) { vkCmdCopyBufferToImage(cmdBuffer, stagingBuffer, image, VkImageLayout.TransferDstOptimal, (uint)bufferCopyRegions.Length, regionsPtr); } VkImageMemoryBarrier imageMemoryBarrier2 = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = VkAccessFlags.TransferWrite, dstAccessMask = VkAccessFlags.ShaderRead, oldLayout = VkImageLayout.TransferDstOptimal, newLayout = VkImageLayout.ShaderReadOnlyOptimal, srcQueueFamilyIndex = (uint)QueueFamilyIgnored, dstQueueFamilyIndex = (uint)QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier2); vkEndCommandBuffer(cmdBuffer); // Submit. VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, pNext = null }; VkFence fence; result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence); result.CheckResult(); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, pNext = null, commandBufferCount = 1, pCommandBuffers = &cmdBuffer }; vkQueueSubmit(ctx.GraphicsQueue, submitInfo, fence); result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); // Cleanup staging resources. vkDestroyFence(ctx.Device, fence, null); vkFreeMemory(ctx.Device, stagingMemory, null); vkDestroyBuffer(ctx.Device, stagingBuffer, null); // Create image view. VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo() { sType = VkStructureType.ImageViewCreateInfo, image = image, viewType = VkImageViewType.Image2D, format = tex2D.Format, subresourceRange = subresourceRange }; VkImageView view; vkCreateImageView(ctx.Device, &imageViewCreateInfo, null, out view); return(new VulkanImage(ctx, image, memory, view, tex2D.Format)); }
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)); }
public void Initialize(IVulkanAppHost host) { Host = host; #if DEBUG const bool debug = true; #else const bool debug = false; #endif _initializingPermanent = true; VkResult result = vkInitialize(); result.CheckResult(); // Calling ToDispose here registers the resource to be automatically disposed on exit. Instance = CreateInstance(debug); Surface = CreateSurface(); Context = new VulkanContext(Instance, Surface, Host.Platform); Content = new ContentManager(Host, Context, "Content"); ImageAvailableSemaphore = CreateSemaphore(Context.Device); RenderingFinishedSemaphore = CreateSemaphore(Context.Device); _initializingPermanent = false; // Calling ToDispose here registers the resource to be automatically disposed on events // such as window resize. var swapchain = CreateSwapchain(); Swapchain = swapchain; ToDispose(new ActionDisposable(() => { vkDestroySwapchainKHR(Context.Device, swapchain, null); })); // Acquire underlying images of the freshly created swapchain. uint swapchainImageCount; result = vkGetSwapchainImagesKHR(Context.Device, Swapchain, &swapchainImageCount, null); result.CheckResult(); var swapchainImages = stackalloc VkImage[(int)swapchainImageCount]; result = vkGetSwapchainImagesKHR(Context.Device, Swapchain, &swapchainImageCount, swapchainImages); result.CheckResult(); SwapchainImages = new VkImage[swapchainImageCount]; for (int i = 0; i < swapchainImageCount; i++) { SwapchainImages[i] = swapchainImages[i]; } VkCommandBufferAllocateInfo allocInfo = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = Context.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = (uint)SwapchainImages.Length, }; VkCommandBuffer[] commandBuffers = new VkCommandBuffer[SwapchainImages.Length]; fixed(VkCommandBuffer *commandBuffersPtr = &commandBuffers[0]) { vkAllocateCommandBuffers(Context.Device, &allocInfo, commandBuffersPtr).CheckResult(); } CommandBuffers = commandBuffers; // Create a fence for each commandbuffer so that we can wait before using it again _initializingPermanent = true; //We need our fences to be there permanently SubmitFences = new VkFence[SwapchainImages.Length]; for (int i = 0; i < SubmitFences.Length; i++) { VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo() { sType = VkStructureType.FenceCreateInfo, pNext = null, flags = VkFenceCreateFlags.Signaled }; VkFence handle; vkCreateFence(Context.Device, &fenceCreateInfo, null, out handle); SubmitFences[i] = handle; ToDispose(new ActionDisposable(() => { vkDestroyFence(Context.Device, handle, null); })); } // Allow concrete samples to initialize their resources. InitializePermanent(); _initializingPermanent = false; InitializeFrame(); // Record commands for execution by Vulkan. RecordCommandBuffers(); }