public static VkDevice Create(Settings settings, VkPhysicalDeviceFeatures enabledFeatures, CStringList enabledExtensions, VkQueueFlags requestedQueueTypes = VkQueueFlags.Graphics | VkQueueFlags.Compute | VkQueueFlags.Transfer) { instanceExtensions.Add(Vulkan.KHRSurfaceExtensionName); instanceExtensions.Add(Vulkan.KHRGetPhysicalDeviceProperties2ExtensionName); enabledExtensions.Add(Vulkan.KHRMaintenance1ExtensionName); enabledExtensions.Add(Vulkan.EXTInlineUniformBlockExtensionName); //enabledExtensions.Add(Strings.VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT); CreateInstance(settings); // Physical Device var physicalDevices = Vulkan.vkEnumeratePhysicalDevices(VkInstance); // TODO: Implement arg parsing, etc. int selectedDevice = 0; PhysicalDevice = physicalDevices[selectedDevice]; Debug.Assert(PhysicalDevice.Handle != IntPtr.Zero); vkGetPhysicalDeviceProperties(PhysicalDevice, out VkPhysicalDeviceProperties properties); Properties = properties; vkGetPhysicalDeviceFeatures(PhysicalDevice, out VkPhysicalDeviceFeatures features); Features = features; if (features.tessellationShader) { enabledFeatures.tessellationShader = true; } if (features.multiDrawIndirect) { enabledFeatures.multiDrawIndirect = true; } // Enable anisotropic filtering if supported if (features.samplerAnisotropy) { enabledFeatures.samplerAnisotropy = true; } // Enable texture compression if (features.textureCompressionBC) { enabledFeatures.textureCompressionBC = true; } else if (features.textureCompressionASTC_LDR) { enabledFeatures.textureCompressionASTC_LDR = true; } else if (features.textureCompressionETC2) { enabledFeatures.textureCompressionETC2 = true; } if (features.sparseBinding && features.sparseResidencyImage2D) { enabledFeatures.shaderResourceResidency = true; enabledFeatures.shaderResourceMinLod = true; enabledFeatures.sparseBinding = true; enabledFeatures.sparseResidencyImage2D = true; } else { Log.Warn("Sparse binding not supported"); } // Memory properties are used regularly for creating all kinds of buffers VkPhysicalDeviceMemoryProperties memoryProperties; vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, out memoryProperties); MemoryProperties = memoryProperties; var qf = Vulkan.vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice); QueueFamilyProperties.Add(qf); var extensions = Vulkan.vkEnumerateDeviceExtensionProperties(PhysicalDevice); foreach (var ext in extensions) { string strExt = UTF8String.FromPointer(ext.extensionName); //enabledExtensions.Add((IntPtr)ext.extensionName); supportedExtensions.Add(strExt); } device = CreateLogicalDevice(Features, enabledExtensions, true, requestedQueueTypes); if (device != VkDevice.Null) { VkPipelineCacheCreateInfo pipelineCacheCreateInfo = new VkPipelineCacheCreateInfo() { sType = VkStructureType.PipelineCacheCreateInfo }; VulkanUtil.CheckResult(vkCreatePipelineCache(device, &pipelineCacheCreateInfo, null, out pipelineCache)); } return(device); }
static VkDevice CreateLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, CStringList enabledExtensions, bool useSwapChain = true, VkQueueFlags requestedQueueTypes = VkQueueFlags.Graphics | VkQueueFlags.Compute | VkQueueFlags.Transfer) { using Vector <VkDeviceQueueCreateInfo> queueCreateInfos = new Vector <VkDeviceQueueCreateInfo>(); float defaultQueuePriority = 0.0f; // Graphics queue if ((requestedQueueTypes & VkQueueFlags.Graphics) != 0) { QFGraphics = GetQueueFamilyIndex(VkQueueFlags.Graphics); var queueInfo = new VkDeviceQueueCreateInfo { sType = VkStructureType.DeviceQueueCreateInfo, queueFamilyIndex = QFGraphics, queueCount = 1, pQueuePriorities = &defaultQueuePriority }; queueCreateInfos.Add(queueInfo); } else { QFGraphics = (uint)IntPtr.Zero; } // Dedicated compute queue if ((requestedQueueTypes & VkQueueFlags.Compute) != 0) { QFCompute = GetQueueFamilyIndex(VkQueueFlags.Compute); if (QFCompute != QFGraphics) { // If compute family index differs, we need an additional queue create info for the compute queue var queueInfo = new VkDeviceQueueCreateInfo { sType = VkStructureType.DeviceQueueCreateInfo, queueFamilyIndex = QFCompute, queueCount = 1, pQueuePriorities = &defaultQueuePriority }; queueCreateInfos.Add(queueInfo); } } else { // Else we use the same queue QFCompute = QFGraphics; } // Dedicated transfer queue if ((requestedQueueTypes & VkQueueFlags.Transfer) != 0) { QFTransfer = GetQueueFamilyIndex(VkQueueFlags.Transfer); if (QFTransfer != QFGraphics && QFTransfer != QFCompute) { // If compute family index differs, we need an additional queue create info for the transfer queue var queueInfo = new VkDeviceQueueCreateInfo { sType = VkStructureType.DeviceQueueCreateInfo, queueFamilyIndex = QFTransfer, queueCount = 1, pQueuePriorities = &defaultQueuePriority }; queueCreateInfos.Add(queueInfo); } } else { // Else we use the same queue QFTransfer = QFGraphics; } // Create the logical device representation using CStringList deviceExtensions = new CStringList(enabledExtensions); if (useSwapChain) { // If the device will be used for presenting to a display via a swapchain we need to request the swapchain extension deviceExtensions.Add(Vulkan.KHRSwapchainExtensionName); } var deviceCreateInfo = new VkDeviceCreateInfo { sType = VkStructureType.DeviceCreateInfo, queueCreateInfoCount = queueCreateInfos.Count, pQueueCreateInfos = queueCreateInfos.DataPtr, pEnabledFeatures = &enabledFeatures }; if (deviceExtensions.Count > 0) { deviceCreateInfo.enabledExtensionCount = deviceExtensions.Count; deviceCreateInfo.ppEnabledExtensionNames = (byte **)deviceExtensions.Data; } return(Vulkan.CreateDevice(PhysicalDevice, &deviceCreateInfo)); }