Пример #1
0
        /// <summary>
        /// Gets the version-aware features associated with the physical device.
        /// </summary>
        /// <param name="device">The device to get the features for.</param>
        /// <param name="props">The Vulkan 1.0 features.</param>
        /// <param name="props11">The Vulkan 1.1 features.</param>
        /// <param name="props12">The Vulkan 1.2 features.</param>
        public static void GetFeatures(VkPhysicalDevice device,
                                       out VkPhysicalDeviceFeatures feats,
                                       out VkPhysicalDeviceVulkan11Features feats11,
                                       out VkPhysicalDeviceVulkan12Features feats12)
        {
            if (!device)
            {
                throw new ArgumentNullException(nameof(device), "Cannot pass null device or device handle");
            }

            VkPhysicalDeviceFeatures.New(out feats);
            VkPhysicalDeviceVulkan11Features.New(out feats11);
            VkPhysicalDeviceVulkan12Features.New(out feats12);
            var version = device.Parent.Functions.CoreVersion;

            // 1.0
            if (version < VkVersion.VK_VERSION_1_1)
            {
                device.GetPhysicalDeviceFeatures(out feats);
            }
            // 1.1
            else if (version < VkVersion.VK_VERSION_1_2)
            {
                VkPhysicalDeviceFeatures2.New(out var feats2);
                fixed(VkPhysicalDeviceVulkan11Features *ptr11 = &feats11)
                {
                    feats2.pNext = ptr11;
                    device.GetPhysicalDeviceFeatures2(&feats2);
                    feats = feats2.Features;
                }
            }
            // 1.2
            else
            {
                VkPhysicalDeviceFeatures2.New(out var feats2);
                fixed(VkPhysicalDeviceVulkan11Features *ptr11 = &feats11)
                fixed(VkPhysicalDeviceVulkan12Features * ptr12 = &feats12)
                {
                    feats2.pNext = ptr11;
                    ptr11->pNext = ptr12;
                    device.GetPhysicalDeviceFeatures2(&feats2);
                    feats        = feats2.Features;
                    ptr11->pNext = null;
                }
            }
        }
