Пример #1
0
        protected virtual void Draw(Timer timer)
        {
            // Acquire an index of drawing image for this frame.
            uint     nextImageIndex;
            VkResult result = vkAcquireNextImageKHR(Context.Device, Swapchain, ulong.MaxValue, ImageAvailableSemaphore, VkFence.Null, out nextImageIndex);

            result.CheckResult();

            // Use a fence to wait until the command buffer has finished execution before using it again
            VkFence fence = SubmitFences[nextImageIndex];

            result = vkWaitForFences(Context.Device, 1, &fence, false, ulong.MaxValue);
            result.CheckResult();

            result = vkResetFences(Context.Device, 1, &fence);
            result.CheckResult();

            VkSemaphore          signalSemaphore = RenderingFinishedSemaphore;
            VkSemaphore          waitSemaphore   = ImageAvailableSemaphore;
            VkPipelineStageFlags waitStages      = VkPipelineStageFlags.ColorAttachmentOutput;
            VkCommandBuffer      commandBuffer   = CommandBuffers[nextImageIndex];

            VkSubmitInfo submitInfo = new VkSubmitInfo()
            {
                sType = VkStructureType.SubmitInfo,
                waitSemaphoreCount   = 1,
                pWaitSemaphores      = &waitSemaphore,
                pWaitDstStageMask    = &waitStages,
                commandBufferCount   = 1,
                pCommandBuffers      = &commandBuffer,
                signalSemaphoreCount = 1,
                pSignalSemaphores    = &signalSemaphore,
            };

            result = vkQueueSubmit(Context.GraphicsQueue, 1, &submitInfo, SubmitFences[nextImageIndex]);
            result.CheckResult();

            // Present the color output to screen.
            VkSemaphore    waitSemaphoreHandle = RenderingFinishedSemaphore;
            VkSwapchainKHR swapchainHandle     = Swapchain;
            var            nativePresentInfo   = new VkPresentInfoKHR
            {
                sType = VkStructureType.PresentInfoKHR,
                pNext = null,
                waitSemaphoreCount = 1,
                pWaitSemaphores    = &waitSemaphoreHandle,
                swapchainCount     = 1,
                pSwapchains        = &swapchainHandle,
                pImageIndices      = &nextImageIndex
            };

            result = vkQueuePresentKHR(Context.PresentQueue, &nativePresentInfo);
            result.CheckResult();
        }
Пример #2
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));
        }
Пример #3
0
        private VkImage[] GetSwapchainImages(VkSwapchainKHR swapchain)
        {
            uint     swapchainImageCount;
            VkResult result = vkGetSwapchainImagesKHR(Context.Device, swapchain, &swapchainImageCount, null);

            result.CheckResult();

            var swapchainImages = stackalloc VkImage[(int)swapchainImageCount];

            result = vkGetSwapchainImagesKHR(Context.Device, swapchain, &swapchainImageCount, swapchainImages);
            result.CheckResult();

            var images = new VkImage[swapchainImageCount];

            for (int i = 0; i < swapchainImageCount; i++)
            {
                images[i] = swapchainImages[i];
            }
            return(images);
        }
Пример #4
0
        private VkSemaphore CreateSemaphore(VkDevice device)
        {
            VkSemaphoreCreateInfo createInfo = new VkSemaphoreCreateInfo
            {
                sType = VkStructureType.SemaphoreCreateInfo,
                pNext = null
            };

            VkSemaphore semaphore;
            VkResult    result = vkCreateSemaphore(device, &createInfo, null, out semaphore);

            result.CheckResult();
            return(semaphore);
        }
