public void CreateDevice()
        {
            /*
             * We create the logical device in this function.
             */

            /*
             * When creating the device, we also specify what queues it has.
             */
            // Store memory properties of the physical device.
            PhysicalDeviceMemoryProperties MemoryProperties = physicalDevice.GetMemoryProperties();
            PhysicalDeviceFeatures         Features         = physicalDevice.GetFeatures();
            PhysicalDeviceProperties       Properties       = physicalDevice.GetProperties();

            // Create a logical device.
            var queueCreateInfos = new DeviceQueueCreateInfo[1];

            queueCreateInfos[0] = new DeviceQueueCreateInfo(computeQueueFamilyIndex, 1, 1.0f);

            var deviceCreateInfo = new DeviceCreateInfo(
                queueCreateInfos,
                new[] { Constant.DeviceExtension.NVExternalMemory },
                Features);

            device = physicalDevice.CreateDevice(deviceCreateInfo);

            // Get queue(s).
            queue = device.GetQueue(computeQueueFamilyIndex);

            // Create command pool(s).
            //commandPool = device.CreateCommandPool(new CommandPoolCreateInfo(computeQueueFamilyIndex));
        }
Exemple #2
0
        protected unsafe DeviceMemory AllocateMemory(MemoryPropertyFlags memoryProperties, MemoryRequirements memoryRequirements)
        {
            var allocateInfo = new MemoryAllocateInfo
            {
                StructureType  = StructureType.MemoryAllocateInfo,
                AllocationSize = memoryRequirements.Size,
            };

            PhysicalDeviceMemoryProperties physicalDeviceMemoryProperties;

            physicalDevice.GetMemoryProperties(out physicalDeviceMemoryProperties);

            var typeBits = memoryRequirements.MemoryTypeBits;

            for (uint i = 0; i < physicalDeviceMemoryProperties.MemoryTypeCount; i++)
            {
                if ((typeBits & 1) == 1)
                {
                    // Type is available, does it match user properties?
                    var memoryType = *((MemoryType *)&physicalDeviceMemoryProperties.MemoryTypes + i);
                    if ((memoryType.PropertyFlags & memoryProperties) == memoryProperties)
                    {
                        allocateInfo.MemoryTypeIndex = i;
                        break;
                    }
                }
                typeBits >>= 1;
            }

            return(device.AllocateMemory(ref allocateInfo));
        }
Exemple #3
0
        AppGpu AppGpuInit(uint id, PhysicalDevice obj)
        {
            // TODO : Limits

            AppGpu gpu = new AppGpu
            {
                Id          = id,
                Obj         = obj,
                Props       = obj.GetProperties(),
                QueueProps  = obj.GetQueueFamilyProperties(),
                MemoryProps = obj.GetMemoryProperties(),
                Features    = obj.GetFeatures(),
                Limits      = null,
            };

            gpu.QueueReqs = new DeviceQueueCreateInfo[gpu.QueueProps.Length];
            for (uint i = 0; i < gpu.QueueProps.Length; i++)
            {
                uint queueCount = gpu.QueueProps[i].QueueCount;
                DeviceQueueCreateInfo queueReq = new DeviceQueueCreateInfo
                {
                    QueueFamilyIndex = i,
                    QueueCount       = queueCount,
                    QueuePriorities  = new float[queueCount],
                };
                gpu.QueueReqs[i] = queueReq;
            }

            gpu.Device = AppDevInit(gpu);
            AppDevInitFormats(gpu.Device);

            return(gpu);
        }
