Пример #1
0
 private void PopulateDebugMessengerCreateInfo(out VkDebugUtilsMessengerCreateInfoEXT createInfo)
 {
     createInfo                 = default;
     createInfo.sType           = VkStructureType.VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
     createInfo.messageSeverity = VkDebugUtilsMessageSeverityFlagsEXT.VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VkDebugUtilsMessageSeverityFlagsEXT.VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VkDebugUtilsMessageSeverityFlagsEXT.VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
     createInfo.messageType     = VkDebugUtilsMessageTypeFlagsEXT.VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VkDebugUtilsMessageTypeFlagsEXT.VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VkDebugUtilsMessageTypeFlagsEXT.VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
     createInfo.pfnUserCallback = Marshal.GetFunctionPointerForDelegate(CallbackDelegate);
     createInfo.pUserData       = null;
 }
Пример #2
0
        /// <summary>
        /// Create a new debug utils messenger providing a PFN_vkDebugUtilsMessengerCallbackEXT delegate.
        /// </summary>
        /// <param name="instance">Vulkan Instance.</param>
        /// <param name="onMessageDelegate">Message callback.</param>
        /// <param name="typeMask">Type mask.</param>
        /// <param name="severityMask">Severity mask.</param>
        public Messenger(Instance instance, PFN_vkDebugUtilsMessengerCallbackEXT onMessageDelegate,
                         VkDebugUtilsMessageTypeFlagsEXT typeMask =
                         VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT,
                         VkDebugUtilsMessageSeverityFlagsEXT severityMask =
                         VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT |
                         VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT)
        {
            inst = instance;
            VkDebugUtilsMessengerCreateInfoEXT info = VkDebugUtilsMessengerCreateInfoEXT.New();

            info.messageType     = typeMask;
            info.messageSeverity = severityMask;
            info.pfnUserCallback = Marshal.GetFunctionPointerForDelegate(onMessageDelegate);
            info.pUserData       = IntPtr.Zero;

            Utils.CheckResult(vkCreateDebugUtilsMessengerEXT(inst.VkInstance, ref info, IntPtr.Zero, out handle));
        }
Пример #3
0
        private VkDebugUtilsMessengerEXT CreateDebugMessenger(PFN_vkDebugUtilsMessengerCallbackEXT callback)
        {
            var createInfo = new VkDebugUtilsMessengerCreateInfoEXT
            {
                sType           = VkStructureType.VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
                messageSeverity = VkDebugUtilsMessageSeverityFlagsEXT.Verbose | VkDebugUtilsMessageSeverityFlagsEXT.Warning | VkDebugUtilsMessageSeverityFlagsEXT.Error,
                messageType     = VkDebugUtilsMessageTypeFlagsEXT.General | VkDebugUtilsMessageTypeFlagsEXT.Validation | VkDebugUtilsMessageTypeFlagsEXT.Performance,
                pfnUserCallback = Marshal.GetFunctionPointerForDelegate(callback),
                pUserData       = null
            };

            trackedDelegates.Add(callback);

            var result = VK.CreateDebugUtilsMessengerEXT(Instance, &createInfo, null, out var messenger);

            if (result != VkResult.Success)
            {
                throw new Exception(result.ToString());
            }

            return(messenger);
        }