Пример #5
0
        public VulkanContext(VkInstance instance, VkSurfaceKHR surface, Platform platform)
        {
            // Find graphics and presentation capable physical device(s) that support
            // the provided surface for platform.
            int graphicsQueueFamilyIndex = -1;
            int computeQueueFamilyIndex  = -1;
            int presentQueueFamilyIndex  = -1;

            var physicalDevices = vkEnumeratePhysicalDevices(instance);

            foreach (var physicalDevice in physicalDevices)
            {
                uint Count = 0;

                vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &Count, null);
                VkQueueFamilyProperties *queueFamilyPropertiesptr = stackalloc VkQueueFamilyProperties[(int)Count];

                vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &Count, queueFamilyPropertiesptr);

                for (int i = 0; i < Count; i++)
                {
                    if (queueFamilyPropertiesptr[i].queueFlags.HasFlag(VkQueueFlags.Graphics))
                    {
                        if (graphicsQueueFamilyIndex == -1)
                        {
                            graphicsQueueFamilyIndex = i;
                        }
                        if (computeQueueFamilyIndex == -1)
                        {
                            computeQueueFamilyIndex = i;
                        }

                        VkBool32 isSupported;
                        uint     queueFamilyIndex = (uint)i;
                        VkResult result           = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, out isSupported);
                        result.CheckResult();

                        if (isSupported == VkBool32.True)
                        {
                            bool presentationSupport = false;
                            if (platform == Platform.Win32)
                            {
                                presentationSupport = vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
                            }
                            else
                            {
                                presentationSupport = true;
                            }

                            if (presentationSupport)
                            {
                                presentQueueFamilyIndex = i;
                            }
                        }

                        if (graphicsQueueFamilyIndex != -1 &&
                            computeQueueFamilyIndex != -1 &&
                            presentQueueFamilyIndex != -1)
                        {
                            PhysicalDevice = physicalDevice;
                            break;
                        }
                    }
                }
                if (PhysicalDevice != null)
                {
                    break;
                }
            }

            if (PhysicalDevice == null)
            {
                throw new InvalidOperationException("No suitable physical device found.");
            }

            vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties);
            MemoryProperties = memoryProperties;
            vkGetPhysicalDeviceFeatures(PhysicalDevice, out VkPhysicalDeviceFeatures features);
            Features = features;
            vkGetPhysicalDeviceProperties(PhysicalDevice, out VkPhysicalDeviceProperties physicalDeviceProperties);
            Properties = physicalDeviceProperties;

            // Create a logical device.
            bool sameGraphicsAndPresent = graphicsQueueFamilyIndex == presentQueueFamilyIndex;
            VkDeviceQueueCreateInfo *queueCreateInfos = stackalloc VkDeviceQueueCreateInfo[sameGraphicsAndPresent ? 1 : 2];

            float defaultQueuePriority = 1.0f;

            VkDeviceQueueCreateInfo queueInfoGraphics = new VkDeviceQueueCreateInfo
            {
                sType            = VkStructureType.DeviceQueueCreateInfo,
                queueFamilyIndex = (uint)graphicsQueueFamilyIndex,
                queueCount       = 1,
                pQueuePriorities = &defaultQueuePriority
            };

            queueCreateInfos[0] = queueInfoGraphics;

            if (!sameGraphicsAndPresent)
            {
                queueCreateInfos[1] = new VkDeviceQueueCreateInfo
                {
                    sType            = VkStructureType.DeviceQueueCreateInfo,
                    queueFamilyIndex = (uint)presentQueueFamilyIndex,
                    queueCount       = 1,
                    pQueuePriorities = &defaultQueuePriority
                };
            }

            VkDeviceCreateInfo deviceCreateInfo = new VkDeviceCreateInfo
            {
                sType = VkStructureType.DeviceCreateInfo,
                pNext = null,
                flags = VkDeviceCreateFlags.None,
                queueCreateInfoCount = (uint)(sameGraphicsAndPresent ? 1 : 2),
                pQueueCreateInfos    = queueCreateInfos,
            };

            deviceCreateInfo.pEnabledFeatures = &features;

            string[] deviceExtensions = new[] {
                // If the device will be used for presenting to a display via a swapchain we need to request the swapchain extension
                "VK_KHR_swapchain"
            };

            deviceCreateInfo.enabledExtensionCount   = (uint)deviceExtensions.Length;
            deviceCreateInfo.ppEnabledExtensionNames = Interop.String.AllocToPointers(deviceExtensions);

            VkResult result2 = vkCreateDevice(PhysicalDevice, &deviceCreateInfo, null, out VkDevice device);

            result2.CheckResult();

            Device = device;

            // Get queue(s).
            GraphicsQueue = GetQueue((uint)graphicsQueueFamilyIndex);
            ComputeQueue  = computeQueueFamilyIndex == graphicsQueueFamilyIndex
                ? GraphicsQueue
                : GetQueue((uint)computeQueueFamilyIndex);
            PresentQueue = presentQueueFamilyIndex == graphicsQueueFamilyIndex
                ? GraphicsQueue
                : GetQueue((uint)presentQueueFamilyIndex);

            GraphicsQueueFamilyIndex = graphicsQueueFamilyIndex;
            PresentQueueFamilyIndex  = presentQueueFamilyIndex;
            ComputeQueueFamilyIndex  = presentQueueFamilyIndex;

            GraphicsCommandPool = CreateCommandPool((uint)graphicsQueueFamilyIndex);
            ComputeCommandPool  = CreateCommandPool((uint)computeQueueFamilyIndex);
        }