Exemple #4
0
        public void BindMemoryAndCreateView()
        {
            using (Image image = CreateImage())
            {
                PhysicalDeviceMemoryProperties deviceMemProps = PhysicalDevice.GetMemoryProperties();
                MemoryRequirements memReq = image.GetMemoryRequirements();

                using (DeviceMemory memory = Device.AllocateMemory(new MemoryAllocateInfo(
                    memReq.Size, 
                    deviceMemProps.MemoryTypes.IndexOf(memReq.MemoryTypeBits, 0))))
                {
                    image.BindMemory(memory);

                    var createInfo = new ImageViewCreateInfo
                    {
                        Format = Format.B8G8R8A8UNorm,
                        ViewType = ImageViewType.Image2D,
                        SubresourceRange = new ImageSubresourceRange
                        {
                            AspectMask = ImageAspects.Color,
                            LayerCount = 1,
                            LevelCount = 1
                        }
                    };
                    using (image.CreateView(createInfo)) { }
                    using (image.CreateView(createInfo, CustomAllocator)) { }
                }
            }
        }
 private void PickPhysicalDevice()
 {
     // Currently simply picks the first physical device. We might want a smarter choice here.
     PhysicalDevice                 = Instance.EnumeratePhysicalDevices()[0];
     PhysicalDeviceFeatures         = PhysicalDevice.GetFeatures();
     PhysicalDeviceMemoryProperties = PhysicalDevice.GetMemoryProperties();
     AvailableDeviceExtensions      = PhysicalDevice.EnumerateExtensionProperties();
 }
Exemple #6
0
        public void Write(PhysicalDevice physicalDevice)
        {
            WriteLine("PhysicalDeviceProperties:");
            WriteLine("=========================");
            var properties = physicalDevice.GetProperties();

            _tabs++;
            PhysicalDeviceProperties(properties);

            WriteLine("PhysicalDeviceLimits:");
            WriteLine("---------------------");
            var limits = properties.Limits;

            _tabs++;
            PhysicalDeviceLimits(limits);

            _tabs--;
            WriteLine("PhysicalDeviceSparseProperties:");
            WriteLine("-------------------------------");
            var sparse = properties.SparseProperties;

            _tabs++;
            PhysicalDeviceSparseProperties(sparse);

            _tabs = 0;
            WriteLine("");
            var queueFamilyProperties = physicalDevice.GetQueueFamilyProperties();

            for (int x = 0; x < queueFamilyProperties.Length; x++)
            {
                WriteLine($"QueueFamilyProperties[{x}]:");
                WriteLine("==========================");
                _tabs++;
                QueueFamilyProperties(queueFamilyProperties[x]);
                _tabs--;
                WriteLine("");
            }

            _tabs = 0;
            WriteLine("PhysicalDeviceMemoryProperties");
            WriteLine("==============================");
            var physicalDeviceMemoryProperties = physicalDevice.GetMemoryProperties();

            _tabs++;
            PhysicalDeviceMemoryProperties(physicalDeviceMemoryProperties);
            WriteLine("");

            _tabs = 0;
            WriteLine("PhysicalDeviceFeatures:");
            WriteLine("=======================");
            var features = physicalDevice.GetFeatures();

            _tabs++;
            PhysicalDeviceFeatures(features);

            Console.WriteLine(_sb.ToString());
        }
Exemple #7
0
        Buffer CreateBuffer(PhysicalDevice physicalDevice, object values, BufferUsageFlags usageFlags, System.Type type)
        {
            var array            = values as System.Array;
            var length           = (array != null) ? array.Length : 1;
            var size             = System.Runtime.InteropServices.Marshal.SizeOf(type) * length;
            var createBufferInfo = new BufferCreateInfo {
                Size               = size,
                Usage              = usageFlags,
                SharingMode        = SharingMode.Exclusive,
                QueueFamilyIndices = new uint [] { 0 }
            };
            var buffer    = device.CreateBuffer(createBufferInfo);
            var memoryReq = device.GetBufferMemoryRequirements(buffer);
            var allocInfo = new MemoryAllocateInfo {
                AllocationSize = memoryReq.Size
            };
            var  memoryProperties = physicalDevice.GetMemoryProperties();
            bool heapIndexSet     = false;
            var  memoryTypes      = memoryProperties.MemoryTypes;

            for (uint i = 0; i < memoryProperties.MemoryTypeCount; i++)
            {
                if (((memoryReq.MemoryTypeBits >> (int)i) & 1) == 1 &&
                    (memoryTypes [i].PropertyFlags & MemoryPropertyFlags.HostVisible) == MemoryPropertyFlags.HostVisible)
                {
                    allocInfo.MemoryTypeIndex = i;
                    heapIndexSet = true;
                }
            }

            if (!heapIndexSet)
            {
                allocInfo.MemoryTypeIndex = memoryProperties.MemoryTypes [0].HeapIndex;
            }

            var deviceMemory = device.AllocateMemory(allocInfo);
            var memPtr       = device.MapMemory(deviceMemory, 0, size, 0);

            if (type == typeof(float))
            {
                System.Runtime.InteropServices.Marshal.Copy(values as float [], 0, memPtr, length);
            }
            else if (type == typeof(short))
            {
                System.Runtime.InteropServices.Marshal.Copy(values as short [], 0, memPtr, length);
            }
            else if (type == typeof(AreaUniformBuffer))
            {
                System.Runtime.InteropServices.Marshal.StructureToPtr(values, memPtr, false);
            }

            device.UnmapMemory(deviceMemory);
            device.BindBufferMemory(buffer, deviceMemory, 0);

            return(buffer);
        }