Пример #2
0
        public GraphicsDevice(string applicationName, bool enableValidation, Window?window)
        {
            VkString name    = applicationName;
            var      appInfo = new VkApplicationInfo
            {
                sType              = VkStructureType.ApplicationInfo,
                pApplicationName   = name,
                applicationVersion = new VkVersion(1, 0, 0),
                pEngineName        = s_EngineName,
                engineVersion      = new VkVersion(1, 0, 0),
                apiVersion         = vkEnumerateInstanceVersion()
            };

            List <string> instanceExtensions = new List <string>
            {
                KHRSurfaceExtensionName
            };

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                instanceExtensions.Add(KHRWin32SurfaceExtensionName);
            }

            List <string> instanceLayers = new List <string>();

            if (enableValidation)
            {
                FindValidationLayers(instanceLayers);
            }

            if (instanceLayers.Count > 0)
            {
                instanceExtensions.Add(EXTDebugUtilsExtensionName);
            }

            using var vkInstanceExtensions = new VkStringArray(instanceExtensions);

            var instanceCreateInfo = new VkInstanceCreateInfo
            {
                sType                   = VkStructureType.InstanceCreateInfo,
                pApplicationInfo        = &appInfo,
                enabledExtensionCount   = vkInstanceExtensions.Length,
                ppEnabledExtensionNames = vkInstanceExtensions
            };

            using var vkLayerNames = new VkStringArray(instanceLayers);
            if (instanceLayers.Count > 0)
            {
                instanceCreateInfo.enabledLayerCount   = vkLayerNames.Length;
                instanceCreateInfo.ppEnabledLayerNames = vkLayerNames;
            }

            var debugUtilsCreateInfo = new VkDebugUtilsMessengerCreateInfoEXT
            {
                sType = VkStructureType.DebugUtilsMessengerCreateInfoEXT
            };

            if (instanceLayers.Count > 0)
            {
                _debugMessengerCallbackFunc          = DebugMessengerCallback;
                debugUtilsCreateInfo.messageSeverity = VkDebugUtilsMessageSeverityFlagsEXT.Error | VkDebugUtilsMessageSeverityFlagsEXT.Warning;
                debugUtilsCreateInfo.messageType     = VkDebugUtilsMessageTypeFlagsEXT.Validation | VkDebugUtilsMessageTypeFlagsEXT.Performance;
                debugUtilsCreateInfo.pfnUserCallback = Marshal.GetFunctionPointerForDelegate(_debugMessengerCallbackFunc);

                instanceCreateInfo.pNext = &debugUtilsCreateInfo;
            }

            VkResult result = vkCreateInstance(&instanceCreateInfo, null, out VkInstance);

            if (result != VkResult.Success)
            {
                throw new InvalidOperationException($"Failed to create vulkan instance: {result}");
            }

            vkLoadInstance(VkInstance);

            if (instanceLayers.Count > 0)
            {
                vkCreateDebugUtilsMessengerEXT(VkInstance, &debugUtilsCreateInfo, null, out _debugMessenger).CheckResult();
            }

            Log.Info($"Created VkInstance with version: {appInfo.apiVersion.Major}.{appInfo.apiVersion.Minor}.{appInfo.apiVersion.Patch}");
            if (instanceLayers.Count > 0)
            {
                foreach (var layer in instanceLayers)
                {
                    Log.Info($"Instance layer '{layer}'");
                }
            }

            foreach (string extension in instanceExtensions)
            {
                Log.Info($"Instance extension '{extension}'");
            }

            _surface = CreateSurface(window);

            // Find physical device, setup queue's and create device.
            var physicalDevices = vkEnumeratePhysicalDevices(VkInstance);

            foreach (var physicalDevice in physicalDevices)
            {
                //vkGetPhysicalDeviceProperties(physicalDevice, out var properties);
                //var deviceName = properties.GetDeviceName();
            }

            PhysicalDevice = physicalDevices[0];
            vkGetPhysicalDeviceProperties(PhysicalDevice, out VkPhysicalDeviceProperties properties);

            var queueFamilies = FindQueueFamilies(PhysicalDevice, _surface);

            var availableDeviceExtensions = vkEnumerateDeviceExtensionProperties(PhysicalDevice);

            var priority        = 1.0f;
            var queueCreateInfo = new VkDeviceQueueCreateInfo
            {
                sType            = VkStructureType.DeviceQueueCreateInfo,
                queueFamilyIndex = queueFamilies.graphicsFamily,
                queueCount       = 1,
                pQueuePriorities = &priority
            };

            List <string> deviceExtensions = new List <string>
            {
                KHRSwapchainExtensionName
            };

            if (CheckDeviceExtensionSupport(KHRSpirv14ExtensionName, availableDeviceExtensions))
            {
                deviceExtensions.Add(KHRSpirv14ExtensionName);
            }

            if (CheckDeviceExtensionSupport(KHRFragmentShadingRateExtensionName, availableDeviceExtensions))
            {
                deviceExtensions.Add(KHRFragmentShadingRateExtensionName);
            }

            if (CheckDeviceExtensionSupport(NVMeshShaderExtensionName, availableDeviceExtensions))
            {
                deviceExtensions.Add(NVMeshShaderExtensionName);
            }

            VkPhysicalDeviceVulkan11Features features_1_1 = new VkPhysicalDeviceVulkan11Features
            {
                sType = VkStructureType.PhysicalDeviceVulkan11Features
            };

            VkPhysicalDeviceVulkan12Features features_1_2 = new VkPhysicalDeviceVulkan12Features
            {
                sType = VkStructureType.PhysicalDeviceVulkan12Features
            };

            VkPhysicalDeviceFeatures2 deviceFeatures2 = new VkPhysicalDeviceFeatures2
            {
                sType = VkStructureType.PhysicalDeviceFeatures2
            };

            deviceFeatures2.pNext = &features_1_1;
            features_1_1.pNext    = &features_1_2;

            void **features_chain = &features_1_2.pNext;

            VkPhysicalDevice8BitStorageFeatures storage_8bit_features = default;

            if (properties.apiVersion <= VkVersion.Version_1_2)
            {
                if (CheckDeviceExtensionSupport(KHR8bitStorageExtensionName, availableDeviceExtensions))
                {
                    deviceExtensions.Add(KHR8bitStorageExtensionName);
                    storage_8bit_features.sType = VkStructureType.PhysicalDevice8bitStorageFeatures;
                    *features_chain = &storage_8bit_features;
                    features_chain = &storage_8bit_features.pNext;
                }
            }

            VkPhysicalDeviceAccelerationStructureFeaturesKHR acceleration_structure_features = default;

            if (CheckDeviceExtensionSupport(KHRAccelerationStructureExtensionName, availableDeviceExtensions))
            {
                deviceExtensions.Add(KHRAccelerationStructureExtensionName);
                acceleration_structure_features.sType = VkStructureType.PhysicalDeviceAccelerationStructureFeaturesKHR;
                *features_chain = &acceleration_structure_features;
                features_chain = &acceleration_structure_features.pNext;
            }

            vkGetPhysicalDeviceFeatures2(PhysicalDevice, out deviceFeatures2);

            using var deviceExtensionNames = new VkStringArray(deviceExtensions);

            var deviceCreateInfo = new VkDeviceCreateInfo
            {
                sType = VkStructureType.DeviceCreateInfo,
                pNext = &deviceFeatures2,
                queueCreateInfoCount    = 1,
                pQueueCreateInfos       = &queueCreateInfo,
                enabledExtensionCount   = deviceExtensionNames.Length,
                ppEnabledExtensionNames = deviceExtensionNames,
                pEnabledFeatures        = null,
            };

            result = vkCreateDevice(PhysicalDevice, &deviceCreateInfo, null, out VkDevice);
            if (result != VkResult.Success)
            {
                throw new Exception($"Failed to create Vulkan Logical Device, {result}");
            }

            vkGetDeviceQueue(VkDevice, queueFamilies.graphicsFamily, 0, out GraphicsQueue);
            vkGetDeviceQueue(VkDevice, queueFamilies.presentFamily, 0, out PresentQueue);

            // Create swap chain
            Swapchain = new Swapchain(this, window);
            _perFrame = new PerFrame[Swapchain.ImageCount];
            for (var i = 0; i < _perFrame.Length; i++)
            {
                VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo(VkFenceCreateFlags.Signaled);
                vkCreateFence(VkDevice, &fenceCreateInfo, null, out _perFrame[i].QueueSubmitFence).CheckResult();

                VkCommandPoolCreateInfo poolCreateInfo = new VkCommandPoolCreateInfo
                {
                    sType            = VkStructureType.CommandPoolCreateInfo,
                    flags            = VkCommandPoolCreateFlags.Transient,
                    queueFamilyIndex = queueFamilies.graphicsFamily,
                };
                vkCreateCommandPool(VkDevice, &poolCreateInfo, null, out _perFrame[i].PrimaryCommandPool).CheckResult();

                VkCommandBufferAllocateInfo commandBufferInfo = new VkCommandBufferAllocateInfo
                {
                    sType              = VkStructureType.CommandBufferAllocateInfo,
                    commandPool        = _perFrame[i].PrimaryCommandPool,
                    level              = VkCommandBufferLevel.Primary,
                    commandBufferCount = 1
                };
                vkAllocateCommandBuffers(VkDevice, &commandBufferInfo, out _perFrame[i].PrimaryCommandBuffer).CheckResult();
            }
        }