Пример #6
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));
        }
Пример #7
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));
        }
Пример #8
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));
        }
        private VkPipeline CreateGraphicsPipeline()
        {
            // Create shader modules. Shader modules are one of the objects required to create the
            // graphics pipeline. But after the pipeline is created, we don't need these shader
            // modules anymore, so we dispose them.
            VkShaderModule vertexShader   = Content.LoadShader("Shader.vert.spv");
            VkShaderModule fragmentShader = Content.LoadShader("Shader.frag.spv");
            VkPipelineShaderStageCreateInfo *shaderStageCreateInfos = stackalloc VkPipelineShaderStageCreateInfo[2]
            {
                new VkPipelineShaderStageCreateInfo
                {
                    sType  = VkStructureType.PipelineShaderStageCreateInfo,
                    pNext  = null,
                    stage  = VkShaderStageFlags.Vertex,
                    module = vertexShader,
                    pName  = Interop.String.ToPointer("main")
                },
                new VkPipelineShaderStageCreateInfo
                {
                    sType  = VkStructureType.PipelineShaderStageCreateInfo,
                    pNext  = null,
                    stage  = VkShaderStageFlags.Fragment,
                    module = fragmentShader,
                    pName  = Interop.String.ToPointer("main")
                }
            };

            VkVertexInputBindingDescription vertexInputBindingDescription = new VkVertexInputBindingDescription
            {
                binding   = 0,
                stride    = (uint)Unsafe.SizeOf <Vertex>(),
                inputRate = VkVertexInputRate.Vertex
            };
            VkVertexInputAttributeDescription *vertexInputAttributeDescription = stackalloc VkVertexInputAttributeDescription[3]
            {
                new VkVertexInputAttributeDescription
                {
                    location = 0,
                    binding  = 0,
                    format   = VkFormat.R32G32B32A32SFloat,
                    offset   = 0
                },  // Position.
                new VkVertexInputAttributeDescription
                {
                    location = 1,
                    binding  = 0,
                    format   = VkFormat.R32G32B32SFloat,
                    offset   = 12
                }, // Normal.
                new VkVertexInputAttributeDescription
                {
                    location = 2,
                    binding  = 0,
                    format   = VkFormat.R32G32SFloat,
                    offset   = 24
                }// TexCoord.
            };
            var vertexInputStateCreateInfo = new VkPipelineVertexInputStateCreateInfo
            {
                sType = VkStructureType.PipelineVertexInputStateCreateInfo,
                pNext = null,
                vertexBindingDescriptionCount   = 1,
                pVertexBindingDescriptions      = &vertexInputBindingDescription,
                vertexAttributeDescriptionCount = 3,
                pVertexAttributeDescriptions    = vertexInputAttributeDescription
            };
            var inputAssemblyStateCreateInfo = new VkPipelineInputAssemblyStateCreateInfo
            {
                sType    = VkStructureType.PipelineInputAssemblyStateCreateInfo,
                pNext    = null,
                topology = VkPrimitiveTopology.TriangleList
            };

            Viewport  viewport = new Viewport(0, 0, Host.Width, Host.Height);
            Rectangle scissor  = new Rectangle(0, 0, Host.Width, Host.Height);

            var viewportStateCreateInfo = new VkPipelineViewportStateCreateInfo
            {
                sType         = VkStructureType.PipelineViewportStateCreateInfo,
                pNext         = null,
                viewportCount = 1,
                pViewports    = &viewport,
                scissorCount  = 1,
                pScissors     = &scissor
            };
            var rasterizationStateCreateInfo = new VkPipelineRasterizationStateCreateInfo
            {
                sType       = VkStructureType.PipelineRasterizationStateCreateInfo,
                polygonMode = VkPolygonMode.Fill,
                cullMode    = VkCullModeFlags.Back,
                frontFace   = VkFrontFace.CounterClockwise,
                lineWidth   = 1.0f
            };
            var multisampleStateCreateInfo = new VkPipelineMultisampleStateCreateInfo
            {
                sType = VkStructureType.PipelineMultisampleStateCreateInfo,
                rasterizationSamples = VkSampleCountFlags.Count1,
                minSampleShading     = 1.0f
            };
            var depthStencilStateCreateInfo = new VkPipelineDepthStencilStateCreateInfo
            {
                sType            = VkStructureType.PipelineDepthStencilStateCreateInfo,
                depthTestEnable  = true,
                depthWriteEnable = true,
                depthCompareOp   = VkCompareOp.LessOrEqual,
                back             = new VkStencilOpState
                {
                    failOp    = VkStencilOp.Keep,
                    passOp    = VkStencilOp.Keep,
                    compareOp = VkCompareOp.Always
                },
                front = new VkStencilOpState
                {
                    failOp    = VkStencilOp.Keep,
                    passOp    = VkStencilOp.Keep,
                    compareOp = VkCompareOp.Always
                }
            };
            var colorBlendAttachmentState = new VkPipelineColorBlendAttachmentState
            {
                srcColorBlendFactor = VkBlendFactor.One,
                dstColorBlendFactor = VkBlendFactor.Zero,
                colorBlendOp        = VkBlendOp.Add,
                srcAlphaBlendFactor = VkBlendFactor.One,
                dstAlphaBlendFactor = VkBlendFactor.Zero,
                alphaBlendOp        = VkBlendOp.Add,
                colorWriteMask      = VkColorComponentFlags.All
            };
            var colorBlendStateCreateInfo = new VkPipelineColorBlendStateCreateInfo
            {
                sType           = VkStructureType.PipelineColorBlendStateCreateInfo,
                pNext           = null,
                attachmentCount = 1,
                pAttachments    = &colorBlendAttachmentState
            };

            var pipelineCreateInfo = new VkGraphicsPipelineCreateInfo
            {
                sType               = VkStructureType.GraphicsPipelineCreateInfo,
                pNext               = null,
                layout              = _pipelineLayout,
                renderPass          = _renderPass,
                subpass             = (uint)0,
                stageCount          = 2,
                pStages             = shaderStageCreateInfos,
                pInputAssemblyState = &inputAssemblyStateCreateInfo,
                pVertexInputState   = &vertexInputStateCreateInfo,
                pRasterizationState = &rasterizationStateCreateInfo,
                pMultisampleState   = &multisampleStateCreateInfo,
                pColorBlendState    = &colorBlendStateCreateInfo,
                pDepthStencilState  = &depthStencilStateCreateInfo,
                pViewportState      = &viewportStateCreateInfo
            };


            VkPipeline pipeline;
            VkResult   result = vkCreateGraphicsPipelines(Context.Device, VkPipelineCache.Null, 1, &pipelineCreateInfo, null, &pipeline);

            result.CheckResult();

            return(pipeline);
        }
    }
}
Пример #10
0
        private void RecordCommandBuffers()
        {
            VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange()
            {
                aspectMask     = VkImageAspectFlags.Color,
                baseMipLevel   = 0,
                baseArrayLayer = 0,
                layerCount     = 1,
                levelCount     = 1
            };

            for (int i = 0; i < CommandBuffers.Length; i++)
            {
                VkCommandBuffer cmdBuffer = CommandBuffers[i];

                VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo()
                {
                    sType = VkStructureType.CommandBufferBeginInfo,
                    flags = VkCommandBufferUsageFlags.SimultaneousUse
                };
                vkBeginCommandBuffer(cmdBuffer, &beginInfo);

                if (Context.PresentQueue != Context.GraphicsQueue)
                {
                    var barrierFromPresentToDraw = new VkImageMemoryBarrier(
                        SwapchainImages[i], subresourceRange,
                        VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentWrite,
                        VkImageLayout.Undefined, VkImageLayout.PresentSrcKHR,
                        (uint)Context.PresentQueueFamilyIndex, (uint)Context.GraphicsQueueFamilyIndex);

                    vkCmdPipelineBarrier(cmdBuffer,
                                         VkPipelineStageFlags.ColorAttachmentOutput,
                                         VkPipelineStageFlags.ColorAttachmentOutput,
                                         0,
                                         0, null, 0, null,
                                         1, &barrierFromPresentToDraw
                                         );
                }

                RecordCommandBuffer(cmdBuffer, i);

                if (Context.PresentQueue != Context.GraphicsQueue)
                {
                    var barrierFromDrawToPresent = new VkImageMemoryBarrier(
                        SwapchainImages[i], subresourceRange,
                        VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead,
                        VkImageLayout.PresentSrcKHR, VkImageLayout.PresentSrcKHR,
                        (uint)Context.GraphicsQueueFamilyIndex, (uint)Context.PresentQueueFamilyIndex);

                    vkCmdPipelineBarrier(cmdBuffer,
                                         VkPipelineStageFlags.ColorAttachmentOutput,
                                         VkPipelineStageFlags.BottomOfPipe,
                                         0,
                                         0, null, 0, null,
                                         1, &barrierFromDrawToPresent
                                         );
                }

                VkResult result = vkEndCommandBuffer(cmdBuffer);
                result.CheckResult();
            }
        }
Пример #11
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();
        }