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 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)); }
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)); }
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)); }