Exemple #8
0
        public void GetMemoryProperties()
        {
            PhysicalDeviceMemoryProperties properties = PhysicalDevice.GetMemoryProperties();

            Assert.True(properties.MemoryHeaps.Length > 0);
            Assert.True(properties.MemoryHeaps.All(x => x.Size > 0));
            Assert.True(properties.MemoryTypes.Length > 0);
            Assert.True(properties.MemoryTypes.All(x =>
                                                   x.HeapIndex >= 0 &&
                                                   x.HeapIndex < properties.MemoryHeaps.Length));
        }
Exemple #9
0
        public PhysicalDeviceInfo(PhysicalDevice physicalDevice)
        {
            PhysicalDevice        = physicalDevice;
            Properties            = PhysicalDevice.GetProperties();
            QueueFamilyProperties = PhysicalDevice.GetQueueFamilyProperties();
            MemoryProperties      = PhysicalDevice.GetMemoryProperties();
            Features = PhysicalDevice.GetFeatures();

            GraphicsQFamilies      = Array.AsReadOnly(QueueFamiliesWithFlag(QueueFlags.Graphics));
            ComputeQFamilies       = Array.AsReadOnly(QueueFamiliesWithFlag(QueueFlags.Compute));
            TransferQFamilies      = Array.AsReadOnly(QueueFamiliesWithFlag(QueueFlags.Transfer));
            SparseBindingQFamilies = Array.AsReadOnly(QueueFamiliesWithFlag(QueueFlags.SparseBinding));
        }
Exemple #10
0
        public void InvalidateMappedMemoryRange()
        {
            PhysicalDeviceMemoryProperties memoryProperties = PhysicalDevice.GetMemoryProperties();
            int memoryTypeIndex = memoryProperties.MemoryTypes.IndexOf(~0, MemoryProperties.HostVisible);

            const int size = 1024;

            using (var memory = Device.AllocateMemory(new MemoryAllocateInfo(size, memoryTypeIndex)))
            {
                memory.Map(0, size);
                Device.InvalidateMappedMemoryRange(new MappedMemoryRange(memory, 0, size));
                Device.InvalidateMappedMemoryRanges(new MappedMemoryRange(memory, 0, size));
                memory.Unmap();
            }
        }
        private uint FindMemoryType(uint typeFilter, MemoryPropertyFlags properties)
        {
            var memProperties = vkPhysicalDevice.GetMemoryProperties();

            for (var i = 0; i < memProperties.MemoryTypeCount; ++i)
            {
                if ((typeFilter & (1 << i)) != 0 &&
                    (memProperties.MemoryTypes[i].PropertyFlags & properties) != 0)
                {
                    return((uint)i);
                }
            }

            throw new InvalidOperationException("Failed to find suitable memory type");
        }
        static uint FindMemoryType(PhysicalDevice physicalDevice, uint typeFilter, MemoryPropertyFlags propertyFlags)
        {
            var memProperties = physicalDevice.GetMemoryProperties();

            uint i = 0;

            foreach (var memType in memProperties.MemoryTypes)
            {
                if ((((typeFilter >> (int)i) & 1) == 1) && ((memType.PropertyFlags & propertyFlags) == propertyFlags))
                {
                    return(i);
                }
                i++;
            }

            MGlobal.displayError("failed to find memory type");
            throw new Exception("failed to find memory type");
        }
