Added generic feature polling/matching/enabling.

This commit is contained in:
dangerkangaroo 2021-04-08 21:45:57 -05:00 committed by Charles Giessen
parent 23dcdd59bf
commit 0a397a33d5
2 changed files with 187 additions and 186 deletions

View File

@ -844,7 +844,10 @@ std::vector<const char*> check_device_extension_support(
} }
// clang-format off // clang-format off
bool supports_features(VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested) { bool supports_features(VkPhysicalDeviceFeatures supported,
VkPhysicalDeviceFeatures requested,
const std::vector<ExtensionFeatures>& extension_supported,
const std::vector<ExtensionFeatures>& extension_requested) {
if (requested.robustBufferAccess && !supported.robustBufferAccess) return false; if (requested.robustBufferAccess && !supported.robustBufferAccess) return false;
if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false; if (requested.fullDrawIndexUint32 && !supported.fullDrawIndexUint32) return false;
if (requested.imageCubeArray && !supported.imageCubeArray) return false; if (requested.imageCubeArray && !supported.imageCubeArray) return false;
@ -900,75 +903,14 @@ bool supports_features(VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatu
if (requested.sparseResidencyAliased && !supported.sparseResidencyAliased) return false; if (requested.sparseResidencyAliased && !supported.sparseResidencyAliased) return false;
if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false; if (requested.variableMultisampleRate && !supported.variableMultisampleRate) return false;
if (requested.inheritedQueries && !supported.inheritedQueries) return false; if (requested.inheritedQueries && !supported.inheritedQueries) return false;
return true;
} for(auto i = 0; i < extension_requested.size(); ++i) {
#if defined(VK_API_VERSION_1_2) auto res = extension_requested[i].match(extension_supported[i]);
bool supports_features_11(VkPhysicalDeviceVulkan11Features supported, VkPhysicalDeviceVulkan11Features requested){ if(!res) return false;
if (requested.storageBuffer16BitAccess && !supported.storageBuffer16BitAccess) return false; }
if (requested.uniformAndStorageBuffer16BitAccess && !supported.uniformAndStorageBuffer16BitAccess) return false;
if (requested.storagePushConstant16 && !supported.storagePushConstant16) return false;
if (requested.storageInputOutput16 && !supported.storageInputOutput16) return false;
if (requested.multiview && !supported.multiview) return false;
if (requested.multiviewGeometryShader && !supported.multiviewGeometryShader) return false;
if (requested.multiviewTessellationShader && !supported.multiviewTessellationShader) return false;
if (requested.variablePointersStorageBuffer && !supported.variablePointersStorageBuffer) return false;
if (requested.variablePointers && !supported.variablePointers) return false;
if (requested.protectedMemory && !supported.protectedMemory) return false;
if (requested.samplerYcbcrConversion && !supported.samplerYcbcrConversion) return false;
if (requested.shaderDrawParameters && !supported.shaderDrawParameters) return false;
return true; return true;
} }
bool supports_features_12(VkPhysicalDeviceVulkan12Features supported, VkPhysicalDeviceVulkan12Features requested){
if(requested.samplerMirrorClampToEdge && !supported.samplerMirrorClampToEdge) return false;
if(requested.drawIndirectCount && !supported.drawIndirectCount) return false;
if(requested.storageBuffer8BitAccess && !supported.storageBuffer8BitAccess) return false;
if(requested.uniformAndStorageBuffer8BitAccess && !supported.uniformAndStorageBuffer8BitAccess) return false;
if(requested.storagePushConstant8 && !supported.storagePushConstant8) return false;
if(requested.shaderBufferInt64Atomics && !supported.shaderBufferInt64Atomics) return false;
if(requested.shaderSharedInt64Atomics && !supported.shaderSharedInt64Atomics) return false;
if(requested.shaderFloat16 && !supported.shaderFloat16) return false;
if(requested.shaderInt8 && !supported.shaderInt8) return false;
if(requested.descriptorIndexing && !supported.descriptorIndexing) return false;
if(requested.shaderInputAttachmentArrayDynamicIndexing && !supported.shaderInputAttachmentArrayDynamicIndexing) return false;
if(requested.shaderUniformTexelBufferArrayDynamicIndexing && !supported.shaderUniformTexelBufferArrayDynamicIndexing) return false;
if(requested.shaderStorageTexelBufferArrayDynamicIndexing && !supported.shaderStorageTexelBufferArrayDynamicIndexing) return false;
if(requested.shaderUniformBufferArrayNonUniformIndexing && !supported.shaderUniformBufferArrayNonUniformIndexing) return false;
if(requested.shaderSampledImageArrayNonUniformIndexing && !supported.shaderSampledImageArrayNonUniformIndexing) return false;
if(requested.shaderStorageBufferArrayNonUniformIndexing && !supported.shaderStorageBufferArrayNonUniformIndexing) return false;
if(requested.shaderStorageImageArrayNonUniformIndexing && !supported.shaderStorageImageArrayNonUniformIndexing) return false;
if(requested.shaderInputAttachmentArrayNonUniformIndexing && !supported.shaderInputAttachmentArrayNonUniformIndexing) return false;
if(requested.shaderUniformTexelBufferArrayNonUniformIndexing && !supported.shaderUniformTexelBufferArrayNonUniformIndexing) return false;
if(requested.shaderStorageTexelBufferArrayNonUniformIndexing && !supported.shaderStorageTexelBufferArrayNonUniformIndexing) return false;
if(requested.descriptorBindingUniformBufferUpdateAfterBind && !supported.descriptorBindingUniformBufferUpdateAfterBind) return false;
if(requested.descriptorBindingSampledImageUpdateAfterBind && !supported.descriptorBindingSampledImageUpdateAfterBind) return false;
if(requested.descriptorBindingStorageImageUpdateAfterBind && !supported.descriptorBindingStorageImageUpdateAfterBind) return false;
if(requested.descriptorBindingStorageBufferUpdateAfterBind && !supported.descriptorBindingStorageBufferUpdateAfterBind) return false;
if(requested.descriptorBindingUniformTexelBufferUpdateAfterBind && !supported.descriptorBindingUniformTexelBufferUpdateAfterBind) return false;
if(requested.descriptorBindingStorageTexelBufferUpdateAfterBind && !supported.descriptorBindingStorageTexelBufferUpdateAfterBind) return false;
if(requested.descriptorBindingUpdateUnusedWhilePending && !supported.descriptorBindingUpdateUnusedWhilePending) return false;
if(requested.descriptorBindingPartiallyBound && !supported.descriptorBindingPartiallyBound) return false;
if(requested.descriptorBindingVariableDescriptorCount && !supported.descriptorBindingVariableDescriptorCount) return false;
if(requested.runtimeDescriptorArray && !supported.runtimeDescriptorArray) return false;
if(requested.samplerFilterMinmax && !supported.samplerFilterMinmax) return false;
if(requested.scalarBlockLayout && !supported.scalarBlockLayout) return false;
if(requested.imagelessFramebuffer && !supported.imagelessFramebuffer) return false;
if(requested.uniformBufferStandardLayout && !supported.uniformBufferStandardLayout) return false;
if(requested.shaderSubgroupExtendedTypes && !supported.shaderSubgroupExtendedTypes) return false;
if(requested.separateDepthStencilLayouts && !supported.separateDepthStencilLayouts) return false;
if(requested.hostQueryReset && !supported.hostQueryReset) return false;
if(requested.timelineSemaphore && !supported.timelineSemaphore) return false;
if(requested.bufferDeviceAddress && !supported.bufferDeviceAddress) return false;
if(requested.bufferDeviceAddressCaptureReplay && !supported.bufferDeviceAddressCaptureReplay) return false;
if(requested.bufferDeviceAddressMultiDevice && !supported.bufferDeviceAddressMultiDevice) return false;
if(requested.vulkanMemoryModel && !supported.vulkanMemoryModel) return false;
if(requested.vulkanMemoryModelDeviceScope && !supported.vulkanMemoryModelDeviceScope) return false;
if(requested.vulkanMemoryModelAvailabilityVisibilityChains && !supported.vulkanMemoryModelAvailabilityVisibilityChains) return false;
if(requested.shaderOutputViewportIndex && !supported.shaderOutputViewportIndex) return false;
if(requested.shaderOutputLayer && !supported.shaderOutputLayer) return false;
if(requested.subgroupBroadcastDynamicId && !supported.subgroupBroadcastDynamicId) return false;
return true;
}
#endif
// clang-format on // clang-format on
// finds the first queue which supports graphics operations. returns QUEUE_INDEX_MAX_VALUE if none is found // finds the first queue which supports graphics operations. returns QUEUE_INDEX_MAX_VALUE if none is found
uint32_t get_graphics_queue_index(std::vector<VkQueueFamilyProperties> const& families) { uint32_t get_graphics_queue_index(std::vector<VkQueueFamilyProperties> const& families) {
@ -1049,7 +991,8 @@ uint32_t get_present_queue_index(VkPhysicalDevice const phys_device,
PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details( PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details(
uint32_t instance_version, VkPhysicalDevice phys_device) const { uint32_t instance_version, VkPhysicalDevice phys_device,
std::vector<ExtensionFeatures> extension_features_as_template) const {
PhysicalDeviceSelector::PhysicalDeviceDesc desc{}; PhysicalDeviceSelector::PhysicalDeviceDesc desc{};
desc.phys_device = phys_device; desc.phys_device = phys_device;
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties>( auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties>(
@ -1062,16 +1005,20 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
desc.extension_features = extension_features_as_template;
#if defined(VK_API_VERSION_1_2) if (instance_version >= VK_API_VERSION_1_1) {
desc.device_features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; ExtensionFeatures* prev = nullptr;
desc.device_features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; for(auto& extension : desc.extension_features) {
desc.device_features2.pNext = &desc.device_features_11; if(prev != nullptr) {
desc.device_features_11.pNext = &desc.device_features_12; prev->structure->pNext = extension.structure;
#endif }
if (instance_version >= VK_API_VERSION_1_1) { prev = &extension;
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(phys_device, &desc.device_features2); }
} if(desc.extension_features.size() > 0) {
desc.device_features2.pNext = &desc.extension_features[0].structure;
}
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(phys_device, &desc.device_features2);
}
#endif #endif
return desc; return desc;
} }
@ -1112,7 +1059,6 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(Phys
if (desired_extensions_supported.size() != criteria.desired_extensions.size()) if (desired_extensions_supported.size() != criteria.desired_extensions.size())
suitable = Suitable::partial; suitable = Suitable::partial;
bool swapChainAdequate = false; bool swapChainAdequate = false;
if (criteria.defer_surface_initialization) { if (criteria.defer_surface_initialization) {
swapChainAdequate = true; swapChainAdequate = true;
@ -1142,21 +1088,10 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(Phys
return Suitable::no; return Suitable::no;
} }
bool required_features_supported = detail::supports_features(pd.device_features, criteria.required_features); bool required_features_supported = detail::supports_features(pd.device_features, criteria.required_features,
pd.extension_features, criteria.extension_features);
if (!required_features_supported) return Suitable::no; if (!required_features_supported) return Suitable::no;
#if defined(VK_API_VERSION_1_2)
if (instance_info.version >= VK_API_VERSION_1_2) {
bool required_features_11_supported =
detail::supports_features_11(pd.device_features_11, criteria.required_features_11);
if (!required_features_11_supported) return Suitable::no;
bool required_features_12_supported =
detail::supports_features_12(pd.device_features_12, criteria.required_features_12);
if (!required_features_12_supported) return Suitable::no;
}
#endif
bool has_required_memory = false; bool has_required_memory = false;
bool has_preferred_memory = false; bool has_preferred_memory = false;
for (uint32_t i = 0; i < pd.mem_properties.memoryHeapCount; i++) { for (uint32_t i = 0; i < pd.mem_properties.memoryHeapCount; i++) {
@ -1205,7 +1140,9 @@ detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const {
std::vector<PhysicalDeviceDesc> phys_device_descriptions; std::vector<PhysicalDeviceDesc> phys_device_descriptions;
for (auto& phys_device : physical_devices) { for (auto& phys_device : physical_devices) {
phys_device_descriptions.push_back(populate_device_details(instance_info.version, phys_device)); phys_device_descriptions.push_back(populate_device_details(instance_info.version,
phys_device,
criteria.extension_features));
} }
PhysicalDeviceDesc selected_device{}; PhysicalDeviceDesc selected_device{};
@ -1231,12 +1168,7 @@ detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const {
out_device.physical_device = selected_device.phys_device; out_device.physical_device = selected_device.phys_device;
out_device.surface = instance_info.surface; out_device.surface = instance_info.surface;
out_device.features = criteria.required_features; out_device.features = criteria.required_features;
#if defined(VK_API_VERSION_1_2) out_device.extension_features = criteria.extension_features;
out_device.features_11 = criteria.required_features_11;
out_device.features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
out_device.features_12 = criteria.required_features_12;
out_device.features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
#endif
out_device.properties = selected_device.device_properties; out_device.properties = selected_device.device_properties;
out_device.memory_properties = selected_device.mem_properties; out_device.memory_properties = selected_device.mem_properties;
out_device.queue_families = selected_device.queue_families; out_device.queue_families = selected_device.queue_families;
@ -1321,20 +1253,17 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::set_desired_version(uint32_t maj
criteria.desired_version = VK_MAKE_VERSION(major, minor, 0); criteria.desired_version = VK_MAKE_VERSION(major, minor, 0);
return *this; return *this;
} }
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features(VkPhysicalDeviceFeatures const& features) {
criteria.required_features = features;
return *this;
}
#if defined(VK_API_VERSION_1_2) #if defined(VK_API_VERSION_1_2)
// Just calls add_required_features
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11( PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11(
VkPhysicalDeviceVulkan11Features const& features_11) { VkPhysicalDeviceVulkan11Features const& features_11) {
criteria.required_features_11 = features_11; add_required_features(features_11);
return *this; return *this;
} }
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12( PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12(
VkPhysicalDeviceVulkan12Features const& features_12) { VkPhysicalDeviceVulkan12Features const& features_12) {
criteria.required_features_12 = features_12; add_required_features(features_12);
return *this; return *this;
} }
#endif #endif
PhysicalDeviceSelector& PhysicalDeviceSelector::defer_surface_initialization() { PhysicalDeviceSelector& PhysicalDeviceSelector::defer_surface_initialization() {
@ -1467,63 +1396,40 @@ detail::Result<Device> DeviceBuilder::build() const {
if (physical_device.surface != VK_NULL_HANDLE || physical_device.defer_surface_initialization) if (physical_device.surface != VK_NULL_HANDLE || physical_device.defer_surface_initialization)
extensions.push_back({ VK_KHR_SWAPCHAIN_EXTENSION_NAME }); extensions.push_back({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
std::vector<VkBaseOutStructure*> pNext_chain = info.pNext_chain; bool has_phys_dev_features_2 = false;
// check if certain structs were added in the pNext chain by the user // Setup the pNexts of all the extension features
bool has_phys_dev_features_2 = false;
bool has_phys_dev_vulkan_features_11 = false;
bool has_phys_dev_vulkan_features_12 = false;
for (auto& pNext_struct : pNext_chain) {
if (pNext_struct->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) {
has_phys_dev_features_2 = true;
}
if (pNext_struct->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES) {
has_phys_dev_vulkan_features_11 = true;
}
if (pNext_struct->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES) {
has_phys_dev_vulkan_features_12 = true;
}
}
// Add the correct structs to the pNext chain if api is 1.1/1.2 and aren't already present
// This is to guard against users who were already doing that
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 local_features2{}; VkPhysicalDeviceFeatures2 local_features2{};
if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0) && !has_phys_dev_features_2) { if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0) &&
local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; physical_device.extension_features.size() > 0) {
local_features2.features = physical_device.features; ExtensionFeatures* prev = nullptr;
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features2)); for(auto& extension : physical_device.extension_features) {
has_phys_dev_features_2 = true; if(prev != nullptr) {
} prev->structure->pNext = extension.structure;
#if defined(VK_API_VERSION_1_2) }
VkPhysicalDeviceVulkan11Features local_features_11 = physical_device.features_11; prev = &extension;
VkPhysicalDeviceVulkan12Features local_features_12 = physical_device.features_12; }
if (physical_device.instance_version >= VK_MAKE_VERSION(1, 2, 0)) { local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
if (!has_phys_dev_vulkan_features_11) { local_features2.features = physical_device.features;
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features_11)); local_features2.pNext = physical_device.extension_features[0].structure;
has_phys_dev_vulkan_features_11 = true; has_phys_dev_features_2 = true;
} }
if (!has_phys_dev_vulkan_features_12) {
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features_12));
has_phys_dev_vulkan_features_12 = true;
}
}
#endif
#endif #endif
VkDeviceCreateInfo device_create_info = {}; VkDeviceCreateInfo device_create_info = {};
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
detail::setup_pNext_chain(device_create_info, pNext_chain);
device_create_info.flags = info.flags; device_create_info.flags = info.flags;
device_create_info.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()); device_create_info.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
device_create_info.pQueueCreateInfos = queueCreateInfos.data(); device_create_info.pQueueCreateInfos = queueCreateInfos.data();
device_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size()); device_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
device_create_info.ppEnabledExtensionNames = extensions.data(); device_create_info.ppEnabledExtensionNames = extensions.data();
// VUID-VkDeviceCreateInfo-pNext-00373 - don't add pEnabledFeatures if the phys_dev_features_2 is present // VUID-VkDeviceCreateInfo-pNext-00373 - don't add pEnabledFeatures if the phys_dev_features_2 is present
if (!has_phys_dev_features_2) { if (!has_phys_dev_features_2) {
device_create_info.pEnabledFeatures = &physical_device.features; device_create_info.pEnabledFeatures = &physical_device.features;
} } else {
device_create_info.pNext = &local_features2;
}
Device device; Device device;
VkResult res = detail::vulkan_functions().fp_vkCreateDevice( VkResult res = detail::vulkan_functions().fp_vkCreateDevice(

View File

@ -195,6 +195,105 @@ struct SystemInfo {
class InstanceBuilder; class InstanceBuilder;
class PhysicalDeviceSelector; class PhysicalDeviceSelector;
struct ExtensionFeatures {
using DeleteProc = void(*)(ExtensionFeatures&);
using CopyProc = void(*)(const ExtensionFeatures&, ExtensionFeatures&);
ExtensionFeatures() = default;
ExtensionFeatures (const ExtensionFeatures& other) : delete_proc(other.delete_proc), copy_proc(other.copy_proc) {
if(copy_proc) { copy_proc(other, *this); }
}
ExtensionFeatures (ExtensionFeatures&& other) : delete_proc(std::exchange(other.delete_proc, nullptr)),
copy_proc(std::exchange(other.copy_proc, nullptr)),
structure(std::exchange(other.structure, nullptr)),
fields(std::exchange(other.fields, {})) {}
ExtensionFeatures& operator=(const ExtensionFeatures& other) {
delete_proc = other.delete_proc;
copy_proc = other.copy_proc;
if(copy_proc) { copy_proc(other, *this); }
return *this;
}
ExtensionFeatures& operator=(ExtensionFeatures&& other) {
delete_proc = std::exchange(other.delete_proc, nullptr);
copy_proc = std::exchange(other.copy_proc, nullptr);
structure = std::exchange(other.structure, nullptr);
fields = std::exchange(other.fields, {});
return *this;
}
template <typename T>
static ExtensionFeatures make(T src) {
ExtensionFeatures extension_features;
T* new_features_structure = new T;
*new_features_structure = src;
extension_features.structure = reinterpret_cast<VkBaseOutStructure*>(new_features_structure);
auto structure_field_count =
(sizeof(T) - (sizeof(VkStructureType) + sizeof(void*))) / sizeof(VkBool32);
extension_features.fields.resize(structure_field_count);
memcpy(extension_features.fields.data(),
reinterpret_cast<unsigned char*>(extension_features.structure) +
(sizeof(VkStructureType) + sizeof(void*)),
sizeof(VkBool32) * extension_features.fields.size());
extension_features.delete_proc = [](ExtensionFeatures& features) {
features.fields = {};
if(features.structure) {
auto casted = reinterpret_cast<T *>(features.structure);
delete casted;
}
};
extension_features.copy_proc = [](const ExtensionFeatures& src, ExtensionFeatures& dst) {
if(dst.structure) {
auto casted = reinterpret_cast<T*>(dst.structure);
delete casted;
}
T* new_features_structure = new T;
*new_features_structure = *reinterpret_cast<T*>(src.structure);
dst.structure = reinterpret_cast<VkBaseOutStructure*>(new_features_structure);
dst.fields = src.fields;
};
return extension_features;
}
bool match(const ExtensionFeatures& other) const {
if(!structure || !other.structure || structure->sType != other.structure->sType) { return false; }
for(auto i = 0; i < fields.size(); ++i) {
if(fields[i] == VK_TRUE && other.fields[i] == VK_FALSE) {
return false;
}
}
return true;
}
~ExtensionFeatures() {
if(delete_proc) { delete_proc(*this); }
}
VkBaseOutStructure* structure = nullptr;
std::vector<VkBool32> fields;
private:
DeleteProc delete_proc = {};
CopyProc copy_proc = {};
};
struct Instance { struct Instance {
VkInstance instance = VK_NULL_HANDLE; VkInstance instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
@ -335,10 +434,6 @@ struct PhysicalDevice {
VkSurfaceKHR surface = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE;
VkPhysicalDeviceFeatures features{}; VkPhysicalDeviceFeatures features{};
#if defined(VK_API_VERSION_1_2)
VkPhysicalDeviceVulkan11Features features_11{};
VkPhysicalDeviceVulkan12Features features_12{};
#endif
VkPhysicalDeviceProperties properties{}; VkPhysicalDeviceProperties properties{};
VkPhysicalDeviceMemoryProperties memory_properties{}; VkPhysicalDeviceMemoryProperties memory_properties{};
@ -359,6 +454,7 @@ struct PhysicalDevice {
uint32_t instance_version = VK_MAKE_VERSION(1, 0, 0); uint32_t instance_version = VK_MAKE_VERSION(1, 0, 0);
std::vector<const char*> extensions_to_enable; std::vector<const char*> extensions_to_enable;
std::vector<VkQueueFamilyProperties> queue_families; std::vector<VkQueueFamilyProperties> queue_families;
mutable std::vector<ExtensionFeatures> extension_features;
bool defer_surface_initialization = false; bool defer_surface_initialization = false;
friend class PhysicalDeviceSelector; friend class PhysicalDeviceSelector;
friend class DeviceBuilder; friend class DeviceBuilder;
@ -419,16 +515,26 @@ class PhysicalDeviceSelector {
// Require a physical device that supports a (major, minor) version of vulkan. // Require a physical device that supports a (major, minor) version of vulkan.
PhysicalDeviceSelector& set_minimum_version(uint32_t major, uint32_t minor); PhysicalDeviceSelector& set_minimum_version(uint32_t major, uint32_t minor);
// Require a physical device which supports the features in VkPhysicalDeviceFeatures. // Require a physical device which supports a specific set of general/extension features.
PhysicalDeviceSelector& set_required_features(VkPhysicalDeviceFeatures const& features); template <typename T>
PhysicalDeviceSelector& add_required_features(T const& features) {
#if defined(VK_API_VERSION_1_1)
criteria.extension_features.push_back(ExtensionFeatures::make(features));
#endif
return *this;
}
template<>
PhysicalDeviceSelector& add_required_features<VkPhysicalDeviceFeatures>(VkPhysicalDeviceFeatures const& features) {
criteria.required_features = features;
return *this;
}
#if defined(VK_API_VERSION_1_2) #if defined(VK_API_VERSION_1_2)
// Require a physical device which supports the features in VkPhysicalDeviceVulkan11Features. // Require a physical device which supports the features in VkPhysicalDeviceVulkan11Features.
// Must have vulkan version 1.2 - This is due to the VkPhysicalDeviceVulkan11Features struct being added in 1.2, not 1.1 // Must have vulkan version 1.2 - This is due to the VkPhysicalDeviceVulkan11Features struct being added in 1.2, not 1.1
PhysicalDeviceSelector& set_required_features_11(VkPhysicalDeviceVulkan11Features const& features_11); PhysicalDeviceSelector& set_required_features_11(VkPhysicalDeviceVulkan11Features const& features_11);
// Require a physical device which supports the features in VkPhysicalDeviceVulkan12Features. // Require a physical device which supports the features in VkPhysicalDeviceVulkan12Features.
// Must have vulkan version 1.2 // Must have vulkan version 1.2
PhysicalDeviceSelector& set_required_features_12(VkPhysicalDeviceVulkan12Features const& features_12); PhysicalDeviceSelector& set_required_features_12(VkPhysicalDeviceVulkan12Features const& features_12);
#endif #endif
// Used when surface creation happens after physical device selection. // Used when surface creation happens after physical device selection.
@ -456,13 +562,16 @@ class PhysicalDeviceSelector {
VkPhysicalDeviceMemoryProperties mem_properties{}; VkPhysicalDeviceMemoryProperties mem_properties{};
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 device_features2{}; VkPhysicalDeviceFeatures2 device_features2{};
#endif std::vector<ExtensionFeatures> extension_features;
#if defined(VK_API_VERSION_1_2)
VkPhysicalDeviceVulkan11Features device_features_11{};
VkPhysicalDeviceVulkan12Features device_features_12{};
#endif #endif
}; };
PhysicalDeviceDesc populate_device_details(uint32_t instance_version, VkPhysicalDevice phys_device) const;
// 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(uint32_t instance_version,
VkPhysicalDevice phys_device,
std::vector<ExtensionFeatures> extension_features_as_template) const;
struct SelectionCriteria { struct SelectionCriteria {
PreferredDeviceType preferred_type = PreferredDeviceType::discrete; PreferredDeviceType preferred_type = PreferredDeviceType::discrete;
@ -484,13 +593,8 @@ class PhysicalDeviceSelector {
VkPhysicalDeviceFeatures required_features{}; VkPhysicalDeviceFeatures required_features{};
#if defined(VK_API_VERSION_1_1) #if defined(VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 required_features2{}; VkPhysicalDeviceFeatures2 required_features2{};
std::vector<ExtensionFeatures> extension_features;
#endif #endif
#if defined(VK_API_VERSION_1_2)
VkPhysicalDeviceVulkan11Features required_features_11{};
VkPhysicalDeviceVulkan12Features required_features_12{};
#endif
bool defer_surface_initialization = false; bool defer_surface_initialization = false;
bool use_first_gpu_unconditionally = false; bool use_first_gpu_unconditionally = false;
} criteria; } criteria;
@ -547,13 +651,6 @@ class DeviceBuilder {
// If a custom queue setup is provided, getting the queues and queue indexes is up to the application. // If a custom queue setup is provided, getting the queues and queue indexes is up to the application.
DeviceBuilder& custom_queue_setup(std::vector<CustomQueueDescription> queue_descriptions); DeviceBuilder& custom_queue_setup(std::vector<CustomQueueDescription> queue_descriptions);
// Add a structure to the pNext chain of VkDeviceCreateInfo.
// The structure must be valid when DeviceBuilder::build() is called.
template <typename T> DeviceBuilder& add_pNext(T* structure) {
info.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
return *this;
}
// Provide custom allocation callbacks. // Provide custom allocation callbacks.
DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks); DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
@ -561,8 +658,6 @@ class DeviceBuilder {
PhysicalDevice physical_device; PhysicalDevice physical_device;
struct DeviceInfo { struct DeviceInfo {
VkDeviceCreateFlags flags = 0; VkDeviceCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain;
std::vector<CustomQueueDescription> queue_descriptions; std::vector<CustomQueueDescription> queue_descriptions;
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
} info; } info;