diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index f366207..60c1bfc 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -908,7 +908,6 @@ bool supports_features(VkPhysicalDeviceFeatures supported, if (requested.inheritedQueries && !supported.inheritedQueries) return false; for(auto i = 0; i < extension_requested.size(); ++i) { - //auto res = extension_requested[i].match(extension_supported[i]); auto res = GenericFeaturesPNextNode::match(extension_requested[i], extension_supported[i]); if(!res) return false; } @@ -1411,21 +1410,47 @@ detail::Result DeviceBuilder::build() const { extensions.push_back({ VK_KHR_SWAPCHAIN_EXTENSION_NAME }); bool has_phys_dev_features_2 = false; + bool user_defined_phys_dev_features_2 = false; std::vector final_pnext_chain; + VkDeviceCreateInfo device_create_info = {}; #if defined(VK_API_VERSION_1_1) + for(auto& pnext : info.pNext_chain) { + if(pnext->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) { + user_defined_phys_dev_features_2 = true; + break; + } + } + + auto physical_device_extension_features_copy = physical_device.extended_features_chain; VkPhysicalDeviceFeatures2 local_features2{}; local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - auto physical_device_extension_features_copy = physical_device.extended_features_chain; - if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0)) { - has_phys_dev_features_2 = true; - for(auto& features_node : physical_device_extension_features_copy) { - final_pnext_chain.push_back(reinterpret_cast(&features_node)); + + if(!user_defined_phys_dev_features_2) { + if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0)) { + local_features2.features = physical_device.features; + final_pnext_chain.push_back(reinterpret_cast(&local_features2)); + has_phys_dev_features_2 = true; + for (auto& features_node : physical_device_extension_features_copy) { + final_pnext_chain.push_back(reinterpret_cast(&features_node)); + } } } + + if(!user_defined_phys_dev_features_2 && !has_phys_dev_features_2) { + device_create_info.pEnabledFeatures = &physical_device.features; + } #endif - VkDeviceCreateInfo device_create_info = {}; + for(auto& pnext : info.pNext_chain) { + final_pnext_chain.push_back(pnext); + } + + detail::setup_pNext_chain(device_create_info, final_pnext_chain); + for(auto& node : final_pnext_chain) { + assert(node->sType != VK_STRUCTURE_TYPE_APPLICATION_INFO); + } + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.flags = info.flags; device_create_info.queueCreateInfoCount = static_cast(queueCreateInfos.size()); @@ -1433,30 +1458,10 @@ detail::Result DeviceBuilder::build() const { device_create_info.enabledExtensionCount = static_cast(extensions.size()); device_create_info.ppEnabledExtensionNames = extensions.data(); - for(auto& pnext : info.pNext_chain) { - final_pnext_chain.push_back(pnext); + if(!final_pnext_chain.empty()) { + device_create_info.pNext = final_pnext_chain.front(); } - detail::setup_pNext_chain(device_create_info, final_pnext_chain); - for(auto& node : final_pnext_chain) { - assert(node->sType != VK_STRUCTURE_TYPE_APPLICATION_INFO); - } - -#if defined(VK_API_VERSION_1_1) - // VUID-VkDeviceCreateInfo-pNext-00373 - don't add pEnabledFeatures if the phys_dev_features_2 is present - if (has_phys_dev_features_2) { - device_create_info.pNext = &local_features2; - if(!final_pnext_chain.empty()) { - local_features2.pNext = final_pnext_chain.front(); - } - device_create_info.pEnabledFeatures = nullptr; - } else { - device_create_info.pEnabledFeatures = &physical_device.features; - } -#else - device_create_info.pEnabledFeatures = &physical_device.features; -#endif - Device device; VkResult res = detail::vulkan_functions().fp_vkCreateDevice( diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index c9a2ec6..f9f2630 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -124,18 +124,18 @@ struct GenericFeaturesPNextNode { VkStructureType sType = static_cast(0); void* pNext = nullptr; - VkBool32 fields[256]; + static const uint32_t field_capacity = 256; + VkBool32 fields[field_capacity]; template void set(T const& features) { - GenericFeaturesPNextNode node; *reinterpret_cast(this) = features; } static bool match(GenericFeaturesPNextNode const& requested, GenericFeaturesPNextNode const& supported) { assert(requested.sType == supported.sType && "Non-matching sTypes in features nodes!"); - for (uint32_t i = 0; i < (sizeof(fields) / sizeof(VkBool32)); i++) { + for (uint32_t i = 0; i < field_capacity; i++) { if (requested.fields[i] && !supported.fields[i]) return false; } return true; @@ -362,6 +362,7 @@ struct PhysicalDevice { VkPhysicalDevice physical_device = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; + // Note that this reflects selected features carried over from required features, not all features the physical device supports. VkPhysicalDeviceFeatures features{}; VkPhysicalDeviceProperties properties{}; VkPhysicalDeviceMemoryProperties memory_properties{}; @@ -450,6 +451,8 @@ class PhysicalDeviceSelector { PhysicalDeviceSelector& add_required_extension_features(T const& features) { assert(features.sType != 0 && "Features struct sType must be filled with the struct's corresponding VkStructureType enum"); + assert(features.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."); detail::GenericFeaturesPNextNode node; node.set(features); criteria.extended_features_chain.push_back(node);