Exemple #13
0
        public void BindMemoryAndCreateBufferView()
        {
            using (Buffer buffer = CreateBuffer())
            {
                PhysicalDeviceMemoryProperties deviceMemProps = PhysicalDevice.GetMemoryProperties();
                MemoryRequirements             memReq         = buffer.GetMemoryRequirements();
                var memoryAllocateInfo = new MemoryAllocateInfo(
                    memReq.Size,
                    deviceMemProps.MemoryTypes.IndexOf(memReq.MemoryTypeBits, 0));

                using (DeviceMemory memory = Device.AllocateMemory(memoryAllocateInfo))
                {
                    buffer.BindMemory(memory);

                    var bufferViewCreateInfo = new BufferViewCreateInfo(Format.R32UInt);
                    using (buffer.CreateView(bufferViewCreateInfo)) { }
                    using (buffer.CreateView(bufferViewCreateInfo, CustomAllocator)) { }
                }
            }
        }
        internal HostDevice(
            PhysicalDevice vulkanPhysicaldevice,
            SurfaceType surfaceType,
            Logger logger = null)
        {
            if (vulkanPhysicaldevice == null)
            {
                throw new ArgumentNullException(nameof(vulkanPhysicaldevice));
            }
            this.physicalDevice         = vulkanPhysicaldevice;
            this.surfaceType            = surfaceType;
            this.logger                 = logger;
            this.properties             = vulkanPhysicaldevice.GetProperties();
            this.deviceMemoryProperties = vulkanPhysicaldevice.GetMemoryProperties();
            this.supportedFeatures      = vulkanPhysicaldevice.GetFeatures();
            this.availableExtensions    = vulkanPhysicaldevice.EnumerateExtensionProperties();
            this.queueFamilies          = vulkanPhysicaldevice.GetQueueFamilyProperties();

            logger?.Log(nameof(HostDevice), $"Found device: {Name}");
            logger?.LogList(nameof(HostDevice), $"{Name} available extensions:", availableExtensions);
        }