Пример #3
0
        public static void Init()
        {
            optionalExtn_avail      = new bool[optionalDeviceExtns.Length];
            Console.BackgroundColor = ConsoleColor.Black;
            Console.ForegroundColor = ConsoleColor.White;
            Window = new GameWindow(AppName);
            fixed(IntPtr *instancePtr = &instanceHndl)
            fixed(IntPtr * surfacePtr = &surfaceHndl)
            {
                VkResult res;
                var      instLayers  = new List <string>();
                var      instExtns   = new List <string>();
                var      devExtns    = new List <string>();
                uint     glfwExtnCnt = 0;
                var      glfwExtns   = glfwGetRequiredInstanceExtensions(&glfwExtnCnt);

                for (int i = 0; i < glfwExtnCnt; i++)
                {
                    instExtns.Add(Marshal.PtrToStringAnsi(glfwExtns[i]));
                }

                instExtns.Add(VkKhrGetPhysicalDeviceProperties2ExtensionName);

                if (EnableValidation)
                {
                    instLayers.Add("VK_LAYER_KHRONOS_validation");
                    instExtns.Add(VkExtDebugUtilsExtensionName);
                }

                var layers = stackalloc IntPtr[instLayers.Count];

                for (int i = 0; i < instLayers.Count; i++)
                {
                    layers[i] = Marshal.StringToHGlobalAnsi(instLayers[i]);
                }

                var extns = stackalloc IntPtr[instExtns.Count];

                for (int i = 0; i < instExtns.Count; i++)
                {
                    extns[i] = Marshal.StringToHGlobalAnsi(instExtns[i]);
                }
                {
                    var appInfo =
                        new VkApplicationInfo()
                    {
                        sType              = VkStructureType.StructureTypeApplicationInfo,
                        pApplicationName   = AppName,
                        pEngineName        = EngineName,
                        apiVersion         = VkApiVersion12,
                        applicationVersion = 1,
                        engineVersion      = 1,
                        pNext              = IntPtr.Zero
                    };
                    var appInfo_ptr = appInfo.Pointer();

                    var instCreatInfo = new VkInstanceCreateInfo()
                    {
                        sType            = VkStructureType.StructureTypeInstanceCreateInfo,
                        pApplicationInfo = appInfo_ptr,
                    };

                    instCreatInfo.ppEnabledLayerNames     = layers;
                    instCreatInfo.enabledLayerCount       = (uint)instLayers.Count;
                    instCreatInfo.ppEnabledExtensionNames = extns;
                    instCreatInfo.enabledExtensionCount   = (uint)instExtns.Count;

                    var instCreatInfo_ptr = instCreatInfo.Pointer();

                    //register instance create debug message handler
                    debugCreatInfo = new VkDebugUtilsMessengerCreateInfoEXT()
                    {
                        sType           = VkStructureType.StructureTypeDebugUtilsMessengerCreateInfoExt,
                        messageSeverity = VkDebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt | VkDebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt | VkDebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityVerboseBitExt | VkDebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityInfoBitExt,
                        messageType     = VkDebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeGeneralBitExt | VkDebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypePerformanceBitExt | VkDebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt,
                        pfnUserCallback = DebugCallback
                    };
                    var debugCreatInfo_ptr = debugCreatInfo.Pointer();

                    if (EnableValidation)
                    {
                        instCreatInfo.pNext = debugCreatInfo_ptr;
                    }

                    res = vkCreateInstance(instCreatInfo_ptr, null, instancePtr);
                    if (res != VkResult.Success)
                    {
                        throw new Exception("Failed to create instance.");
                    }
                }

                if (EnableValidation)
                {
                    SetupDebugMessengers(instanceHndl);
                    var debugCreatInfo_ptr = debugCreatInfo.Pointer();

                    fixed(IntPtr *dbg_ptr = &debugMessenger)
                    res = CreateDebugUtilsMessengerEXT(instanceHndl, debugCreatInfo_ptr, IntPtr.Zero, dbg_ptr);

                    if (res != VkResult.Success)
                    {
                        throw new Exception("Failed to register debug callback.");
                    }
                }

                res = Window.CreateSurface(instanceHndl, surfacePtr);
                if (res != VkResult.Success)
                {
                    throw new Exception("Failed to create surface.");
                }

                uint devCount = 0;

                vkEnumeratePhysicalDevices(instanceHndl, &devCount, null);
                if (devCount == 0)
                {
                    throw new Exception("Failed to find Vulkan compatible devices.");
                }

                var devices = new IntPtr[devCount];

                fixed(IntPtr *devicesPtr = devices)
                vkEnumeratePhysicalDevices(instanceHndl, &devCount, devicesPtr);

                var ratedDevices = new List <(uint, IntPtr)>();

                for (int i = 0; i < devices.Length; i++)
                {
                    //rate each device
                    ratedDevices.Add((RateDevice(devices[i]), devices[i]));
                }
                var orderedDevices = ratedDevices.OrderByDescending(a => a.Item1)
                                     .Select(a => a.Item2)
                                     .ToArray();

                DeviceInformation    = new DeviceInfo[orderedDevices.Length];
                DeviceInformation[0] = new DeviceInfo()
                {
                    PhysicalDevice = orderedDevices[0]
                };
                //TODO for now just choose the first device

                {
                    //allocate queues for primary device
                    uint graphicsFamily = ~0u;
                    uint computeFamily  = ~0u;
                    uint transferFamily = ~0u;
                    uint presentFamily  = ~0u;

                    uint qfam_cnt = 0;
                    vkGetPhysicalDeviceQueueFamilyProperties(orderedDevices[0], &qfam_cnt, null);
                    var qFams_ptr = new ManagedPtrArray <VkQueueFamilyProperties>(qfam_cnt);
                    vkGetPhysicalDeviceQueueFamilyProperties(orderedDevices[0], &qfam_cnt, qFams_ptr);
                    var qFams = qFams_ptr.Value;

                    uint qFamIdx = 0;
                    foreach (var qFam in qFams)
                    {
                        bool presentSupport = false;
                        vkGetPhysicalDeviceSurfaceSupportKHR(orderedDevices[0], qFamIdx, surfaceHndl, &presentSupport);

                        if ((qFam.queueFlags & VkQueueFlags.QueueGraphicsBit) != 0 && graphicsFamily == ~0u)
                        {
                            graphicsFamily = qFamIdx;
                            if (presentSupport)
                            {
                                presentFamily = qFamIdx;
                            }
                            qFamIdx++;
                            continue;
                        }

                        if ((qFam.queueFlags & VkQueueFlags.QueueComputeBit) != 0 && computeFamily == ~0u)
                        {
                            computeFamily = qFamIdx;
                            if ((qFam.queueFlags & VkQueueFlags.QueueTransferBit) != 0)
                            {
                                transferFamily = qFamIdx;
                            }
                            qFamIdx++;
                            continue;
                        }

                        if ((qFam.queueFlags & VkQueueFlags.QueueTransferBit) != 0)
                        {
                            transferFamily = qFamIdx;
                        }

                        if (graphicsFamily != ~0u && computeFamily != ~0u && transferFamily != ~0u && presentFamily != ~0u)
                        {
                            break;
                        }
                        qFamIdx++;
                    }

                    if (presentFamily == ~0u)
                    {
                        throw new Exception("Separate present queue support hasn't been implemented.");
                    }

                    var max_q_priority          = stackalloc float[] { 1.0f };
                    var dual_graph_q_priority   = stackalloc float[] { 1.0f };
                    var triple_graph_q_priority = stackalloc float[] { 1.0f, 1.0f, 1.0f };

                    VkDeviceQueueCreateInfo graphics_qCreatInfo = new VkDeviceQueueCreateInfo()
                    {
                        sType            = VkStructureType.StructureTypeDeviceQueueCreateInfo,
                        queueFamilyIndex = graphicsFamily,
                        queueCount       = 1,
                        pQueuePriorities = max_q_priority
                    };

                    VkDeviceQueueCreateInfo compute_qCreatInfo = new VkDeviceQueueCreateInfo
                    {
                        sType            = VkStructureType.StructureTypeDeviceQueueCreateInfo,
                        queueFamilyIndex = computeFamily,
                        queueCount       = 1,
                        pQueuePriorities = max_q_priority
                    };

                    VkDeviceQueueCreateInfo transfer_qCreatInfo = new VkDeviceQueueCreateInfo();
                    if (transferFamily != graphicsFamily)
                    {
                        transfer_qCreatInfo.sType            = VkStructureType.StructureTypeDeviceQueueCreateInfo;
                        transfer_qCreatInfo.queueFamilyIndex = transferFamily;
                        transfer_qCreatInfo.queueCount       = 1;
                        transfer_qCreatInfo.pQueuePriorities = max_q_priority;
                    }
                    else
                    {
                        graphics_qCreatInfo.queueCount       = 2;
                        graphics_qCreatInfo.pQueuePriorities = dual_graph_q_priority;
                    }


                    var qCreatInfos = new VkDeviceQueueCreateInfo[3];
                    qCreatInfos[0] = graphics_qCreatInfo;
                    qCreatInfos[1] = compute_qCreatInfo;
                    if (transferFamily != graphicsFamily)
                    {
                        qCreatInfos[2] = transfer_qCreatInfo;
                    }

                    DeviceInformation[0].GraphicsFamily = graphicsFamily;
                    DeviceInformation[0].ComputeFamily  = computeFamily;
                    DeviceInformation[0].TransferFamily = transferFamily;
                    DeviceInformation[0].PresentFamily  = presentFamily;

                    VkPhysicalDeviceFeatures devFeats = new VkPhysicalDeviceFeatures()
                    {
                        multiDrawIndirect              = true,
                        drawIndirectFirstInstance      = true,
                        fullDrawIndexUint32            = true,
                        tessellationShader             = true,
                        fragmentStoresAndAtomics       = true,
                        vertexPipelineStoresAndAtomics = true,
                        robustBufferAccess             = EnableValidation,
                        shaderInt16       = true,
                        samplerAnisotropy = true,
                        fillModeNonSolid  = true,
                        largePoints       = true,
                    };

                    var devFeats11 = new VkPhysicalDeviceVulkan11Features()
                    {
                        sType = VkStructureType.StructureTypePhysicalDeviceVulkan11Features,
                        shaderDrawParameters = true,
                        //storageBuffer16BitAccess = true,
                        //uniformAndStorageBuffer16BitAccess = true,
                        //storagePushConstant16 = true,
                    };
                    var devFeats11_ptr = devFeats11.Pointer();

                    /*
                     * var depthStenc = new VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures()
                     * {
                     *  sType = VkStructureType.StructureTypePhysicalDeviceSeparateDepthStencilLayoutsFeatures,
                     *  separateDepthStencilLayouts = true,
                     *  pNext = devFeats11_ptr
                     * };
                     * var depthStenc_ptr = depthStenc.Pointer();
                     *
                     * var timelineSems = new VkPhysicalDeviceTimelineSemaphoreFeatures()
                     * {
                     *  sType = VkStructureType.StructureTypePhysicalDeviceTimelineSemaphoreFeatures,
                     *  timelineSemaphore = true,
                     *  pNext = depthStenc_ptr,
                     * };
                     * var timelineSems_ptr = timelineSems.Pointer();
                     *
                     * var indirectCnt = new VkPhysicalDeviceShaderFloat16Int8Features()
                     * {
                     *  sType = VkStructureType.StructureTypePhysicalDeviceShaderFloat16Int8Features,
                     *  shaderFloat16 = true,
                     *  shaderInt8 = true,
                     *  pNext = timelineSems_ptr,
                     * };
                     * var indirectCnt_ptr = indirectCnt.Pointer();
                     *
                     * var uboLayout = new VkPhysicalDeviceUniformBufferStandardLayoutFeatures()
                     * {
                     *  sType = VkStructureType.StructureTypePhysicalDeviceUniformBufferStandardLayoutFeatures,
                     *  uniformBufferStandardLayout = true,
                     *  pNext = indirectCnt_ptr
                     * };
                     * var uboLayout_ptr = uboLayout.Pointer();
                     *
                     * var storageByte = new VkPhysicalDevice8BitStorageFeatures()
                     * {
                     *  sType = VkStructureType.StructureTypePhysicalDevice8bitStorageFeatures,
                     *  storageBuffer8BitAccess = true,
                     *  uniformAndStorageBuffer8BitAccess = true,
                     *  pNext = uboLayout_ptr
                     * };
                     * var storageByte_ptr = storageByte.Pointer();
                     * var descIndexing = new VkPhysicalDeviceDescriptorIndexingFeatures()
                     * {
                     *  sType = VkStructureType.StructureTypePhysicalDeviceDescriptorIndexingFeatures,
                     *  descriptorBindingSampledImageUpdateAfterBind = true,
                     *  descriptorBindingStorageBufferUpdateAfterBind = true,
                     *  descriptorBindingStorageImageUpdateAfterBind = true,
                     *  descriptorBindingStorageTexelBufferUpdateAfterBind = true,
                     *  descriptorBindingUniformBufferUpdateAfterBind = true,
                     *  descriptorBindingUniformTexelBufferUpdateAfterBind = true,
                     *  descriptorBindingUpdateUnusedWhilePending = true,
                     *  descriptorBindingPartiallyBound = true,
                     *  shaderStorageTexelBufferArrayDynamicIndexing = true,
                     *  pNext = storageByte_ptr,
                     * };
                     * var descIndexing_ptr = descIndexing.Pointer();*/

                    //var drawIndirectCount = new VkDrawIndirecCount

                    var devFeats12 = new VkPhysicalDeviceVulkan12Features()
                    {
                        sType = VkStructureType.StructureTypePhysicalDeviceVulkan12Features,
                        separateDepthStencilLayouts = true,
                        timelineSemaphore           = true,
                        drawIndirectCount           = true,
                        shaderFloat16 = true,
                        shaderInt8    = true,
                        uniformBufferStandardLayout       = true,
                        storageBuffer8BitAccess           = true,
                        uniformAndStorageBuffer8BitAccess = true,
                        descriptorIndexing = true,
                        descriptorBindingSampledImageUpdateAfterBind       = true,
                        descriptorBindingStorageBufferUpdateAfterBind      = true,
                        descriptorBindingStorageImageUpdateAfterBind       = true,
                        descriptorBindingStorageTexelBufferUpdateAfterBind = true,
                        descriptorBindingUniformBufferUpdateAfterBind      = true,
                        descriptorBindingUniformTexelBufferUpdateAfterBind = true,
                        descriptorBindingUpdateUnusedWhilePending          = true,
                        descriptorBindingPartiallyBound = true,
                        shaderStorageTexelBufferArrayDynamicIndexing = true,

                        shaderStorageBufferArrayNonUniformIndexing = true,
                        runtimeDescriptorArray = true,
                        descriptorBindingVariableDescriptorCount = true,

                        pNext = devFeats11_ptr
                    };
                    var devFeats12_ptr = devFeats12.Pointer();

                    devExtns.AddRange(requiredDeviceExtns);
                    for (int i = 0; i < optionalExtn_avail.Length; i++)
                    {
                        if (optionalExtn_avail[i])
                        {
                            devExtns.Add(optionalDeviceExtns[i]);
                        }
                    }
                    var devExtns_ptr = stackalloc IntPtr[devExtns.Count];
                    for (int i = 0; i < devExtns.Count; i++)
                    {
                        devExtns_ptr[i] = Marshal.StringToHGlobalAnsi(devExtns[i]);
                    }

                    var qCreatInfos_ptr = qCreatInfos.Pointer();
                    var devFeats_ptr    = devFeats.Pointer();
                    var devCreatInfo    = new VkDeviceCreateInfo()
                    {
                        sType = VkStructureType.StructureTypeDeviceCreateInfo,
                        queueCreateInfoCount    = (uint)(transferFamily != graphicsFamily ? 3 : 2),
                        enabledExtensionCount   = (uint)devExtns.Count,
                        ppEnabledExtensionNames = devExtns_ptr,
                        enabledLayerCount       = (uint)instLayers.Count,
                        ppEnabledLayerNames     = layers,
                        pEnabledFeatures        = devFeats_ptr,
                        pQueueCreateInfos       = qCreatInfos_ptr,
                        pNext = devFeats12_ptr
                    };
                    var    devCreatInfo_ptr = devCreatInfo.Pointer();
                    IntPtr deviceHndl       = IntPtr.Zero;
                    res = vkCreateDevice(orderedDevices[0], devCreatInfo_ptr, null, &deviceHndl);
                    if (res != VkResult.Success)
                    {
                        throw new Exception("Failed to create logical device.");
                    }
                    DeviceInformation[0].Device = deviceHndl;

                    //Setup memory allocator
                    var allocCreatInfo = new VmaAllocatorCreateInfo()
                    {
                        physicalDevice = DeviceInformation[0].PhysicalDevice,
                        device         = DeviceInformation[0].Device
                    };
                    var allocCreatInfo_ptr = allocCreatInfo.Pointer();

                    fixed(IntPtr *vma_alloc_ptr = &DeviceInformation[0].vmaAllocator)
                    res = vmaCreateAllocator(allocCreatInfo_ptr, vma_alloc_ptr);

                    if (res != VkResult.Success)
                    {
                        throw new Exception("Failed to initialize allocator.");
                    }

                    IntPtr graph_q_hndl = IntPtr.Zero;
                    IntPtr trans_q_hndl = IntPtr.Zero;
                    IntPtr comp_q_hndl  = IntPtr.Zero;
                    vkGetDeviceQueue(DeviceInformation[0].Device, graphicsFamily, 0, &graph_q_hndl);
                    vkGetDeviceQueue(DeviceInformation[0].Device, computeFamily, 0, &comp_q_hndl);
                    if (transferFamily != graphicsFamily)
                    {
                        vkGetDeviceQueue(DeviceInformation[0].Device, transferFamily, 0, &trans_q_hndl);
                    }
                    else
                    {
                        vkGetDeviceQueue(DeviceInformation[0].Device, graphicsFamily, 1, &trans_q_hndl);
                    }

                    DeviceInformation[0].GraphicsQueue = new GpuQueue(CommandQueueKind.Graphics, graph_q_hndl, graphicsFamily, 0);
                    DeviceInformation[0].TransferQueue = new GpuQueue(CommandQueueKind.Transfer, trans_q_hndl, transferFamily, 0);
                    DeviceInformation[0].ComputeQueue  = new GpuQueue(CommandQueueKind.Compute, comp_q_hndl, computeFamily, 0);

                    var queue_indices = new List <uint>();
                    if (!queue_indices.Contains(DeviceInformation[0].GraphicsFamily))
                    {
                        queue_indices.Add(DeviceInformation[0].GraphicsFamily);
                    }
                    if (!queue_indices.Contains(DeviceInformation[0].ComputeFamily))
                    {
                        queue_indices.Add(DeviceInformation[0].ComputeFamily);
                    }
                    if (!queue_indices.Contains(DeviceInformation[0].PresentFamily))
                    {
                        queue_indices.Add(DeviceInformation[0].PresentFamily);
                    }
                    if (!queue_indices.Contains(DeviceInformation[0].TransferFamily))
                    {
                        queue_indices.Add(DeviceInformation[0].TransferFamily);
                    }
                    DeviceInformation[0].QueueFamilyIndices = queue_indices.ToArray();

                    var physDeviceProps = new ManagedPtr <VkPhysicalDeviceProperties>();
                    vkGetPhysicalDeviceProperties(DeviceInformation[0].PhysicalDevice, physDeviceProps);
                    DeviceInformation[0].Properties = physDeviceProps.Value;

                    var caps_ptr = new ManagedPtr <VkSurfaceCapabilitiesKHR>();
                    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(DeviceInformation[0].PhysicalDevice, surfaceHndl, caps_ptr);
                    var caps = caps_ptr.Value;

                    VkExtent2D cur_extent = new VkExtent2D();
                    if (caps.currentExtent.width != uint.MaxValue)
                    {
                        cur_extent = caps.currentExtent;
                    }
                    else
                    {
                        cur_extent.width  = System.Math.Clamp((uint)Window.Width, caps.minImageExtent.width, caps.maxImageExtent.width);
                        cur_extent.height = System.Math.Clamp((uint)Window.Height, caps.minImageExtent.height, caps.maxImageExtent.height);
                    }

                    uint img_cnt = caps.minImageCount + 1;

                    VkSwapchainCreateInfoKHR swapCreatInfo = new VkSwapchainCreateInfoKHR()
                    {
                        sType                 = VkStructureType.StructureTypeSwapchainCreateInfoKhr,
                        surface               = surfaceHndl,
                        minImageCount         = img_cnt,
                        imageFormat           = surface_fmt.format,
                        imageColorSpace       = surface_fmt.colorSpace,
                        imageExtent           = cur_extent,
                        imageArrayLayers      = 1,
                        imageUsage            = VkImageUsageFlags.ImageUsageColorAttachmentBit | VkImageUsageFlags.ImageUsageTransferDstBit | VkImageUsageFlags.ImageUsageTransferSrcBit,
                        imageSharingMode      = VkSharingMode.SharingModeExclusive,
                        queueFamilyIndexCount = 0,
                        pQueueFamilyIndices   = null,
                        preTransform          = caps.currentTransform,
                        compositeAlpha        = VkCompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr,
                        presentMode           = present_mode,
                        clipped               = true,
                        oldSwapchain          = IntPtr.Zero
                    };
                    var swapCreatInfo_ptr = swapCreatInfo.Pointer();

                    fixed(IntPtr *swapchain_ptr = &swapChainHndl)
                    res = vkCreateSwapchainKHR(DeviceInformation[0].Device, swapCreatInfo_ptr, null, swapchain_ptr);

                    if (res != VkResult.Success)
                        throw new Exception("Failed to create swapchain.");

                    fixed(uint *swapchain_img_cnt_ptr = &swapchain_img_cnt)
                    {
                        vkGetSwapchainImagesKHR(DeviceInformation[0].Device, swapChainHndl, swapchain_img_cnt_ptr, null);
                        var swapchainImages_l = new IntPtr[swapchain_img_cnt];

                        fixed(IntPtr *swapchain_imgs = swapchainImages_l)
                        vkGetSwapchainImagesKHR(DeviceInformation[0].Device, swapChainHndl, swapchain_img_cnt_ptr, swapchain_imgs);

                        MaxFramesInFlight = swapchain_img_cnt;
                        MaxFrameCount     = swapchain_img_cnt;
                        swapchainImages   = new Image[swapchain_img_cnt];
                        for (int i = 0; i < swapchainImages.Length; i++)
                        {
                            swapchainImages[i] = new Image($"Swapchain_{i}")
                            {
                                Dimensions    = 2,
                                Width         = cur_extent.width,
                                Height        = cur_extent.height,
                                Depth         = 1,
                                Format        = (ImageFormat)surface_fmt.format,
                                Layers        = 1,
                                Levels        = 1,
                                MemoryUsage   = MemoryUsage.GpuOnly,
                                Usage         = ImageUsage.Sampled,
                                InitialLayout = ImageLayout.Undefined,
                                Cubemappable  = false,
                            };
                            swapchainImages[i].Build(0, swapchainImages_l[i]);
                        }


                        surface_extent     = cur_extent;
                        swapchainViews     = new ImageView[swapchain_img_cnt];
                        DefaultFramebuffer = new Framebuffer[swapchain_img_cnt];
                        for (int i = 0; i < swapchainImages.Length; i++)
                        {
                            swapchainViews[i] = new ImageView($"Swapchain_{i}")
                            {
                                BaseLayer  = 0,
                                BaseLevel  = 0,
                                Format     = (ImageFormat)surface_fmt.format,
                                LayerCount = 1,
                                LevelCount = 1,
                                ViewType   = ImageViewType.View2D,
                            };
                            swapchainViews[i].Build(swapchainImages[i]);

                            DefaultFramebuffer[i]                  = new Framebuffer();
                            DefaultFramebuffer[i].Width            = surface_extent.width;
                            DefaultFramebuffer[i].Height           = surface_extent.height;
                            DefaultFramebuffer[i].Name             = $"Swapchain_{i}";
                            DefaultFramebuffer[i].ColorAttachments = new ImageView[] { swapchainViews[i] };
                        }
                    }

                    for (int i = 0; i < instLayers.Count; i++)
                    {
                        Marshal.FreeHGlobal(layers[i]);
                    }
                    for (int i = 0; i < instExtns.Count; i++)
                    {
                        Marshal.FreeHGlobal(extns[i]);
                    }
                    for (int i = 0; i < devExtns.Count; i++)
                    {
                        Marshal.FreeHGlobal(devExtns_ptr[i]);
                    }

                    //TODO allocate compute and trasnfer queues for all secondary devices
                }

                for (int i = 0; i < 1 /*DeviceInformation.Length*/; i++)
                {
                    var    devInfo    = DeviceInformation[i];
                    IntPtr rrCtxtHndl = IntPtr.Zero;

                    if (rrCreateContextVk(RrApiVersion, devInfo.Device, devInfo.PhysicalDevice, devInfo.ComputeQueue.Handle, devInfo.ComputeFamily, &rrCtxtHndl) != RRError.RrSuccess)
                    {
                        Console.WriteLine($"Failed to initialize RadeonRays for device #{i}.");
                    }
                    DeviceInformation[i].RaysContext = rrCtxtHndl;
                }

                FrameFinishedSemaphore  = new GpuSemaphore[MaxFramesInFlight];
                ImageAvailableSemaphore = new GpuSemaphore[MaxFramesInFlight];
                InflightFences          = new Fence[MaxFramesInFlight];
                for (int i = 0; i < MaxFramesInFlight; i++)
                {
                    FrameFinishedSemaphore[i] = new GpuSemaphore();
                    FrameFinishedSemaphore[i].Build(0, false, 0);

                    ImageAvailableSemaphore[i] = new GpuSemaphore();
                    ImageAvailableSemaphore[i].Build(0, false, 0);

                    InflightFences[i] = new Fence
                    {
                        CreateSignaled = true
                    };
                    InflightFences[i].Build(0);
                }

                Width  = (uint)Window.Width;
                Height = (uint)Window.Height;
            }
        }