Пример #4
0
        public unsafe GraphicsAdapterFactoryInstance(bool enableValidation)
        {
            var applicationInfo = new VkApplicationInfo
            {
                sType       = VkStructureType.ApplicationInfo,
                apiVersion  = new VkVersion(1, 0, 0),
                pEngineName = (byte *)Marshal.StringToHGlobalAnsi("Stride"),
                //engineVersion = new VkVersion()
            };

            var validationLayerNames = new[]
            {
                "VK_LAYER_KHRONOS_validation",
            };

            IntPtr[] enabledLayerNames = new IntPtr[0];

            if (enableValidation)
            {
                var layers = vkEnumerateInstanceLayerProperties();
                var availableLayerNames = new HashSet <string>();

                for (int index = 0; index < layers.Length; index++)
                {
                    var properties  = layers[index];
                    var namePointer = properties.layerName;
                    var name        = Marshal.PtrToStringAnsi((IntPtr)namePointer);

                    availableLayerNames.Add(name);
                }

                enabledLayerNames = validationLayerNames
                                    .Where(x => availableLayerNames.Contains(x))
                                    .Select(Marshal.StringToHGlobalAnsi).ToArray();

                // Check if validation was really available
                enableValidation = enabledLayerNames.Length > 0;
            }

            var extensionProperties     = vkEnumerateInstanceExtensionProperties();
            var availableExtensionNames = new List <string>();
            var desiredExtensionNames   = new List <string>();

            for (int index = 0; index < extensionProperties.Length; index++)
            {
                var extensionProperty = extensionProperties[index];
                var name = Marshal.PtrToStringAnsi((IntPtr)extensionProperty.extensionName);
                availableExtensionNames.Add(name);
            }

            desiredExtensionNames.Add(KHRSurfaceExtensionName);
            if (!availableExtensionNames.Contains(KHRSurfaceExtensionName))
            {
                throw new InvalidOperationException($"Required extension {KHRSurfaceExtensionName} is not available");
            }

            if (Platform.Type == PlatformType.Windows)
            {
                desiredExtensionNames.Add(KHRWin32SurfaceExtensionName);
                if (!availableExtensionNames.Contains(KHRWin32SurfaceExtensionName))
                {
                    throw new InvalidOperationException($"Required extension {KHRWin32SurfaceExtensionName} is not available");
                }
            }
            else if (Platform.Type == PlatformType.Android)
            {
                desiredExtensionNames.Add(KHRAndroidSurfaceExtensionName);
                if (!availableExtensionNames.Contains(KHRAndroidSurfaceExtensionName))
                {
                    throw new InvalidOperationException($"Required extension {KHRAndroidSurfaceExtensionName} is not available");
                }
            }
            else if (Platform.Type == PlatformType.Linux)
            {
                if (availableExtensionNames.Contains("VK_KHR_xlib_surface"))
                {
                    desiredExtensionNames.Add("VK_KHR_xlib_surface");
                    HasXlibSurfaceSupport = true;
                }
                else if (availableExtensionNames.Contains("VK_KHR_xcb_surface"))
                {
                    desiredExtensionNames.Add("VK_KHR_xcb_surface");
                }
                else
                {
                    throw new InvalidOperationException("None of the supported surface extensions VK_KHR_xcb_surface or VK_KHR_xlib_surface is available");
                }
            }

            bool enableDebugReport = enableValidation && availableExtensionNames.Contains(EXTDebugUtilsExtensionName);

            if (enableDebugReport)
            {
                desiredExtensionNames.Add(EXTDebugUtilsExtensionName);
            }

            var enabledExtensionNames = desiredExtensionNames.Select(Marshal.StringToHGlobalAnsi).ToArray();

            try
            {
                fixed(void *enabledExtensionNamesPointer = &enabledExtensionNames[0])
                {
                    var instanceCreateInfo = new VkInstanceCreateInfo
                    {
                        sType                   = VkStructureType.InstanceCreateInfo,
                        pApplicationInfo        = &applicationInfo,
                        enabledLayerCount       = enabledLayerNames != null ? (uint)enabledLayerNames.Length : 0,
                        ppEnabledLayerNames     = enabledLayerNames?.Length > 0 ? (byte **)Core.Interop.Fixed(enabledLayerNames) : null,
                        enabledExtensionCount   = (uint)enabledExtensionNames.Length,
                        ppEnabledExtensionNames = (byte **)enabledExtensionNamesPointer,
                    };

                    vkCreateInstance(&instanceCreateInfo, null, out NativeInstance);
                    vkLoadInstance(NativeInstance);
                }

                // Check if validation layer was available (otherwise detected count is 0)
                if (enableValidation)
                {
                    debugReport = DebugReport;
                    var createInfo = new VkDebugUtilsMessengerCreateInfoEXT
                    {
                        sType           = VkStructureType.DebugUtilsMessengerCreateInfoEXT,
                        messageSeverity = VkDebugUtilsMessageSeverityFlagsEXT.Verbose | VkDebugUtilsMessageSeverityFlagsEXT.Error | VkDebugUtilsMessageSeverityFlagsEXT.Warning,
                        messageType     = VkDebugUtilsMessageTypeFlagsEXT.General | VkDebugUtilsMessageTypeFlagsEXT.Validation | VkDebugUtilsMessageTypeFlagsEXT.Performance,
                        pfnUserCallback = Marshal.GetFunctionPointerForDelegate(debugReport)
                    };

                    vkCreateDebugUtilsMessengerEXT(NativeInstance, &createInfo, null, out debugReportCallback).CheckResult();
                }
            }
            finally
            {
                foreach (var enabledExtensionName in enabledExtensionNames)
                {
                    Marshal.FreeHGlobal(enabledExtensionName);
                }

                foreach (var enabledLayerName in enabledLayerNames)
                {
                    Marshal.FreeHGlobal(enabledLayerName);
                }

                Marshal.FreeHGlobal((IntPtr)applicationInfo.pEngineName);
            }
        }
Пример #5
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];

            var queueFamilies = FindQueueFamilies(PhysicalDevice, _surface);

            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
            };
            var deviceCreateInfo = new VkDeviceCreateInfo
            {
                sType                = VkStructureType.DeviceCreateInfo,
                pQueueCreateInfos    = &queueCreateInfo,
                queueCreateInfoCount = 1,
                pEnabledFeatures     = null,
            };

            using var deviceExtensionNames           = new VkStringArray(deviceExtensions);
            deviceCreateInfo.enabledExtensionCount   = deviceExtensionNames.Length;
            deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames;

            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();
            }
        }
