Esempio n. 1
0
 private VulkanImage(VulkanContext ctx, VkImage image, VkDeviceMemory memory, VkImageView view, VkFormat format)
 {
     Image    = image;
     Memory   = memory;
     View     = view;
     Format   = format;
     this.ctx = ctx;
 }
Esempio n. 2
0
        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));
        }
Esempio n. 3
0
        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));
        }
Esempio n. 4
0
        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));
        }
Esempio n. 5
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));
        }
Esempio n. 6
0
 public ContentManager(IVulkanAppHost host, VulkanContext ctx, string contentRoot)
 {
     _host        = host;
     _ctx         = ctx;
     _contentRoot = contentRoot;
 }
Esempio n. 7
0
 public static VulkanBuffer Storage <T>(VulkanContext ctx, T[] data) where T : unmanaged
 {
     return(GetBuffer <T>(ctx, data, VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.StorageBuffer));
 }
Esempio n. 8
0
 public static VulkanBuffer Vertex <T>(VulkanContext ctx, T[] vertices) where T : unmanaged
 {
     return(GetBuffer <T>(ctx, vertices, VkBufferUsageFlags.VertexBuffer));
 }
Esempio n. 9
0
 public static VulkanBuffer Index(VulkanContext ctx, int[] indices)
 {
     return(GetBuffer(ctx, indices, VkBufferUsageFlags.IndexBuffer));
 }
Esempio n. 10
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));
        }
Esempio n. 11
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));
        }
Esempio n. 12
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));
        }
Esempio n. 13
0
        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));
        }
Esempio n. 14
0
        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();
        }