Example #1
0
        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));
        }
Example #2
0
        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));
        }
Example #3
0
        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));
        }
Example #4
0
        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));
        }