diff --git a/.clang-format b/.clang-format index 2ef5b38..e38d62b 100644 --- a/.clang-format +++ b/.clang-format @@ -12,7 +12,7 @@ BinPackParameters: false BreakBeforeBinaryOperators: false BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false -ColumnLimit: 100 +ColumnLimit: 120 ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 0 ContinuationIndentWidth: 4 diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index e3cfd3e..62eb3f6 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -31,17 +31,15 @@ #endif #include +#include namespace vkb { namespace detail { -GenericFeaturesPNextNode::GenericFeaturesPNextNode() { - memset(fields, UINT8_MAX, sizeof(VkBool32) * field_capacity); -} +GenericFeaturesPNextNode::GenericFeaturesPNextNode() { memset(fields, UINT8_MAX, sizeof(VkBool32) * field_capacity); } -bool GenericFeaturesPNextNode::match( - GenericFeaturesPNextNode const& requested, GenericFeaturesPNextNode const& supported) noexcept { +bool GenericFeaturesPNextNode::match(GenericFeaturesPNextNode const& requested, GenericFeaturesPNextNode const& supported) noexcept { assert(requested.sType == supported.sType && "Non-matching sTypes in features nodes!"); for (uint32_t i = 0; i < field_capacity; i++) { if (requested.fields[i] && !supported.fields[i]) return false; @@ -115,8 +113,8 @@ class VulkanFunctions { ptr_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties")); fp_vkEnumerateInstanceVersion = reinterpret_cast( ptr_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceVersion")); - fp_vkCreateInstance = reinterpret_cast( - ptr_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance")); + fp_vkCreateInstance = + reinterpret_cast(ptr_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance")); } public: @@ -124,8 +122,7 @@ class VulkanFunctions { out_ptr = reinterpret_cast(ptr_vkGetInstanceProcAddr(instance, func_name)); } - template - void get_device_proc_addr(VkDevice device, T& out_ptr, const char* func_name) { + template void get_device_proc_addr(VkDevice device, T& out_ptr, const char* func_name) { out_ptr = reinterpret_cast(fp_vkGetDeviceProcAddr(device, func_name)); } @@ -204,8 +201,7 @@ VulkanFunctions& vulkan_functions() { } // Helper for robustly executing the two-call pattern -template -auto get_vector(std::vector& out, F&& f, Ts&&... ts) -> VkResult { +template auto get_vector(std::vector& out, F&& f, Ts&&... ts) -> VkResult { uint32_t count = 0; VkResult err; do { @@ -220,8 +216,7 @@ auto get_vector(std::vector& out, F&& f, Ts&&... ts) -> VkResult { return err; } -template -auto get_vector_noerror(F&& f, Ts&&... ts) -> std::vector { +template auto get_vector_noerror(F&& f, Ts&&... ts) -> std::vector { uint32_t count = 0; std::vector results; f(ts..., &count, nullptr); @@ -306,8 +301,7 @@ bool check_layer_supported(std::vector const& available_layer return false; } -bool check_layers_supported(std::vector const& available_layers, - std::vector const& layer_names) { +bool check_layers_supported(std::vector const& available_layers, std::vector const& layer_names) { bool all_found = true; for (const auto& layer_name : layer_names) { bool found = check_layer_supported(available_layers, layer_name); @@ -316,8 +310,7 @@ bool check_layers_supported(std::vector const& available_laye return all_found; } -bool check_extension_supported( - std::vector const& available_extensions, const char* extension_name) { +bool check_extension_supported(std::vector const& available_extensions, const char* extension_name) { if (!extension_name) return false; for (const auto& extension_properties : available_extensions) { if (strcmp(extension_name, extension_properties.extensionName) == 0) { @@ -327,8 +320,8 @@ bool check_extension_supported( return false; } -bool check_extensions_supported(std::vector const& available_extensions, - std::vector const& extension_names) { +bool check_extensions_supported( + std::vector const& available_extensions, std::vector const& extension_names) { bool all_found = true; for (const auto& extension_name : extension_names) { bool found = check_extension_supported(available_extensions, extension_name); @@ -337,8 +330,7 @@ bool check_extensions_supported(std::vector const& availa return all_found; } -template -void setup_pNext_chain(T& structure, std::vector const& structs) { +template void setup_pNext_chain(T& structure, std::vector const& structs) { structure.pNext = nullptr; if (structs.size() <= 0) return; for (size_t i = 0; i < structs.size() - 1; i++) { @@ -350,17 +342,13 @@ const char* validation_layer_name = "VK_LAYER_KHRONOS_validation"; struct InstanceErrorCategory : std::error_category { const char* name() const noexcept override { return "vkb_instance"; } - std::string message(int err) const override { - return to_string(static_cast(err)); - } + std::string message(int err) const override { return to_string(static_cast(err)); } }; const InstanceErrorCategory instance_error_category; struct PhysicalDeviceErrorCategory : std::error_category { const char* name() const noexcept override { return "vkb_physical_device"; } - std::string message(int err) const override { - return to_string(static_cast(err)); - } + std::string message(int err) const override { return to_string(static_cast(err)); } }; const PhysicalDeviceErrorCategory physical_device_error_category; @@ -378,9 +366,7 @@ const DeviceErrorCategory device_error_category; struct SwapchainErrorCategory : std::error_category { const char* name() const noexcept override { return "vbk_swapchain"; } - std::string message(int err) const override { - return to_string(static_cast(err)); - } + std::string message(int err) const override { return to_string(static_cast(err)); } }; const SwapchainErrorCategory swapchain_error_category; @@ -506,8 +492,7 @@ SystemInfo::SystemInfo() { } for (auto& layer : this->available_layers) - if (strcmp(layer.layerName, detail::validation_layer_name) == 0) - validation_layers_available = true; + if (strcmp(layer.layerName, detail::validation_layer_name) == 0) validation_layers_available = true; auto available_extensions_ret = detail::get_vector( this->available_extensions, detail::vulkan_functions().fp_vkEnumerateInstanceExtensionProperties, nullptr); @@ -523,9 +508,8 @@ SystemInfo::SystemInfo() { for (auto& layer : this->available_layers) { std::vector layer_extensions; - auto layer_extensions_ret = detail::get_vector(layer_extensions, - detail::vulkan_functions().fp_vkEnumerateInstanceExtensionProperties, - layer.layerName); + auto layer_extensions_ret = detail::get_vector( + layer_extensions, detail::vulkan_functions().fp_vkEnumerateInstanceExtensionProperties, layer.layerName); if (layer_extensions_ret == VK_SUCCESS) { this->available_extensions.insert( this->available_extensions.end(), layer_extensions.begin(), layer_extensions.end()); @@ -580,8 +564,7 @@ detail::Result InstanceBuilder::build() const { if (info.minimum_instance_version > VKB_VK_API_VERSION_1_0 || info.required_api_version > VKB_VK_API_VERSION_1_0 || info.desired_api_version > VKB_VK_API_VERSION_1_0) { - PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion = - detail::vulkan_functions().fp_vkEnumerateInstanceVersion; + PFN_vkEnumerateInstanceVersion pfn_vkEnumerateInstanceVersion = detail::vulkan_functions().fp_vkEnumerateInstanceVersion; if (pfn_vkEnumerateInstanceVersion != nullptr) { VkResult res = pfn_vkEnumerateInstanceVersion(&instance_version); @@ -624,8 +607,8 @@ detail::Result InstanceBuilder::build() const { if (info.debug_callback != nullptr && system.debug_utils_available) { extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } - bool supports_properties2_ext = detail::check_extension_supported( - system.available_extensions, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + bool supports_properties2_ext = + detail::check_extension_supported(system.available_extensions, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); if (supports_properties2_ext) { extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); @@ -688,11 +671,9 @@ detail::Result InstanceBuilder::build() const { if (info.enabled_validation_features.size() != 0 || info.disabled_validation_features.size()) { features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; features.pNext = nullptr; - features.enabledValidationFeatureCount = - static_cast(info.enabled_validation_features.size()); + features.enabledValidationFeatureCount = static_cast(info.enabled_validation_features.size()); features.pEnabledValidationFeatures = info.enabled_validation_features.data(); - features.disabledValidationFeatureCount = - static_cast(info.disabled_validation_features.size()); + features.disabledValidationFeatureCount = static_cast(info.disabled_validation_features.size()); features.pDisabledValidationFeatures = info.disabled_validation_features.data(); pNext_chain.push_back(reinterpret_cast(&features)); } @@ -722,10 +703,9 @@ detail::Result InstanceBuilder::build() const { instance_create_info.ppEnabledLayerNames = layers.data(); Instance instance; - VkResult res = detail::vulkan_functions().fp_vkCreateInstance( - &instance_create_info, info.allocation_callbacks, &instance.instance); - if (res != VK_SUCCESS) - return detail::Result(InstanceError::failed_create_instance, res); + VkResult res = + detail::vulkan_functions().fp_vkCreateInstance(&instance_create_info, info.allocation_callbacks, &instance.instance); + if (res != VK_SUCCESS) return detail::Result(InstanceError::failed_create_instance, res); detail::vulkan_functions().init_instance_funcs(instance.instance); @@ -878,8 +858,7 @@ void destroy_debug_messenger(VkInstance const instance, VkDebugUtilsMessengerEXT namespace detail { -std::vector check_device_extension_support( - VkPhysicalDevice device, std::vector desired_extensions) { +std::vector check_device_extension_support(VkPhysicalDevice device, std::vector desired_extensions) { std::vector available_extensions; auto available_extensions_ret = detail::get_vector( available_extensions, detail::vulkan_functions().fp_vkEnumerateDeviceExtensionProperties, device, nullptr); @@ -899,71 +878,71 @@ std::vector check_device_extension_support( // clang-format off bool supports_features(VkPhysicalDeviceFeatures supported, - VkPhysicalDeviceFeatures requested, - std::vector const& extension_supported, - std::vector const& extension_requested) { - if (requested.robustBufferAccess && !supported.robustBufferAccess) return false; - if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false; - if (requested.imageCubeArray && !supported.imageCubeArray) return false; - if (requested.independentBlend && !supported.independentBlend) return false; - if (requested.geometryShader && !supported.geometryShader) return false; - if (requested.tessellationShader && !supported.tessellationShader) return false; - if (requested.sampleRateShading && !supported.sampleRateShading) return false; - if (requested.dualSrcBlend && !supported.dualSrcBlend) return false; - if (requested.logicOp && !supported.logicOp) return false; - if (requested.multiDrawIndirect && !supported.multiDrawIndirect) return false; - if (requested.drawIndirectFirstInstance && !supported.drawIndirectFirstInstance) return false; - if (requested.depthClamp && !supported.depthClamp) return false; - if (requested.depthBiasClamp && !supported.depthBiasClamp) return false; - if (requested.fillModeNonSolid && !supported.fillModeNonSolid) return false; - if (requested.depthBounds && !supported.depthBounds) return false; - if (requested.wideLines && !supported.wideLines) return false; - if (requested.largePoints && !supported.largePoints) return false; - if (requested.alphaToOne && !supported.alphaToOne) return false; - if (requested.multiViewport && !supported.multiViewport) return false; - if (requested.samplerAnisotropy && !supported.samplerAnisotropy) return false; - if (requested.textureCompressionETC2 && !supported.textureCompressionETC2) return false; - if (requested.textureCompressionASTC_LDR && !supported.textureCompressionASTC_LDR) return false; - if (requested.textureCompressionBC && !supported.textureCompressionBC) return false; - if (requested.occlusionQueryPrecise && !supported.occlusionQueryPrecise) return false; - if (requested.pipelineStatisticsQuery && !supported.pipelineStatisticsQuery) return false; - if (requested.vertexPipelineStoresAndAtomics && !supported.vertexPipelineStoresAndAtomics) return false; - if (requested.fragmentStoresAndAtomics && !supported.fragmentStoresAndAtomics) return false; - if (requested.shaderTessellationAndGeometryPointSize && !supported.shaderTessellationAndGeometryPointSize) return false; - if (requested.shaderImageGatherExtended && !supported.shaderImageGatherExtended) return false; - if (requested.shaderStorageImageExtendedFormats && !supported.shaderStorageImageExtendedFormats) return false; - if (requested.shaderStorageImageMultisample && !supported.shaderStorageImageMultisample) return false; - if (requested.shaderStorageImageReadWithoutFormat && !supported.shaderStorageImageReadWithoutFormat) return false; - if (requested.shaderStorageImageWriteWithoutFormat && !supported.shaderStorageImageWriteWithoutFormat) return false; - if (requested.shaderUniformBufferArrayDynamicIndexing && !supported.shaderUniformBufferArrayDynamicIndexing) return false; - if (requested.shaderSampledImageArrayDynamicIndexing && !supported.shaderSampledImageArrayDynamicIndexing) return false; - if (requested.shaderStorageBufferArrayDynamicIndexing && !supported.shaderStorageBufferArrayDynamicIndexing) return false; - if (requested.shaderStorageImageArrayDynamicIndexing && !supported.shaderStorageImageArrayDynamicIndexing) return false; - if (requested.shaderClipDistance && !supported.shaderClipDistance) return false; - if (requested.shaderCullDistance && !supported.shaderCullDistance) return false; - if (requested.shaderFloat64 && !supported.shaderFloat64) return false; - if (requested.shaderInt64 && !supported.shaderInt64) return false; - if (requested.shaderInt16 && !supported.shaderInt16) return false; - if (requested.shaderResourceResidency && !supported.shaderResourceResidency) return false; - if (requested.shaderResourceMinLod && !supported.shaderResourceMinLod) return false; - if (requested.sparseBinding && !supported.sparseBinding) return false; - if (requested.sparseResidencyBuffer && !supported.sparseResidencyBuffer) return false; - if (requested.sparseResidencyImage2D && !supported.sparseResidencyImage2D) return false; - if (requested.sparseResidencyImage3D && !supported.sparseResidencyImage3D) return false; - if (requested.sparseResidency2Samples && !supported.sparseResidency2Samples) return false; - if (requested.sparseResidency4Samples && !supported.sparseResidency4Samples) return false; - if (requested.sparseResidency8Samples && !supported.sparseResidency8Samples) return false; - if (requested.sparseResidency16Samples && !supported.sparseResidency16Samples) return false; - if (requested.sparseResidencyAliased && !supported.sparseResidencyAliased) return false; - if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false; - if (requested.inheritedQueries && !supported.inheritedQueries) return false; + VkPhysicalDeviceFeatures requested, + std::vector const& extension_supported, + std::vector const& extension_requested) { + if (requested.robustBufferAccess && !supported.robustBufferAccess) return false; + if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false; + if (requested.imageCubeArray && !supported.imageCubeArray) return false; + if (requested.independentBlend && !supported.independentBlend) return false; + if (requested.geometryShader && !supported.geometryShader) return false; + if (requested.tessellationShader && !supported.tessellationShader) return false; + if (requested.sampleRateShading && !supported.sampleRateShading) return false; + if (requested.dualSrcBlend && !supported.dualSrcBlend) return false; + if (requested.logicOp && !supported.logicOp) return false; + if (requested.multiDrawIndirect && !supported.multiDrawIndirect) return false; + if (requested.drawIndirectFirstInstance && !supported.drawIndirectFirstInstance) return false; + if (requested.depthClamp && !supported.depthClamp) return false; + if (requested.depthBiasClamp && !supported.depthBiasClamp) return false; + if (requested.fillModeNonSolid && !supported.fillModeNonSolid) return false; + if (requested.depthBounds && !supported.depthBounds) return false; + if (requested.wideLines && !supported.wideLines) return false; + if (requested.largePoints && !supported.largePoints) return false; + if (requested.alphaToOne && !supported.alphaToOne) return false; + if (requested.multiViewport && !supported.multiViewport) return false; + if (requested.samplerAnisotropy && !supported.samplerAnisotropy) return false; + if (requested.textureCompressionETC2 && !supported.textureCompressionETC2) return false; + if (requested.textureCompressionASTC_LDR && !supported.textureCompressionASTC_LDR) return false; + if (requested.textureCompressionBC && !supported.textureCompressionBC) return false; + if (requested.occlusionQueryPrecise && !supported.occlusionQueryPrecise) return false; + if (requested.pipelineStatisticsQuery && !supported.pipelineStatisticsQuery) return false; + if (requested.vertexPipelineStoresAndAtomics && !supported.vertexPipelineStoresAndAtomics) return false; + if (requested.fragmentStoresAndAtomics && !supported.fragmentStoresAndAtomics) return false; + if (requested.shaderTessellationAndGeometryPointSize && !supported.shaderTessellationAndGeometryPointSize) return false; + if (requested.shaderImageGatherExtended && !supported.shaderImageGatherExtended) return false; + if (requested.shaderStorageImageExtendedFormats && !supported.shaderStorageImageExtendedFormats) return false; + if (requested.shaderStorageImageMultisample && !supported.shaderStorageImageMultisample) return false; + if (requested.shaderStorageImageReadWithoutFormat && !supported.shaderStorageImageReadWithoutFormat) return false; + if (requested.shaderStorageImageWriteWithoutFormat && !supported.shaderStorageImageWriteWithoutFormat) return false; + if (requested.shaderUniformBufferArrayDynamicIndexing && !supported.shaderUniformBufferArrayDynamicIndexing) return false; + if (requested.shaderSampledImageArrayDynamicIndexing && !supported.shaderSampledImageArrayDynamicIndexing) return false; + if (requested.shaderStorageBufferArrayDynamicIndexing && !supported.shaderStorageBufferArrayDynamicIndexing) return false; + if (requested.shaderStorageImageArrayDynamicIndexing && !supported.shaderStorageImageArrayDynamicIndexing) return false; + if (requested.shaderClipDistance && !supported.shaderClipDistance) return false; + if (requested.shaderCullDistance && !supported.shaderCullDistance) return false; + if (requested.shaderFloat64 && !supported.shaderFloat64) return false; + if (requested.shaderInt64 && !supported.shaderInt64) return false; + if (requested.shaderInt16 && !supported.shaderInt16) return false; + if (requested.shaderResourceResidency && !supported.shaderResourceResidency) return false; + if (requested.shaderResourceMinLod && !supported.shaderResourceMinLod) return false; + if (requested.sparseBinding && !supported.sparseBinding) return false; + if (requested.sparseResidencyBuffer && !supported.sparseResidencyBuffer) return false; + if (requested.sparseResidencyImage2D && !supported.sparseResidencyImage2D) return false; + if (requested.sparseResidencyImage3D && !supported.sparseResidencyImage3D) return false; + if (requested.sparseResidency2Samples && !supported.sparseResidency2Samples) return false; + if (requested.sparseResidency4Samples && !supported.sparseResidency4Samples) return false; + if (requested.sparseResidency8Samples && !supported.sparseResidency8Samples) return false; + if (requested.sparseResidency16Samples && !supported.sparseResidency16Samples) return false; + if (requested.sparseResidencyAliased && !supported.sparseResidencyAliased) return false; + if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false; + if (requested.inheritedQueries && !supported.inheritedQueries) return false; - for(size_t i = 0; i < extension_requested.size(); ++i) { - auto res = GenericFeaturesPNextNode::match(extension_requested[i], extension_supported[i]); - if(!res) return false; - } + for(size_t i = 0; i < extension_requested.size(); ++i) { + auto res = GenericFeaturesPNextNode::match(extension_requested[i], extension_supported[i]); + if(!res) return false; + } - return true; + return true; } // clang-format on // Finds the first queue which supports the desired operations. Returns QUEUE_INDEX_MAX_VALUE if none is found @@ -976,13 +955,11 @@ uint32_t get_first_queue_index(std::vector const& famil // Finds the queue which is separate from the graphics queue and has the desired flag and not the // undesired flag, but will select it if no better options are available compute support. Returns // QUEUE_INDEX_MAX_VALUE if none is found. -uint32_t get_separate_queue_index(std::vector const& families, - VkQueueFlags desired_flags, - VkQueueFlags undesired_flags) { +uint32_t get_separate_queue_index( + std::vector const& families, VkQueueFlags desired_flags, VkQueueFlags undesired_flags) { uint32_t index = QUEUE_INDEX_MAX_VALUE; for (uint32_t i = 0; i < static_cast(families.size()); i++) { - if ((families[i].queueFlags & desired_flags) && - ((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) { + if ((families[i].queueFlags & desired_flags) && ((families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) { if ((families[i].queueFlags & undesired_flags) == 0) { return i; } else { @@ -994,9 +971,8 @@ uint32_t get_separate_queue_index(std::vector const& fa } // finds the first queue which supports only the desired flag (not graphics or transfer). Returns QUEUE_INDEX_MAX_VALUE if none is found. -uint32_t get_dedicated_queue_index(std::vector const& families, - VkQueueFlags desired_flags, - VkQueueFlags undesired_flags) { +uint32_t get_dedicated_queue_index( + std::vector const& families, VkQueueFlags desired_flags, VkQueueFlags undesired_flags) { for (uint32_t i = 0; i < static_cast(families.size()); i++) { if ((families[i].queueFlags & desired_flags) && (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && (families[i].queueFlags & undesired_flags) == 0) @@ -1006,16 +982,13 @@ uint32_t get_dedicated_queue_index(std::vector const& f } // finds the first queue which supports presenting. returns QUEUE_INDEX_MAX_VALUE if none is found -uint32_t get_present_queue_index(VkPhysicalDevice const phys_device, - VkSurfaceKHR const surface, - std::vector const& families) { +uint32_t get_present_queue_index( + VkPhysicalDevice const phys_device, VkSurfaceKHR const surface, std::vector const& families) { for (uint32_t i = 0; i < static_cast(families.size()); i++) { VkBool32 presentSupport = false; if (surface != VK_NULL_HANDLE) { - VkResult res = detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceSupportKHR( - phys_device, i, surface, &presentSupport); - if (res != VK_SUCCESS) - return QUEUE_INDEX_MAX_VALUE; // TODO: determine if this should fail another way + VkResult res = detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceSupportKHR(phys_device, i, surface, &presentSupport); + if (res != VK_SUCCESS) return QUEUE_INDEX_MAX_VALUE; // TODO: determine if this should fail another way } if (presentSupport == VK_TRUE) return i; } @@ -1023,29 +996,32 @@ uint32_t get_present_queue_index(VkPhysicalDevice const phys_device, } } // namespace detail - -PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details(VkPhysicalDevice phys_device, +PhysicalDevice PhysicalDeviceSelector::populate_device_details(VkPhysicalDevice vk_phys_device, std::vector const& src_extended_features_chain) const { - PhysicalDeviceSelector::PhysicalDeviceDesc desc{}; - desc.phys_device = phys_device; + PhysicalDevice physical_device{}; + physical_device.physical_device = vk_phys_device; + physical_device.surface = instance_info.surface; + physical_device.defer_surface_initialization = criteria.defer_surface_initialization; + physical_device.instance_version = instance_info.version; auto queue_families = detail::get_vector_noerror( - detail::vulkan_functions().fp_vkGetPhysicalDeviceQueueFamilyProperties, phys_device); - desc.queue_families = queue_families; + detail::vulkan_functions().fp_vkGetPhysicalDeviceQueueFamilyProperties, vk_phys_device); + physical_device.queue_families = queue_families; - detail::vulkan_functions().fp_vkGetPhysicalDeviceProperties(phys_device, &desc.device_properties); - detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures(phys_device, &desc.device_features); - detail::vulkan_functions().fp_vkGetPhysicalDeviceMemoryProperties(phys_device, &desc.mem_properties); + detail::vulkan_functions().fp_vkGetPhysicalDeviceProperties(vk_phys_device, &physical_device.properties); + detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures(vk_phys_device, &physical_device.features); + detail::vulkan_functions().fp_vkGetPhysicalDeviceMemoryProperties(vk_phys_device, &physical_device.memory_properties); + + physical_device.name = physical_device.properties.deviceName; #if defined(VKB_VK_API_VERSION_1_1) - desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + physical_device.features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; #else - desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; + physical_device.features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; #endif auto fill_chain = src_extended_features_chain; - if (!fill_chain.empty() && - (instance_info.version >= VKB_VK_API_VERSION_1_1 || instance_info.supports_properties2_ext)) { + if (!fill_chain.empty() && (instance_info.version >= VKB_VK_API_VERSION_1_1 || instance_info.supports_properties2_ext)) { detail::GenericFeaturesPNextNode* prev = nullptr; for (auto& extension : fill_chain) { @@ -1056,213 +1032,229 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi } #if defined(VKB_VK_API_VERSION_1_1) - if (instance_info.version >= VKB_VK_API_VERSION_1_1 && desc.device_properties.apiVersion >= VKB_VK_API_VERSION_1_1) { + if (instance_info.version >= VKB_VK_API_VERSION_1_1 && physical_device.properties.apiVersion >= VKB_VK_API_VERSION_1_1) { VkPhysicalDeviceFeatures2 local_features{}; local_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; local_features.pNext = &fill_chain.front(); - detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(phys_device, &local_features); + detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(vk_phys_device, &local_features); } else if (instance_info.supports_properties2_ext) { VkPhysicalDeviceFeatures2KHR local_features_khr{}; local_features_khr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; local_features_khr.pNext = &fill_chain.front(); - detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2KHR(phys_device, &local_features_khr); + detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2KHR(vk_phys_device, &local_features_khr); } #else VkPhysicalDeviceFeatures2KHR local_features_khr{}; local_features_khr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; local_features_khr.pNext = &fill_chain.front(); if (instance_info.supports_properties2_ext) { - detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2KHR(phys_device, &local_features_khr); + detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2KHR(vk_phys_device, &local_features_khr); } #endif - desc.extended_features_chain = fill_chain; + physical_device.extended_features_chain = fill_chain; } - return desc; + return physical_device; } -PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(PhysicalDeviceDesc pd) const { - Suitable suitable = Suitable::yes; +PhysicalDevice::Suitable PhysicalDeviceSelector::is_device_suitable(PhysicalDevice const& pd) const { + PhysicalDevice::Suitable suitable = PhysicalDevice::Suitable::yes; - if (criteria.required_version > pd.device_properties.apiVersion) return Suitable::no; - if (criteria.desired_version > pd.device_properties.apiVersion) suitable = Suitable::partial; + if (criteria.name.size() > 0 && criteria.name != pd.properties.deviceName) return PhysicalDevice::Suitable::no; - bool dedicated_compute = detail::get_dedicated_queue_index(pd.queue_families, - VK_QUEUE_COMPUTE_BIT, - VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE; - bool dedicated_transfer = detail::get_dedicated_queue_index(pd.queue_families, - VK_QUEUE_TRANSFER_BIT, - VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE; - bool separate_compute = - detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != - detail::QUEUE_INDEX_MAX_VALUE; - bool separate_transfer = - detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != - detail::QUEUE_INDEX_MAX_VALUE; + if (criteria.required_version > pd.properties.apiVersion) return PhysicalDevice::Suitable::no; + if (criteria.desired_version > pd.properties.apiVersion) suitable = PhysicalDevice::Suitable::partial; - bool present_queue = - detail::get_present_queue_index(pd.phys_device, instance_info.surface, pd.queue_families) != - detail::QUEUE_INDEX_MAX_VALUE; + bool dedicated_compute = detail::get_dedicated_queue_index(pd.queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != + detail::QUEUE_INDEX_MAX_VALUE; + bool dedicated_transfer = detail::get_dedicated_queue_index(pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != + detail::QUEUE_INDEX_MAX_VALUE; + bool separate_compute = detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != + detail::QUEUE_INDEX_MAX_VALUE; + bool separate_transfer = detail::get_separate_queue_index(pd.queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != + detail::QUEUE_INDEX_MAX_VALUE; - if (criteria.require_dedicated_compute_queue && !dedicated_compute) return Suitable::no; - if (criteria.require_dedicated_transfer_queue && !dedicated_transfer) return Suitable::no; - if (criteria.require_separate_compute_queue && !separate_compute) return Suitable::no; - if (criteria.require_separate_transfer_queue && !separate_transfer) return Suitable::no; + bool present_queue = detail::get_present_queue_index(pd.physical_device, instance_info.surface, pd.queue_families) != + detail::QUEUE_INDEX_MAX_VALUE; + + if (criteria.require_dedicated_compute_queue && !dedicated_compute) return PhysicalDevice::Suitable::no; + if (criteria.require_dedicated_transfer_queue && !dedicated_transfer) return PhysicalDevice::Suitable::no; + if (criteria.require_separate_compute_queue && !separate_compute) return PhysicalDevice::Suitable::no; + if (criteria.require_separate_transfer_queue && !separate_transfer) return PhysicalDevice::Suitable::no; if (criteria.require_present && !present_queue && !criteria.defer_surface_initialization) - return Suitable::no; + return PhysicalDevice::Suitable::no; - auto required_extensions_supported = - detail::check_device_extension_support(pd.phys_device, criteria.required_extensions); + auto required_extensions_supported = detail::check_device_extension_support(pd.physical_device, criteria.required_extensions); if (required_extensions_supported.size() != criteria.required_extensions.size()) - return Suitable::no; + return PhysicalDevice::Suitable::no; - auto desired_extensions_supported = - detail::check_device_extension_support(pd.phys_device, criteria.desired_extensions); + auto desired_extensions_supported = detail::check_device_extension_support(pd.physical_device, criteria.desired_extensions); if (desired_extensions_supported.size() != criteria.desired_extensions.size()) - suitable = Suitable::partial; + suitable = PhysicalDevice::Suitable::partial; - bool swapChainAdequate = false; - if (criteria.defer_surface_initialization) { - swapChainAdequate = true; - } else if (!instance_info.headless) { + if (!criteria.defer_surface_initialization && criteria.require_present) { std::vector formats; std::vector present_modes; auto formats_ret = detail::get_vector(formats, detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceFormatsKHR, - pd.phys_device, + pd.physical_device, instance_info.surface); auto present_modes_ret = detail::get_vector(present_modes, detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfacePresentModesKHR, - pd.phys_device, + pd.physical_device, instance_info.surface); - if (formats_ret == VK_SUCCESS && present_modes_ret == VK_SUCCESS) { - swapChainAdequate = !formats.empty() && !present_modes.empty(); + if (formats_ret != VK_SUCCESS || present_modes_ret != VK_SUCCESS || formats.empty() || present_modes.empty()) { + return PhysicalDevice::Suitable::no; } } - if (criteria.require_present && !swapChainAdequate) return Suitable::no; - if (pd.device_properties.deviceType != static_cast(criteria.preferred_type)) { - if (criteria.allow_any_type) - suitable = Suitable::partial; - else - return Suitable::no; + if (!criteria.allow_any_type && pd.properties.deviceType != static_cast(criteria.preferred_type)) { + suitable = PhysicalDevice::Suitable::partial; } bool required_features_supported = detail::supports_features( - pd.device_features, criteria.required_features, pd.extended_features_chain, criteria.extended_features_chain); - if (!required_features_supported) return Suitable::no; + pd.features, criteria.required_features, pd.extended_features_chain, criteria.extended_features_chain); + if (!required_features_supported) return PhysicalDevice::Suitable::no; - bool has_required_memory = false; - bool has_preferred_memory = false; - for (uint32_t i = 0; i < pd.mem_properties.memoryHeapCount; i++) { - if (pd.mem_properties.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { - if (pd.mem_properties.memoryHeaps[i].size > criteria.required_mem_size) { - has_required_memory = true; - } - if (pd.mem_properties.memoryHeaps[i].size > criteria.desired_mem_size) { - has_preferred_memory = true; + for (uint32_t i = 0; i < pd.memory_properties.memoryHeapCount; i++) { + if (pd.memory_properties.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { + if (pd.memory_properties.memoryHeaps[i].size < criteria.required_mem_size) { + return PhysicalDevice::Suitable::no; + } else if (pd.memory_properties.memoryHeaps[i].size < criteria.desired_mem_size) { + suitable = PhysicalDevice::Suitable::partial; } } } - if (!has_required_memory) return Suitable::no; - if (!has_preferred_memory) suitable = Suitable::partial; return suitable; } +// delegate construction to the one with an explicit surface parameter +PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance) +: PhysicalDeviceSelector(instance, VK_NULL_HANDLE) {} -PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance) { +PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance, VkSurfaceKHR surface) { instance_info.instance = instance.instance; - instance_info.headless = instance.headless; instance_info.version = instance.instance_version; instance_info.supports_properties2_ext = instance.supports_properties2_ext; + instance_info.surface = surface; criteria.require_present = !instance.headless; criteria.required_version = instance.api_version; criteria.desired_version = instance.api_version; } -detail::Result PhysicalDeviceSelector::select() const { - +detail::Result> PhysicalDeviceSelector::select_impl(DeviceSelectionMode selection) const { #if !defined(NDEBUG) // Validation for (const auto& node : criteria.extended_features_chain) { assert(node.sType != static_cast(0) && "Features struct sType must be filled with the struct's " "corresponding VkStructureType enum"); - assert( - node.sType != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 && - "Do not pass VkPhysicalDeviceFeatures2 as a required extension feature structure. An " - "instance of this is managed internally for selection criteria and device creation."); + assert(node.sType != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 && + "Do not pass VkPhysicalDeviceFeatures2 as a required extension feature structure. An " + "instance of this is managed internally for selection criteria and device creation."); } #endif - if (!instance_info.headless && !criteria.defer_surface_initialization) { + if (criteria.require_present && !criteria.defer_surface_initialization) { if (instance_info.surface == VK_NULL_HANDLE) - return detail::Result{ PhysicalDeviceError::no_surface_provided }; + return detail::Result>{ PhysicalDeviceError::no_surface_provided }; } - std::vector physical_devices; + // Get the VkPhysicalDevice handles on the system + std::vector vk_physical_devices; - auto physical_devices_ret = detail::get_vector( - physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, instance_info.instance); - if (physical_devices_ret != VK_SUCCESS) { - return detail::Result{ PhysicalDeviceError::failed_enumerate_physical_devices, - physical_devices_ret }; + auto vk_physical_devices_ret = detail::get_vector( + vk_physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, instance_info.instance); + if (vk_physical_devices_ret != VK_SUCCESS) { + return detail::Result>{ PhysicalDeviceError::failed_enumerate_physical_devices, + vk_physical_devices_ret }; } - if (physical_devices.size() == 0) { - return detail::Result{ PhysicalDeviceError::no_physical_devices_found }; + if (vk_physical_devices.size() == 0) { + return detail::Result>{ PhysicalDeviceError::no_physical_devices_found }; } - std::vector phys_device_descriptions; - for (auto& phys_device : physical_devices) { - phys_device_descriptions.push_back(populate_device_details(phys_device, criteria.extended_features_chain)); + auto fill_out_phys_dev_with_criteria = [&](PhysicalDevice& phys_dev) { + phys_dev.features = criteria.required_features; + phys_dev.extended_features_chain = criteria.extended_features_chain; + phys_dev.extensions_to_enable.insert( + phys_dev.extensions_to_enable.end(), criteria.required_extensions.begin(), criteria.required_extensions.end()); + auto desired_extensions_supported = + detail::check_device_extension_support(phys_dev.physical_device, criteria.desired_extensions); + phys_dev.extensions_to_enable.insert( + phys_dev.extensions_to_enable.end(), desired_extensions_supported.begin(), desired_extensions_supported.end()); + }; + + // if this option is set, always return only the first physical device found + if (criteria.use_first_gpu_unconditionally && vk_physical_devices.size() > 0) { + PhysicalDevice physical_device = populate_device_details(vk_physical_devices[0], criteria.extended_features_chain); + fill_out_phys_dev_with_criteria(physical_device); + return std::vector{ physical_device }; } - PhysicalDeviceDesc selected_device{}; - - if (criteria.use_first_gpu_unconditionally) { - selected_device = phys_device_descriptions.at(0); - } else { - for (const auto& device : phys_device_descriptions) { - auto suitable = is_device_suitable(device); - if (suitable == Suitable::yes) { - selected_device = device; - break; - } else if (suitable == Suitable::partial) { - selected_device = device; - } + // Populate their details and check their suitability + std::vector physical_devices; + for (auto& vk_physical_device : vk_physical_devices) { + PhysicalDevice phys_dev = populate_device_details(vk_physical_device, criteria.extended_features_chain); + phys_dev.suitable = is_device_suitable(phys_dev); + if (phys_dev.suitable != PhysicalDevice::Suitable::no) { + physical_devices.push_back(phys_dev); } } - if (selected_device.phys_device == VK_NULL_HANDLE) { - return detail::Result{ PhysicalDeviceError::no_suitable_device }; - } - PhysicalDevice out_device{}; - out_device.physical_device = selected_device.phys_device; - out_device.surface = instance_info.surface; - out_device.features = criteria.required_features; - out_device.extended_features_chain = criteria.extended_features_chain; - out_device.properties = selected_device.device_properties; - out_device.memory_properties = selected_device.mem_properties; - out_device.queue_families = selected_device.queue_families; - out_device.defer_surface_initialization = criteria.defer_surface_initialization; - out_device.instance_version = instance_info.version; + // sort the list into fully and partially suitable devices. use stable_partition to maintain relative order + const auto partition_index = std::stable_partition(physical_devices.begin(), physical_devices.end(), [](auto const& pd) { + return pd.suitable == PhysicalDevice::Suitable::yes; + }); - out_device.extensions_to_enable.insert(out_device.extensions_to_enable.end(), - criteria.required_extensions.begin(), - criteria.required_extensions.end()); - auto desired_extensions_supported = - detail::check_device_extension_support(out_device.physical_device, criteria.desired_extensions); - out_device.extensions_to_enable.insert(out_device.extensions_to_enable.end(), - desired_extensions_supported.begin(), - desired_extensions_supported.end()); - return out_device; + // Remove the partially suitable elements if they aren't desired + if (selection == DeviceSelectionMode::only_fully_suitable) { + physical_devices.erase(partition_index, physical_devices.end() - 1); + } + + return physical_devices; } +detail::Result PhysicalDeviceSelector::select(DeviceSelectionMode selection) const { + auto const selected_devices = select_impl(selection); + + if (!selected_devices) return detail::Result{ selected_devices.error() }; + if (selected_devices.value().size() == 0) { + return detail::Result{ PhysicalDeviceError::no_suitable_device }; + } + + return selected_devices.value().at(0); +} + +// Return all devices which are considered suitable - intended for applications which want to let the user pick the physical device +detail::Result> PhysicalDeviceSelector::select_devices(DeviceSelectionMode selection) const { + auto const selected_devices = select_impl(selection); + if (!selected_devices) return detail::Result>{ selected_devices.error() }; + if (selected_devices.value().size() == 0) { + return detail::Result>{ PhysicalDeviceError::no_suitable_device }; + } + return selected_devices.value(); +} + +detail::Result> PhysicalDeviceSelector::select_device_names(DeviceSelectionMode selection) const { + auto const selected_devices = select_impl(selection); + if (!selected_devices) return detail::Result>{ selected_devices.error() }; + if (selected_devices.value().size() == 0) { + return detail::Result>{ PhysicalDeviceError::no_suitable_device }; + } + std::vector names; + for (const auto& pd : selected_devices.value()) { + names.push_back(pd.name); + } + return names; +} PhysicalDeviceSelector& PhysicalDeviceSelector::set_surface(VkSurfaceKHR surface) { instance_info.surface = surface; - instance_info.headless = false; + return *this; +} +PhysicalDeviceSelector& PhysicalDeviceSelector::set_name(std::string const& name) { + criteria.name = name; return *this; } PhysicalDeviceSelector& PhysicalDeviceSelector::prefer_gpu_device_type(PreferredDeviceType type) { @@ -1306,8 +1298,7 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::add_required_extension(const cha return *this; } PhysicalDeviceSelector& PhysicalDeviceSelector::add_required_extensions(std::vector extensions) { - criteria.required_extensions.insert( - criteria.required_extensions.end(), extensions.begin(), extensions.end()); + criteria.required_extensions.insert(criteria.required_extensions.end(), extensions.begin(), extensions.end()); return *this; } PhysicalDeviceSelector& PhysicalDeviceSelector::add_desired_extension(const char* extension) { @@ -1315,8 +1306,7 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::add_desired_extension(const char return *this; } PhysicalDeviceSelector& PhysicalDeviceSelector::add_desired_extensions(std::vector extensions) { - criteria.desired_extensions.insert( - criteria.desired_extensions.end(), extensions.begin(), extensions.end()); + criteria.desired_extensions.insert(criteria.desired_extensions.end(), extensions.begin(), extensions.end()); return *this; } PhysicalDeviceSelector& PhysicalDeviceSelector::set_minimum_version(uint32_t major, uint32_t minor) { @@ -1333,22 +1323,19 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features(VkPhysical } #if defined(VKB_VK_API_VERSION_1_2) // Just calls add_required_features -PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11( - VkPhysicalDeviceVulkan11Features features_11) { +PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11(VkPhysicalDeviceVulkan11Features features_11) { features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; add_required_extension_features(features_11); return *this; } -PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12( - VkPhysicalDeviceVulkan12Features features_12) { +PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12(VkPhysicalDeviceVulkan12Features features_12) { features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; add_required_extension_features(features_12); return *this; } #endif #if defined(VKB_VK_API_VERSION_1_3) -PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_13( - VkPhysicalDeviceVulkan13Features features_13) { +PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_13(VkPhysicalDeviceVulkan13Features features_13) { features_13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; add_required_extension_features(features_13); return *this; @@ -1363,25 +1350,20 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::select_first_device_unconditiona return *this; } +// PhysicalDevice bool PhysicalDevice::has_dedicated_compute_queue() const { - return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != - detail::QUEUE_INDEX_MAX_VALUE; + return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } bool PhysicalDevice::has_separate_compute_queue() const { - return detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != - detail::QUEUE_INDEX_MAX_VALUE; + return detail::get_separate_queue_index(queue_families, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_TRANSFER_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } bool PhysicalDevice::has_dedicated_transfer_queue() const { - return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != - detail::QUEUE_INDEX_MAX_VALUE; + return detail::get_dedicated_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } bool PhysicalDevice::has_separate_transfer_queue() const { - return detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != - detail::QUEUE_INDEX_MAX_VALUE; -} -std::vector PhysicalDevice::get_queue_families() const { - return queue_families; + return detail::get_separate_queue_index(queue_families, VK_QUEUE_TRANSFER_BIT, VK_QUEUE_COMPUTE_BIT) != detail::QUEUE_INDEX_MAX_VALUE; } +std::vector PhysicalDevice::get_queue_families() const { return queue_families; } std::vector PhysicalDevice::get_extensions() const { return extensions_to_enable; } PhysicalDevice::operator VkPhysicalDevice() const { return this->physical_device; } @@ -1471,8 +1453,7 @@ DeviceBuilder::DeviceBuilder(PhysicalDevice phys_device) { physical_device = phy detail::Result DeviceBuilder::build() const { std::vector queue_descriptions; - queue_descriptions.insert( - queue_descriptions.end(), info.queue_descriptions.begin(), info.queue_descriptions.end()); + queue_descriptions.insert(queue_descriptions.end(), info.queue_descriptions.begin(), info.queue_descriptions.end()); if (queue_descriptions.size() == 0) { for (uint32_t i = 0; i < physical_device.queue_families.size(); i++) { @@ -1560,10 +1541,8 @@ detail::Result DeviceBuilder::build() const { device.queue_families = physical_device.queue_families; device.allocation_callbacks = info.allocation_callbacks; device.fp_vkGetDeviceProcAddr = detail::vulkan_functions().fp_vkGetDeviceProcAddr; - detail::vulkan_functions().get_device_proc_addr( - device.device, device.internal_table.fp_vkGetDeviceQueue, "vkGetDeviceQueue"); - detail::vulkan_functions().get_device_proc_addr( - device.device, device.internal_table.fp_vkDestroyDevice, "vkDestroyDevice"); + detail::vulkan_functions().get_device_proc_addr(device.device, device.internal_table.fp_vkGetDeviceQueue, "vkGetDeviceQueue"); + detail::vulkan_functions().get_device_proc_addr(device.device, device.internal_table.fp_vkDestroyDevice, "vkDestroyDevice"); return device; } DeviceBuilder& DeviceBuilder::custom_queue_setup(std::vector queue_descriptions) { @@ -1618,8 +1597,7 @@ Result query_surface_support_details(VkPhysicalDevice phy if (surface == VK_NULL_HANDLE) return make_error_code(SurfaceSupportError::surface_handle_null); VkSurfaceCapabilitiesKHR capabilities; - VkResult res = detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - phys_device, surface, &capabilities); + VkResult res = detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_device, surface, &capabilities); if (res != VK_SUCCESS) { return { make_error_code(SurfaceSupportError::failed_get_surface_capabilities), res }; } @@ -1646,13 +1624,10 @@ VkSurfaceFormatKHR find_surface_format(VkPhysicalDevice phys_device, for (auto const& desired_format : desired_formats) { for (auto const& available_format : available_formats) { // finds the first format that is desired and available - if (desired_format.format == available_format.format && - desired_format.colorSpace == available_format.colorSpace) { + if (desired_format.format == available_format.format && desired_format.colorSpace == available_format.colorSpace) { VkFormatProperties properties; - detail::vulkan_functions().fp_vkGetPhysicalDeviceFormatProperties( - phys_device, desired_format.format, &properties); - if ((properties.optimalTilingFeatures & feature_flags) == feature_flags) - return desired_format; + detail::vulkan_functions().fp_vkGetPhysicalDeviceFormatProperties(phys_device, desired_format.format, &properties); + if ((properties.optimalTilingFeatures & feature_flags) == feature_flags) return desired_format; } } } @@ -1682,10 +1657,10 @@ VkExtent2D find_extent(VkSurfaceCapabilitiesKHR const& capabilities, uint32_t de } else { VkExtent2D actualExtent = { desired_width, desired_height }; - actualExtent.width = maximum(capabilities.minImageExtent.width, - minimum(capabilities.maxImageExtent.width, actualExtent.width)); - actualExtent.height = maximum(capabilities.minImageExtent.height, - minimum(capabilities.maxImageExtent.height, actualExtent.height)); + actualExtent.width = + maximum(capabilities.minImageExtent.width, minimum(capabilities.maxImageExtent.width, actualExtent.width)); + actualExtent.height = + maximum(capabilities.minImageExtent.height, minimum(capabilities.maxImageExtent.height, actualExtent.height)); return actualExtent; } @@ -1694,8 +1669,7 @@ VkExtent2D find_extent(VkSurfaceCapabilitiesKHR const& capabilities, uint32_t de void destroy_swapchain(Swapchain const& swapchain) { if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE) { - swapchain.internal_table.fp_vkDestroySwapchainKHR( - swapchain.device, swapchain.swapchain, swapchain.allocation_callbacks); + swapchain.internal_table.fp_vkDestroySwapchainKHR(swapchain.device, swapchain.swapchain, swapchain.allocation_callbacks); } } @@ -1754,19 +1728,17 @@ detail::Result SwapchainBuilder::build() const { auto surface_support_ret = detail::query_surface_support_details(info.physical_device, info.surface); if (!surface_support_ret.has_value()) - return detail::Error{ SwapchainError::failed_query_surface_support_details, - surface_support_ret.vk_result() }; + return detail::Error{ SwapchainError::failed_query_surface_support_details, surface_support_ret.vk_result() }; auto surface_support = surface_support_ret.value(); uint32_t image_count = surface_support.capabilities.minImageCount + 1; if (surface_support.capabilities.maxImageCount > 0 && image_count > surface_support.capabilities.maxImageCount) { image_count = surface_support.capabilities.maxImageCount; } - VkSurfaceFormatKHR surface_format = detail::find_surface_format( - info.physical_device, surface_support.formats, desired_formats, info.format_feature_flags); + VkSurfaceFormatKHR surface_format = + detail::find_surface_format(info.physical_device, surface_support.formats, desired_formats, info.format_feature_flags); - VkExtent2D extent = - detail::find_extent(surface_support.capabilities, info.desired_width, info.desired_height); + VkExtent2D extent = detail::find_extent(surface_support.capabilities, info.desired_width, info.desired_height); uint32_t image_array_layers = info.array_layer_count; if (surface_support.capabilities.maxImageArrayLayers < info.array_layer_count) @@ -1776,8 +1748,7 @@ detail::Result SwapchainBuilder::build() const { uint32_t queue_family_indices[] = { info.graphics_queue_index, info.present_queue_index }; - VkPresentModeKHR present_mode = - detail::find_present_mode(surface_support.present_modes, desired_present_modes); + VkPresentModeKHR present_mode = detail::find_present_mode(surface_support.present_modes, desired_present_modes); VkSurfaceTransformFlagBitsKHR pre_transform = info.pre_transform; if (info.pre_transform == static_cast(0)) @@ -1816,8 +1787,7 @@ detail::Result SwapchainBuilder::build() const { Swapchain swapchain{}; PFN_vkCreateSwapchainKHR swapchain_create_proc; detail::vulkan_functions().get_device_proc_addr(info.device, swapchain_create_proc, "vkCreateSwapchainKHR"); - auto res = swapchain_create_proc( - info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain); + auto res = swapchain_create_proc(info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain); if (res != VK_SUCCESS) { return detail::Error{ SwapchainError::failed_create_swapchain, res }; @@ -1827,10 +1797,8 @@ detail::Result SwapchainBuilder::build() const { swapchain.extent = extent; detail::vulkan_functions().get_device_proc_addr( info.device, swapchain.internal_table.fp_vkGetSwapchainImagesKHR, "vkGetSwapchainImagesKHR"); - detail::vulkan_functions().get_device_proc_addr( - info.device, swapchain.internal_table.fp_vkCreateImageView, "vkCreateImageView"); - detail::vulkan_functions().get_device_proc_addr( - info.device, swapchain.internal_table.fp_vkDestroyImageView, "vkDestroyImageView"); + detail::vulkan_functions().get_device_proc_addr(info.device, swapchain.internal_table.fp_vkCreateImageView, "vkCreateImageView"); + detail::vulkan_functions().get_device_proc_addr(info.device, swapchain.internal_table.fp_vkDestroyImageView, "vkDestroyImageView"); detail::vulkan_functions().get_device_proc_addr( info.device, swapchain.internal_table.fp_vkDestroySwapchainKHR, "vkDestroySwapchainKHR"); auto images = swapchain.get_images(); @@ -1844,8 +1812,8 @@ detail::Result SwapchainBuilder::build() const { detail::Result> Swapchain::get_images() { std::vector swapchain_images; - auto swapchain_images_ret = detail::get_vector( - swapchain_images, internal_table.fp_vkGetSwapchainImagesKHR, device, swapchain); + auto swapchain_images_ret = + detail::get_vector(swapchain_images, internal_table.fp_vkGetSwapchainImagesKHR, device, swapchain); if (swapchain_images_ret != VK_SUCCESS) { return detail::Error{ SwapchainError::failed_get_swapchain_images, swapchain_images_ret }; } @@ -1875,10 +1843,8 @@ detail::Result> Swapchain::get_image_views() { createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; - VkResult res = - internal_table.fp_vkCreateImageView(device, &createInfo, allocation_callbacks, &views[i]); - if (res != VK_SUCCESS) - return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res }; + VkResult res = internal_table.fp_vkCreateImageView(device, &createInfo, allocation_callbacks, &views[i]); + if (res != VK_SUCCESS) return detail::Error{ SwapchainError::failed_create_swapchain_image_views, res }; } return views; } diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 5acc8b5..cd60a93 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -28,25 +29,25 @@ #include "VkBootstrapDispatch.h" #ifdef VK_MAKE_API_VERSION - #define VKB_MAKE_VK_VERSION(variant, major, minor, patch) VK_MAKE_API_VERSION(variant, major, minor, patch) +#define VKB_MAKE_VK_VERSION(variant, major, minor, patch) VK_MAKE_API_VERSION(variant, major, minor, patch) #elif defined(VK_MAKE_VERSION) - #define VKB_MAKE_VK_VERSION(variant, major, minor, patch) VK_MAKE_VERSION(major, minor, patch) +#define VKB_MAKE_VK_VERSION(variant, major, minor, patch) VK_MAKE_VERSION(major, minor, patch) #endif #if defined(VK_API_VERSION_1_3) || defined(VK_VERSION_1_3) - #define VKB_VK_API_VERSION_1_3 VKB_MAKE_VK_VERSION(0, 1, 3, 0) +#define VKB_VK_API_VERSION_1_3 VKB_MAKE_VK_VERSION(0, 1, 3, 0) #endif #if defined(VK_API_VERSION_1_2) || defined(VK_VERSION_1_2) - #define VKB_VK_API_VERSION_1_2 VKB_MAKE_VK_VERSION(0, 1, 2, 0) +#define VKB_VK_API_VERSION_1_2 VKB_MAKE_VK_VERSION(0, 1, 2, 0) #endif #if defined(VK_API_VERSION_1_1) || defined(VK_VERSION_1_1) - #define VKB_VK_API_VERSION_1_1 VKB_MAKE_VK_VERSION(0, 1, 1, 0) +#define VKB_VK_API_VERSION_1_1 VKB_MAKE_VK_VERSION(0, 1, 1, 0) #endif #if defined(VK_API_VERSION_1_0) || defined(VK_VERSION_1_0) - #define VKB_VK_API_VERSION_1_0 VKB_MAKE_VK_VERSION(0, 1, 0, 0) +#define VKB_VK_API_VERSION_1_0 VKB_MAKE_VK_VERSION(0, 1, 0, 0) #endif namespace vkb { @@ -65,8 +66,7 @@ template class Result { Result(Error error) : m_error{ error }, m_init{ false } {} - Result(std::error_code error_code, VkResult result = VK_SUCCESS) - : m_error{ error_code, result }, m_init{ false } {} + Result(std::error_code error_code, VkResult result = VK_SUCCESS) : m_error{ error_code, result }, m_init{ false } {} ~Result() { destroy(); } Result(Result const& expected) : m_init(expected.m_init) { @@ -423,9 +423,9 @@ class InstanceBuilder { PFN_vkDebugUtilsMessengerCallbackEXT debug_callback = default_debug_callback; VkDebugUtilsMessageSeverityFlagsEXT debug_message_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - VkDebugUtilsMessageTypeFlagsEXT debug_message_type = - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + VkDebugUtilsMessageTypeFlagsEXT debug_message_type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; void* debug_user_data_pointer = nullptr; // validation features @@ -450,15 +450,15 @@ VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback(VkDebugUtilsMessageSeverit const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); -void destroy_debug_utils_messenger(VkInstance const instance, - VkDebugUtilsMessengerEXT const messenger, - VkAllocationCallbacks* allocation_callbacks = nullptr); +void destroy_debug_utils_messenger( + VkInstance const instance, VkDebugUtilsMessengerEXT const messenger, VkAllocationCallbacks* allocation_callbacks = nullptr); // ---- Physical Device ---- // class PhysicalDeviceSelector; class DeviceBuilder; struct PhysicalDevice { + std::string name; VkPhysicalDevice physical_device = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; @@ -492,28 +492,55 @@ struct PhysicalDevice { std::vector extensions_to_enable; std::vector queue_families; std::vector extended_features_chain; +#if defined(VKB_VK_API_VERSION_1_1) + VkPhysicalDeviceFeatures2 features2{}; +#else + VkPhysicalDeviceFeatures2KHR features2{}; +#endif bool defer_surface_initialization = false; + enum class Suitable { yes, partial, no }; + Suitable suitable = Suitable::yes; friend class PhysicalDeviceSelector; friend class DeviceBuilder; }; -enum class PreferredDeviceType { - other = 0, - integrated = 1, - discrete = 2, - virtual_gpu = 3, - cpu = 4 +enum class PreferredDeviceType { other = 0, integrated = 1, discrete = 2, virtual_gpu = 3, cpu = 4 }; + +enum class DeviceSelectionMode { + // return all suitable and partially suitable devices + partially_and_fully_suitable, + // return only physical devices which are fully suitable + only_fully_suitable }; +// Enumerates the physical devices on the system, and based on the added criteria, returns a physical device or list of physical devies +// A device is considered suitable if it meets all the 'required' and 'desired' criteria. +// A device is considered partially suitable if it meets only the 'required' criteria. class PhysicalDeviceSelector { public: // Requires a vkb::Instance to construct, needed to pass instance creation info. explicit PhysicalDeviceSelector(Instance const& instance); + // Requires a vkb::Instance to construct, needed to pass instance creation info, optionally specify the surface here + explicit PhysicalDeviceSelector(Instance const& instance, VkSurfaceKHR surface); - detail::Result select() const; + // Return the first device which is suitable + // use the `selection` parameter to configure if partially + detail::Result select(DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const; + + // Return all devices which are considered suitable - intended for applications which want to let the user pick the physical device + detail::Result> select_devices( + DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const; + + // Return the names of all devices which are considered suitable - intended for applications which want to let the user pick the physical device + detail::Result> select_device_names( + DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const; // Set the surface in which the physical device should render to. + // Be sure to set it if swapchain functionality is to be used. PhysicalDeviceSelector& set_surface(VkSurfaceKHR surface); + + // Set the name of the device to select. + PhysicalDeviceSelector& set_name(std::string const& name); // Set the desired physical device type to select. Defaults to PreferredDeviceType::discrete. PhysicalDeviceSelector& prefer_gpu_device_type(PreferredDeviceType type = PreferredDeviceType::discrete); // Allow selection of a gpu device type that isn't the preferred physical device type. Defaults to true. @@ -555,8 +582,7 @@ class PhysicalDeviceSelector { // Require a physical device which supports a specific set of general/extension features. #if defined(VKB_VK_API_VERSION_1_1) - template - PhysicalDeviceSelector& add_required_extension_features(T const& features) { + template PhysicalDeviceSelector& add_required_extension_features(T const& features) { criteria.extended_features_chain.push_back(features); return *this; } @@ -614,10 +640,8 @@ class PhysicalDeviceSelector { // We copy the extension features stored in the selector criteria under the prose of a // "template" to ensure that after fetching everything is compared 1:1 during a match. - PhysicalDeviceDesc populate_device_details(VkPhysicalDevice phys_device, - std::vector const& src_extended_features_chain) const; - struct SelectionCriteria { + std::string name; PreferredDeviceType preferred_type = PreferredDeviceType::discrete; bool allow_any_type = true; bool require_present = true; @@ -643,9 +667,12 @@ class PhysicalDeviceSelector { bool use_first_gpu_unconditionally = false; } criteria; - enum class Suitable { yes, partial, no }; + PhysicalDevice populate_device_details(VkPhysicalDevice phys_device, + std::vector const& src_extended_features_chain) const; - Suitable is_device_suitable(PhysicalDeviceDesc phys_device) const; + PhysicalDevice::Suitable is_device_suitable(PhysicalDevice const& phys_device) const; + + detail::Result> select_impl(DeviceSelectionMode selection) const; }; // ---- Queue ---- // diff --git a/tests/bootstrap_tests.cpp b/tests/bootstrap_tests.cpp index 03a0ba6..b964e61 100644 --- a/tests/bootstrap_tests.cpp +++ b/tests/bootstrap_tests.cpp @@ -204,6 +204,31 @@ TEST_CASE("Device Configuration", "[VkBootstrap.bootstrap]") { vkb::destroy_instance(instance); } + +TEST_CASE("Select all Physical Devices", "[VkBootstrap.bootstrap]") { + + auto window = create_window_glfw("Select all Physical Devices"); + auto instance = get_instance(1); + auto surface = create_surface_glfw(instance.instance, window); + + vkb::PhysicalDeviceSelector phys_device_selector(instance, surface); + + auto phys_device_ret = phys_device_selector.select_devices(); + REQUIRE(phys_device_ret.has_value()); + auto phys_devices = phys_device_ret.value(); + + REQUIRE(phys_devices.at(0).name.size() > 0); + + auto phys_device_names_ret = phys_device_selector.select_device_names(); + REQUIRE(phys_device_names_ret.has_value()); + REQUIRE(phys_device_names_ret.value().at(0).size() > 0); + + vkb::DeviceBuilder device_builder(phys_devices.at(0)); + auto device_ret = device_builder.build(); + REQUIRE(device_ret.has_value()); + auto dispatch_table = device_ret.value().make_table(); +} + TEST_CASE("Loading Dispatch Table", "[VkBootstrap.bootstrap]") { auto instance = get_headless_instance(0); {