@@ -47,6 +47,54 @@ bool GenericFeaturesPNextNode::match(GenericFeaturesPNextNode const& requested,
4747 return true ;
4848}
4949
50+ void GenericFeaturesPNextNode::combine (GenericFeaturesPNextNode const & right) noexcept {
51+ assert (sType == right.sType && " Non-matching sTypes in features nodes!" );
52+ for (uint32_t i = 0 ; i < GenericFeaturesPNextNode::field_capacity; i++) {
53+ fields[i] = fields[i] || right.fields [i];
54+ }
55+ }
56+
57+ bool GenericFeatureChain::match (GenericFeatureChain const & extension_requested) const noexcept {
58+ // Should only be false if extension_supported was unable to be filled out, due to the
59+ // physical device not supporting vkGetPhysicalDeviceFeatures2 in any capacity.
60+ if (extension_requested.nodes .size () != nodes.size ()) {
61+ return false ;
62+ }
63+
64+ for (size_t i = 0 ; i < nodes.size () && i < nodes.size (); ++i) {
65+ if (!GenericFeaturesPNextNode::match (extension_requested.nodes [i], nodes[i])) return false ;
66+ }
67+ return true ;
68+ }
69+
70+ void GenericFeatureChain::chain_up (VkPhysicalDeviceFeatures2& feats2) noexcept {
71+ detail::GenericFeaturesPNextNode* prev = nullptr ;
72+ for (auto & extension : nodes) {
73+ if (prev != nullptr ) {
74+ prev->pNext = &extension;
75+ }
76+ prev = &extension;
77+ }
78+ feats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ;
79+ feats2.pNext = !nodes.empty () ? &nodes.at (0 ) : nullptr ;
80+ }
81+
82+ void GenericFeatureChain::combine (GenericFeatureChain const & right) noexcept {
83+ for (const auto & right_node : right.nodes ) {
84+ bool already_contained = false ;
85+ for (auto & left_node : nodes) {
86+ if (left_node.sType == right_node.sType ) {
87+ left_node.combine (right_node);
88+ already_contained = true ;
89+ }
90+ }
91+ if (!already_contained) {
92+ nodes.push_back (right_node);
93+ }
94+ }
95+ }
96+
97+
5098class VulkanFunctions {
5199 private:
52100 std::mutex init_mutex;
@@ -863,10 +911,68 @@ std::vector<std::string> check_device_extension_support(
863911}
864912
865913// clang-format off
914+ void combine_features (VkPhysicalDeviceFeatures& dest, VkPhysicalDeviceFeatures src){
915+ dest.robustBufferAccess = dest.robustBufferAccess || src.robustBufferAccess ;
916+ dest.fullDrawIndexUint32 = dest.fullDrawIndexUint32 || src.fullDrawIndexUint32 ;
917+ dest.imageCubeArray = dest.imageCubeArray || src.imageCubeArray ;
918+ dest.independentBlend = dest.independentBlend || src.independentBlend ;
919+ dest.geometryShader = dest.geometryShader || src.geometryShader ;
920+ dest.tessellationShader = dest.tessellationShader || src.tessellationShader ;
921+ dest.sampleRateShading = dest.sampleRateShading || src.sampleRateShading ;
922+ dest.dualSrcBlend = dest.dualSrcBlend || src.dualSrcBlend ;
923+ dest.logicOp = dest.logicOp || src.logicOp ;
924+ dest.multiDrawIndirect = dest.multiDrawIndirect || src.multiDrawIndirect ;
925+ dest.drawIndirectFirstInstance = dest.drawIndirectFirstInstance || src.drawIndirectFirstInstance ;
926+ dest.depthClamp = dest.depthClamp || src.depthClamp ;
927+ dest.depthBiasClamp = dest.depthBiasClamp || src.depthBiasClamp ;
928+ dest.fillModeNonSolid = dest.fillModeNonSolid || src.fillModeNonSolid ;
929+ dest.depthBounds = dest.depthBounds || src.depthBounds ;
930+ dest.wideLines = dest.wideLines || src.wideLines ;
931+ dest.largePoints = dest.largePoints || src.largePoints ;
932+ dest.alphaToOne = dest.alphaToOne || src.alphaToOne ;
933+ dest.multiViewport = dest.multiViewport || src.multiViewport ;
934+ dest.samplerAnisotropy = dest.samplerAnisotropy || src.samplerAnisotropy ;
935+ dest.textureCompressionETC2 = dest.textureCompressionETC2 || src.textureCompressionETC2 ;
936+ dest.textureCompressionASTC_LDR = dest.textureCompressionASTC_LDR || src.textureCompressionASTC_LDR ;
937+ dest.textureCompressionBC = dest.textureCompressionBC || src.textureCompressionBC ;
938+ dest.occlusionQueryPrecise = dest.occlusionQueryPrecise || src.occlusionQueryPrecise ;
939+ dest.pipelineStatisticsQuery = dest.pipelineStatisticsQuery || src.pipelineStatisticsQuery ;
940+ dest.vertexPipelineStoresAndAtomics = dest.vertexPipelineStoresAndAtomics || src.vertexPipelineStoresAndAtomics ;
941+ dest.fragmentStoresAndAtomics = dest.fragmentStoresAndAtomics || src.fragmentStoresAndAtomics ;
942+ dest.shaderTessellationAndGeometryPointSize = dest.shaderTessellationAndGeometryPointSize || src.shaderTessellationAndGeometryPointSize ;
943+ dest.shaderImageGatherExtended = dest.shaderImageGatherExtended || src.shaderImageGatherExtended ;
944+ dest.shaderStorageImageExtendedFormats = dest.shaderStorageImageExtendedFormats || src.shaderStorageImageExtendedFormats ;
945+ dest.shaderStorageImageMultisample = dest.shaderStorageImageMultisample || src.shaderStorageImageMultisample ;
946+ dest.shaderStorageImageReadWithoutFormat = dest.shaderStorageImageReadWithoutFormat || src.shaderStorageImageReadWithoutFormat ;
947+ dest.shaderStorageImageWriteWithoutFormat = dest.shaderStorageImageWriteWithoutFormat || src.shaderStorageImageWriteWithoutFormat ;
948+ dest.shaderUniformBufferArrayDynamicIndexing = dest.shaderUniformBufferArrayDynamicIndexing || src.shaderUniformBufferArrayDynamicIndexing ;
949+ dest.shaderSampledImageArrayDynamicIndexing = dest.shaderSampledImageArrayDynamicIndexing || src.shaderSampledImageArrayDynamicIndexing ;
950+ dest.shaderStorageBufferArrayDynamicIndexing = dest.shaderStorageBufferArrayDynamicIndexing || src.shaderStorageBufferArrayDynamicIndexing ;
951+ dest.shaderStorageImageArrayDynamicIndexing = dest.shaderStorageImageArrayDynamicIndexing || src.shaderStorageImageArrayDynamicIndexing ;
952+ dest.shaderClipDistance = dest.shaderClipDistance || src.shaderClipDistance ;
953+ dest.shaderCullDistance = dest.shaderCullDistance || src.shaderCullDistance ;
954+ dest.shaderFloat64 = dest.shaderFloat64 || src.shaderFloat64 ;
955+ dest.shaderInt64 = dest.shaderInt64 || src.shaderInt64 ;
956+ dest.shaderInt16 = dest.shaderInt16 || src.shaderInt16 ;
957+ dest.shaderResourceResidency = dest.shaderResourceResidency || src.shaderResourceResidency ;
958+ dest.shaderResourceMinLod = dest.shaderResourceMinLod || src.shaderResourceMinLod ;
959+ dest.sparseBinding = dest.sparseBinding || src.sparseBinding ;
960+ dest.sparseResidencyBuffer = dest.sparseResidencyBuffer || src.sparseResidencyBuffer ;
961+ dest.sparseResidencyImage2D = dest.sparseResidencyImage2D || src.sparseResidencyImage2D ;
962+ dest.sparseResidencyImage3D = dest.sparseResidencyImage3D || src.sparseResidencyImage3D ;
963+ dest.sparseResidency2Samples = dest.sparseResidency2Samples || src.sparseResidency2Samples ;
964+ dest.sparseResidency4Samples = dest.sparseResidency4Samples || src.sparseResidency4Samples ;
965+ dest.sparseResidency8Samples = dest.sparseResidency8Samples || src.sparseResidency8Samples ;
966+ dest.sparseResidency16Samples = dest.sparseResidency16Samples || src.sparseResidency16Samples ;
967+ dest.sparseResidencyAliased = dest.sparseResidencyAliased || src.sparseResidencyAliased ;
968+ dest.variableMultisampleRate = dest.variableMultisampleRate || src.variableMultisampleRate ;
969+ dest.inheritedQueries = dest.inheritedQueries || src.inheritedQueries ;
970+ }
971+
866972bool supports_features (VkPhysicalDeviceFeatures supported,
867973 VkPhysicalDeviceFeatures requested,
868- std::vector<GenericFeaturesPNextNode> const & extension_supported,
869- std::vector<GenericFeaturesPNextNode> const & extension_requested) {
974+ GenericFeatureChain const & extension_supported,
975+ GenericFeatureChain const & extension_requested) {
870976 if (requested.robustBufferAccess && !supported.robustBufferAccess ) return false ;
871977 if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32 ) return false ;
872978 if (requested.imageCubeArray && !supported.imageCubeArray ) return false ;
@@ -923,18 +1029,7 @@ bool supports_features(VkPhysicalDeviceFeatures supported,
9231029 if (requested.variableMultisampleRate && !supported.variableMultisampleRate ) return false ;
9241030 if (requested.inheritedQueries && !supported.inheritedQueries ) return false ;
9251031
926- // Should only be false if extension_supported was unable to be filled out, due to the
927- // physical device not supporting vkGetPhysicalDeviceFeatures2 in any capacity.
928- if (extension_requested.size () != extension_supported.size ()) {
929- return false ;
930- }
931-
932- for (size_t i = 0 ; i < extension_requested.size () && i < extension_supported.size (); ++i) {
933- auto res = GenericFeaturesPNextNode::match (extension_requested[i], extension_supported[i]);
934- if (!res) return false ;
935- }
936-
937- return true ;
1032+ return extension_supported.match (extension_requested);
9381033}
9391034// clang-format on
9401035// Finds the first queue which supports the desired operations. Returns QUEUE_INDEX_MAX_VALUE if none is found
@@ -988,8 +1083,8 @@ uint32_t get_present_queue_index(
9881083}
9891084} // namespace detail
9901085
991- PhysicalDevice PhysicalDeviceSelector::populate_device_details (VkPhysicalDevice vk_phys_device,
992- std::vector< detail::GenericFeaturesPNextNode> const & src_extended_features_chain) const {
1086+ PhysicalDevice PhysicalDeviceSelector::populate_device_details (
1087+ VkPhysicalDevice vk_phys_device, detail::GenericFeatureChain const & src_extended_features_chain) const {
9931088 PhysicalDevice physical_device{};
9941089 physical_device.physical_device = vk_phys_device;
9951090 physical_device.surface = instance_info.surface ;
@@ -1013,25 +1108,14 @@ PhysicalDevice PhysicalDeviceSelector::populate_device_details(VkPhysicalDevice
10131108 physical_device.available_extensions .push_back (&ext.extensionName [0 ]);
10141109 }
10151110
1016- physical_device.features2 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ; // same value as the non-KHR version
10171111 physical_device.properties2_ext_enabled = instance_info.properties2_ext_enabled ;
10181112
10191113 auto fill_chain = src_extended_features_chain;
10201114
10211115 bool instance_is_1_1 = instance_info.version >= VKB_VK_API_VERSION_1_1 ;
1022- if (!fill_chain.empty () && (instance_is_1_1 || instance_info.properties2_ext_enabled )) {
1023-
1024- detail::GenericFeaturesPNextNode* prev = nullptr ;
1025- for (auto & extension : fill_chain) {
1026- if (prev != nullptr ) {
1027- prev->pNext = &extension;
1028- }
1029- prev = &extension;
1030- }
1031-
1116+ if (!fill_chain.nodes .empty () && (instance_is_1_1 || instance_info.properties2_ext_enabled )) {
10321117 VkPhysicalDeviceFeatures2 local_features{};
1033- local_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ; // KHR is same as core here
1034- local_features.pNext = &fill_chain.front ();
1118+ fill_chain.chain_up (local_features);
10351119 // Use KHR function if not able to use the core function
10361120 if (instance_is_1_1) {
10371121 detail::vulkan_functions ().fp_vkGetPhysicalDeviceFeatures2 (vk_phys_device, &local_features);
@@ -1135,7 +1219,7 @@ PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance, VkSurfa
11351219Result<std::vector<PhysicalDevice>> PhysicalDeviceSelector::select_impl (DeviceSelectionMode selection) const {
11361220#if !defined(NDEBUG)
11371221 // Validation
1138- for (const auto & node : criteria.extended_features_chain ) {
1222+ for (const auto & node : criteria.extended_features_chain . nodes ) {
11391223 assert (node.sType != static_cast <VkStructureType>(0 ) &&
11401224 " Features struct sType must be filled with the struct's "
11411225 " corresponding VkStructureType enum" );
@@ -1336,7 +1420,7 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::disable_portability_subset() {
13361420}
13371421
13381422PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features (VkPhysicalDeviceFeatures const & features) {
1339- criteria.required_features = features;
1423+ detail::combine_features ( criteria.required_features , features) ;
13401424 return *this ;
13411425}
13421426#if defined(VKB_VK_API_VERSION_1_2)
@@ -1399,7 +1483,7 @@ bool PhysicalDevice::enable_extension_if_present(const char* extension) {
13991483 }
14001484 return false ;
14011485}
1402- bool PhysicalDevice::enable_extensions_if_present (const std::vector<const char *>& extensions) {
1486+ bool PhysicalDevice::enable_extensions_if_present (const std::vector<const char *>& extensions) {
14031487 for (const auto extension : extensions) {
14041488 auto it = std::find_if (std::begin (available_extensions),
14051489 std::end (available_extensions),
@@ -1411,6 +1495,39 @@ bool PhysicalDevice::enable_extensions_if_present(const std::vector<const char*>
14111495 return true ;
14121496}
14131497
1498+ bool PhysicalDevice::enable_features_if_present (const VkPhysicalDeviceFeatures& features_to_enable) {
1499+ VkPhysicalDeviceFeatures actual_pdf{};
1500+ detail::vulkan_functions ().fp_vkGetPhysicalDeviceFeatures (physical_device, &actual_pdf);
1501+
1502+ bool required_features_supported = detail::supports_features (actual_pdf, features_to_enable, {}, {});
1503+ if (required_features_supported) {
1504+ detail::combine_features (features, features_to_enable);
1505+ }
1506+ return required_features_supported;
1507+ }
1508+
1509+ bool PhysicalDevice::enable_features_node_if_present (detail::GenericFeaturesPNextNode const & node) {
1510+ VkPhysicalDeviceFeatures2 actual_pdf2{};
1511+
1512+ detail::GenericFeatureChain requested_features;
1513+ requested_features.nodes .push_back (node);
1514+
1515+ detail::GenericFeatureChain fill_chain = requested_features;
1516+ // Zero out supported features
1517+ memset (fill_chain.nodes .front ().fields , UINT8_MAX , sizeof (VkBool32) * detail::GenericFeaturesPNextNode::field_capacity);
1518+
1519+ actual_pdf2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ;
1520+ fill_chain.chain_up (actual_pdf2);
1521+
1522+ detail::vulkan_functions ().fp_vkGetPhysicalDeviceFeatures2 (physical_device, &actual_pdf2);
1523+ bool required_features_supported = detail::supports_features ({}, {}, fill_chain, requested_features);
1524+ if (required_features_supported) {
1525+ extended_features_chain.combine (requested_features);
1526+ }
1527+ return required_features_supported;
1528+ }
1529+
1530+
14141531PhysicalDevice::operator VkPhysicalDevice () const { return this ->physical_device ; }
14151532
14161533// ---- Queues ---- //
@@ -1527,20 +1644,20 @@ Result<Device> DeviceBuilder::build() const {
15271644 }
15281645 }
15291646
1530- if (user_defined_phys_dev_features_2 && !physical_device.extended_features_chain .empty ()) {
1647+ if (user_defined_phys_dev_features_2 && !physical_device.extended_features_chain .nodes . empty ()) {
15311648 return { DeviceError::VkPhysicalDeviceFeatures2_in_pNext_chain_while_using_add_required_extension_features };
15321649 }
15331650
15341651 // These objects must be alive during the call to vkCreateDevice
15351652 auto physical_device_extension_features_copy = physical_device.extended_features_chain ;
15361653 VkPhysicalDeviceFeatures2 local_features2{};
15371654 local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 ;
1655+ local_features2.features = physical_device.features ;
15381656
15391657 if (!user_defined_phys_dev_features_2) {
15401658 if (physical_device.instance_version >= VKB_VK_API_VERSION_1_1 || physical_device.properties2_ext_enabled ) {
1541- local_features2.features = physical_device.features ;
15421659 final_pnext_chain.push_back (reinterpret_cast <VkBaseOutStructure*>(&local_features2));
1543- for (auto & features_node : physical_device_extension_features_copy) {
1660+ for (auto & features_node : physical_device_extension_features_copy. nodes ) {
15441661 final_pnext_chain.push_back (reinterpret_cast <VkBaseOutStructure*>(&features_node));
15451662 }
15461663 } else {
0 commit comments