Exemple #15
0
        public Context(GameWindow window)
        {
            Window              = window;
            Instance            = ToDispose(VKHelper.CreateInstance());
            DebugReportCallback = ToDispose(VKHelper.CreateDebugReportCallback(Instance));
            Surface             = ToDispose(VKHelper.CreateSurface(Instance, Window.Handle));

            foreach (PhysicalDevice physicalDevice in Instance.EnumeratePhysicalDevices())
            {
                QueueFamilyProperties[] queueFamilyProperties = physicalDevice.GetQueueFamilyProperties();
                for (int i = 0; i < queueFamilyProperties.Length; i++)
                {
                    if (queueFamilyProperties[i].QueueFlags.HasFlag(Queues.Graphics))
                    {
                        if (GraphicsQueueFamilyIndex == -1)
                        {
                            GraphicsQueueFamilyIndex = i;
                        }
                        if (ComputeQueueFamilyIndex == -1)
                        {
                            ComputeQueueFamilyIndex = i;
                        }

                        if (physicalDevice.GetSurfaceSupportKhr(i, Surface) &&
                            VKHelper.GetPresentationSupport(physicalDevice, i))
                        {
                            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.");
            }

            GenerateDepthStencilFormat();

            // Store memory properties of the physical device.
            MemoryProperties = PhysicalDevice.GetMemoryProperties();
            Features         = PhysicalDevice.GetFeatures();
            Properties       = PhysicalDevice.GetProperties();

            // Create a logical device.
            bool sameGraphicsAndPresent = GraphicsQueueFamilyIndex == PresentQueueFamilyIndex;
            var  queueCreateInfos       = new DeviceQueueCreateInfo[sameGraphicsAndPresent ? 1 : 2];

            queueCreateInfos[0] = new DeviceQueueCreateInfo(GraphicsQueueFamilyIndex, 1, 1.0f);
            if (!sameGraphicsAndPresent)
            {
                queueCreateInfos[1] = new DeviceQueueCreateInfo(PresentQueueFamilyIndex, 1, 1.0f);
            }

            var deviceCreateInfo = new DeviceCreateInfo(
                queueCreateInfos,
                new[] { Constant.DeviceExtension.KhrSwapchain, Constant.DeviceExtension.KhrMaintenance1 },
                Features);

            Device = PhysicalDevice.CreateDevice(deviceCreateInfo);

            // Get queue(s).
            GraphicsQueue = Device.GetQueue(GraphicsQueueFamilyIndex);
            ComputeQueue  = ComputeQueueFamilyIndex == GraphicsQueueFamilyIndex
                ? GraphicsQueue
                : Device.GetQueue(ComputeQueueFamilyIndex);
            PresentQueue = PresentQueueFamilyIndex == GraphicsQueueFamilyIndex
                ? GraphicsQueue
                : Device.GetQueue(PresentQueueFamilyIndex);

            Content = new Content(this);

            GraphicsCommandPool = ToDispose(Device.CreateCommandPool(new CommandPoolCreateInfo(GraphicsQueueFamilyIndex, CommandPoolCreateFlags.ResetCommandBuffer)));
            ComputeCommandPool  = ToDispose(Device.CreateCommandPool(new CommandPoolCreateInfo(ComputeQueueFamilyIndex)));

            Graphics = ToDispose(new Graphics(this));

            Build();
        }
        public VulkanContext(Instance instance, SurfaceKhr 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;

            foreach (PhysicalDevice physicalDevice in instance.EnumeratePhysicalDevices())
            {
                QueueFamilyProperties[] queueFamilyProperties = physicalDevice.GetQueueFamilyProperties();
                for (int i = 0; i < queueFamilyProperties.Length; i++)
                {
                    if (queueFamilyProperties[i].QueueFlags.HasFlag(Queues.Graphics))
                    {
                        if (graphicsQueueFamilyIndex == -1)
                        {
                            graphicsQueueFamilyIndex = i;
                        }
                        if (computeQueueFamilyIndex == -1)
                        {
                            computeQueueFamilyIndex = i;
                        }

                        if (physicalDevice.GetSurfaceSupportKhr(i, surface) &&
                            GetPresentationSupport(physicalDevice, i))
                        {
                            presentQueueFamilyIndex = i;
                        }

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

            bool GetPresentationSupport(PhysicalDevice physicalDevice, int queueFamilyIndex)
            {
                switch (platform)
                {
                case Platform.Android:
                    return(true);

                case Platform.Win32:
                    return(physicalDevice.GetWin32PresentationSupportKhr(queueFamilyIndex));

                default:
                    throw new NotImplementedException();
                }
            }

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

            // Store memory properties of the physical device.
            MemoryProperties = PhysicalDevice.GetMemoryProperties();
            Features         = PhysicalDevice.GetFeatures();
            Properties       = PhysicalDevice.GetProperties();

            // Create a logical device.
            bool sameGraphicsAndPresent = graphicsQueueFamilyIndex == presentQueueFamilyIndex;
            var  queueCreateInfos       = new DeviceQueueCreateInfo[sameGraphicsAndPresent ? 1 : 2];

            queueCreateInfos[0] = new DeviceQueueCreateInfo(graphicsQueueFamilyIndex, 1, 1.0f);
            if (!sameGraphicsAndPresent)
            {
                queueCreateInfos[1] = new DeviceQueueCreateInfo(presentQueueFamilyIndex, 1, 1.0f);
            }

            var deviceCreateInfo = new DeviceCreateInfo(
                queueCreateInfos,
                new[] { Constant.DeviceExtension.KhrSwapchain },
                Features);

            Device = PhysicalDevice.CreateDevice(deviceCreateInfo);

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

            // Create command pool(s).
            GraphicsCommandPool = Device.CreateCommandPool(new CommandPoolCreateInfo(graphicsQueueFamilyIndex));
            ComputeCommandPool  = Device.CreateCommandPool(new CommandPoolCreateInfo(computeQueueFamilyIndex));
        }
Exemple #17
0
        private static IEnumerable <MemoryTypeInfo> GetMemoryTypesAllowed(PhysicalDevice physicalDevice, uint memoryTypeBits)
        {
            var memoryTypes = physicalDevice.GetMemoryProperties().MemoryTypes;

            return(memoryTypes.Select((m, i) => new MemoryTypeInfo(i, m)).Where(m => ((memoryTypeBits >> m.MemoryTypeIndex) & 0x01) != 0));
        }
Exemple #18
0
 /// <summary>
 /// Construct a Graphics object belonging to a window
 /// </summary>
 /// <param name="window"></param>
 public Graphics(WyvernWindow window)
 {
     // Argument checks
     if (window is null)
     {
         throw new ArgumentNullException(nameof(window));
     }
     // Initialize the static part of Graphics if necessary
     InitializeStatic();
     // Store window
     Window = window;
     // Create window surface
     {
         AllocationCallbacks?allocationCallbacks = null;
         Surface = new SurfaceKhr(
             Instance,
             ref allocationCallbacks,
             VkGLFW3.VkGlfw.CreateWindowSurface(Instance.Handle, Window, IntPtr.Zero)
             );
         Surface.PrintDebug();
     }
     // Choose a physical device
     {
         PhysicalDevice = Instance.EnumeratePhysicalDevices()
                          .Where(e => GetDeviceMeetsRequirements(e, Surface))
                          .OrderByDescending(GetDeviceScore)
                          .FirstOrDefault();
         if (PhysicalDevice is null)
         {
             throw new InvalidOperationException("No physical device found that meets the requirements for the application");
         }
         MemoryProperties = PhysicalDevice.GetMemoryProperties();
     }
     // Create default queue families
     {
         ComputeQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(ComputeQueueFamily)}", this, QueueFamily.QueueType.Compute, 2,
             true, ComputeCommandPoolFlags
             );
         GraphicsQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(GraphicsQueueFamily)}", this, QueueFamily.QueueType.Graphics, 2,
             true, GraphicsCommandPoolFlags
             );
         TransferQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(TransferQueueFamily)}", this, QueueFamily.QueueType.Transfer, 2,
             true, TransferCommandPoolFlags
             );
         PresentQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(PresentQueueFamily)}", this, QueueFamily.QueueType.Present, 1,
             false
             );
     }
     // Create a logical device
     {
         // Generate queue create info structs
         var queueCreateInfos = QueueFamilies.Select(queueFamily =>
         {
             // Generate queue priorities
             var priorities = new float[queueFamily.Count];
             for (var i = 0; i < priorities.Length; i++)
             {
                 priorities[i] = 1f - (i / (float)(priorities.Length - 1));
             }
             // Create create info
             var createInfo = new DeviceQueueCreateInfo()
             {
                 QueueFamilyIndex = queueFamily.Index,
                 QueueCount       = queueFamily.Count,
                 QueuePriorities  = priorities
             };
             return(createInfo);
         });
         // Merge multiple queue families' queue create infos
         {
             var alreadyHave       = new List <int>();
             var uniqueCreateInfos = new List <DeviceQueueCreateInfo>();
             foreach (var createInfo in queueCreateInfos.OrderByDescending(e => e.QueueCount))
             {
                 if (!alreadyHave.Contains(createInfo.QueueFamilyIndex))
                 {
                     alreadyHave.Add(createInfo.QueueFamilyIndex);
                     uniqueCreateInfos.Add(createInfo);
                 }
             }
             queueCreateInfos = uniqueCreateInfos;
             foreach (var createInfo in queueCreateInfos)
             {
                 createInfo.PrintDebug();
             }
         }
         // Create device
         Device = PhysicalDevice.CreateDevice(new DeviceCreateInfo()
         {
             EnabledExtensionNames = EnabledDeviceExtensions.ToArray(),
             QueueCreateInfos      = queueCreateInfos.ToArray(),
             EnabledFeatures       = EnabledPhysicalDeviceFeatures
         });
         // Set the queues in the queue families, using those created with the device
         foreach (var family in QueueFamilies)
         {
             var queues = new Queue[family.Count];
             for (var i = 0; i < queues.Length; i++)
             {
                 queues[i] = Device.GetQueue(family.Index, i);
             }
             family.SetQueues(queues);
         }
         // Create and set the command pools in the queue families
         foreach (var family in QueueFamilies)
         {
             // Skip family that shouldn't have a command pool
             if (!family.HasCommandPool)
             {
                 continue;
             }
             // Create command pool
             var commandPool = Device.CreateCommandPool(new CommandPoolCreateInfo()
             {
                 QueueFamilyIndex = family.Index,
                 Flags            = family.CommandPoolFlags
             });
             family.SetCommandPool(commandPool);
         }
     }
     // Create swapchain
     {
         // Query supported capabilities and formats
         var surfaceCapabilities = SurfaceCapabilities;
         var surfaceFormats      = SurfaceFormats;
         var surfacePresentModes = SurfacePresentModes;
         surfaceCapabilities.PrintDebug();
         // Choose the best image format and color space
         {
             var imageFormat = Array.Find(
                 PreferredSwapchainFormats,
                 preferred => surfaceFormats.Any(available => available.Format == preferred)
                 );
             if (imageFormat == Format.Undefined)
             {
                 imageFormat = surfaceFormats.FirstOrDefault().Format;
             }
             if (imageFormat == Format.Undefined)
             {
                 throw new InvalidOperationException("Surface somehow does not support any known image formats");
             }
             SwapchainImageFormat = imageFormat;
             SwapchainColorSpace  = surfaceFormats.First(e => e.Format == SwapchainImageFormat).ColorSpace;
         }
         // Choose the best present mode
         {
             var presentMode = Array.Find(
                 PreferredPresentModes,
                 preferred => surfacePresentModes.Any(available => available == preferred)
                 );
             SwapchainPresentMode = presentMode;
         }
         // Create the swapchain
         SwapchainExtent = surfaceCapabilities.CurrentExtent;
         Swapchain       = Device.CreateSwapchainKhr(new SwapchainCreateInfoKhr(
                                                         surface: Surface,
                                                         imageFormat: SwapchainImageFormat,
                                                         imageExtent: SwapchainExtent,
                                                         preTransform: surfaceCapabilities.CurrentTransform,
                                                         presentMode: SwapchainPresentMode,
                                                         minImageCount: SurfaceCapabilities.MinImageCount,
                                                         imageArrayLayers: SurfaceCapabilities.MaxImageArrayLayers,
                                                         imageSharingMode: SharingMode.Exclusive,
                                                         imageColorSpace: SwapchainColorSpace
                                                         ));
         SwapchainAttachmentImages = Swapchain.GetImages().Select(
             e => new VKImage(
                 e, SwapchainImageFormat,
                 SwapchainExtent,
                 new ImageSubresourceRange(ImageAspects.Color, 0, 1, 0, 1)
                 )
             ).ToArray();
         Swapchain.PrintDebug();
     }
     // Create semaphores & fences
     {
         // Image available semaphore
         ImageAvailableSemaphore = Device.CreateSemaphore();
         ReadyToPresentSemaphore = Device.CreateSemaphore();
         // Swapchain image rendering fences
         RenderToImageFences = new Fence[SwapchainAttachmentImages.Length];
         for (var i = 0; i < RenderToImageFences.Length; i++)
         {
             RenderToImageFences[i] = Device.CreateFence(new FenceCreateInfo(flags: FenceCreateFlags.Signaled));
         }
     }
     // Create content collection
     {
         Content = new ContentCollection(this);
     }
     // Misc
     Stopwatch   = Stopwatch.StartNew();
     CurrentTime = 0.0;
 }