Пример #6
0
            protected override void Initialize()
            {
                var result = vkInitialize();

                result.CheckResult();

                var version         = vkEnumerateInstanceVersion();
                var queryExtensions = vkEnumerateInstanceExtensionProperties();
                var queryLayers     = vkEnumerateInstanceLayerProperties();

                VkString name    = "01-ClearScreen";
                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         = VkVersion.Version_1_0,
                };

                var instanceExtensions = new List <string>
                {
                    KHRSurfaceExtensionName,
                    KHRWin32SurfaceExtensionName
                };

                var instanceLayers = new List <string>();

                if (EnableValidationLayers)
                {
                    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;
                }

                result = vkCreateInstance(&instanceCreateInfo, null, out instance);
                vkLoadInstance(instance);

                if (instanceLayers.Count > 0)
                {
                    _debugMessengerCallbackFunc = DebugMessengerCallback;
                    var debugCreateInfo = new VkDebugUtilsMessengerCreateInfoEXT
                    {
                        sType           = VkStructureType.DebugUtilsMessengerCreateInfoEXT,
                        messageSeverity = /*VkDebugUtilsMessageSeverityFlagsEXT.VerboseEXT | */ VkDebugUtilsMessageSeverityFlagsEXT.ErrorEXT | VkDebugUtilsMessageSeverityFlagsEXT.WarningEXT,
                        messageType     = VkDebugUtilsMessageTypeFlagsEXT.GeneralEXT | VkDebugUtilsMessageTypeFlagsEXT.ValidationEXT | VkDebugUtilsMessageTypeFlagsEXT.PerformanceEXT,
                        pfnUserCallback = Marshal.GetFunctionPointerForDelegate(_debugMessengerCallbackFunc)
                    };

                    vkCreateDebugUtilsMessengerEXT(instance, &debugCreateInfo, null, out debugMessenger).CheckResult();
                }

                var surfaceCreateInfo = new VkWin32SurfaceCreateInfoKHR
                {
                    sType     = VkStructureType.Win32SurfaceCreateInfoKHR,
                    hinstance = HInstance,
                    hwnd      = MainWindow.Handle
                };

                result = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, null, out surface);

                var physicalDevices = vkEnumeratePhysicalDevices(instance);

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

                physicalDevice = physicalDevices[0];

                var queueFamilies = FindQueueFamilies(physicalDevice, surface);

                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
                };
                var deviceCreateInfo = new VkDeviceCreateInfo
                {
                    sType                = VkStructureType.DeviceCreateInfo,
                    pQueueCreateInfos    = &queueCreateInfo,
                    queueCreateInfoCount = 1,
                    pEnabledFeatures     = null,
                };

                using var deviceExtensionNames           = new VkStringArray(deviceExtensions);
                deviceCreateInfo.enabledExtensionCount   = deviceExtensionNames.Length;
                deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames;

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

                vkGetDeviceQueue(device, queueFamilies.graphicsFamily, 0, out graphicsQueue);
                vkGetDeviceQueue(device, queueFamilies.presentFamily, 0, out presentQueue);

                CreateSwapchain();
                CreateSyncPrimitives();
            }
Пример #7
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;
            }
        }
Пример #8
0
        private VkInstance CreateInstance(bool debug)
        {
            VkInstance instance;

            // Specify standard validation layers.
            string surfaceExtension;

            switch (Host.Platform)
            {
            case Platform.Android:
                surfaceExtension = KHRAndroidSurfaceExtensionName;
                break;

            case Platform.Win32:
                surfaceExtension = KHRWin32SurfaceExtensionName;
                break;

            default:
                throw new NotImplementedException();
            }

            VkString name    = "TODO Application Name";
            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         = VkVersion.Version_1_0,
            };

            var instanceExtensions = new List <string>
            {
                KHRSurfaceExtensionName,
                surfaceExtension
            };

            var instanceLayers = new List <string>();

            if (EnableValidationLayers)
            {
                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;
            }

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

            vkLoadInstance(instance);

            if (instanceLayers.Count > 0)
            {
                _debugMessengerCallbackFunc = DebugMessengerCallback;
                var debugCreateInfo = new VkDebugUtilsMessengerCreateInfoEXT
                {
                    sType           = VkStructureType.DebugUtilsMessengerCreateInfoEXT,
                    messageSeverity = VkDebugUtilsMessageSeverityFlagsEXT.Verbose | VkDebugUtilsMessageSeverityFlagsEXT.Error | VkDebugUtilsMessageSeverityFlagsEXT.Warning,
                    messageType     = VkDebugUtilsMessageTypeFlagsEXT.General | VkDebugUtilsMessageTypeFlagsEXT.Validation | VkDebugUtilsMessageTypeFlagsEXT.Performance,
                    pfnUserCallback = Marshal.GetFunctionPointerForDelegate(_debugMessengerCallbackFunc)
                };

                vkCreateDebugUtilsMessengerEXT(instance, &debugCreateInfo, null, out debugMessenger).CheckResult();
            }

            return(instance);
        }