Add selection by and enableing 1.1 and 1.2 features.

Users can now ask for physical devices which support a specific 1.1 and 1.2
feature. VkBootstrap will then add the selected features to the enable list
in device creation.
This commit is contained in:
Charles Giessen 2021-03-26 17:34:10 -06:00 committed by Charles Giessen
parent 94ebc3e9a1
commit 151c76d1cc
4 changed files with 498 additions and 295 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
*.vs *.vs
*.idea *.idea
cmake-build-* cmake-build-*
build

View File

@ -843,8 +843,8 @@ std::vector<const char*> check_device_extension_support(
return extensions_to_enable; return extensions_to_enable;
} }
// clang-format off
bool supports_features(VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested) { bool supports_features(VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested) {
// clang-format off
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,10 +900,76 @@ 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;
// clang-format on
return true; return true;
} }
#if defined(VK_API_VERSION_1_2)
bool supports_features_11(VkPhysicalDeviceVulkan11Features supported, VkPhysicalDeviceVulkan11Features requested){
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;
}
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
// 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) {
for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) { for (uint32_t i = 0; i < static_cast<uint32_t>(families.size()); i++) {
@ -983,7 +1049,7 @@ uint32_t get_present_queue_index(VkPhysicalDevice const phys_device,
PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details( PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_device_details(
VkPhysicalDevice phys_device) const { uint32_t instance_version, VkPhysicalDevice phys_device) 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>(
@ -993,6 +1059,20 @@ PhysicalDeviceSelector::PhysicalDeviceDesc PhysicalDeviceSelector::populate_devi
detail::vulkan_functions().fp_vkGetPhysicalDeviceProperties(phys_device, &desc.device_properties); detail::vulkan_functions().fp_vkGetPhysicalDeviceProperties(phys_device, &desc.device_properties);
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures(phys_device, &desc.device_features); detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures(phys_device, &desc.device_features);
detail::vulkan_functions().fp_vkGetPhysicalDeviceMemoryProperties(phys_device, &desc.mem_properties); detail::vulkan_functions().fp_vkGetPhysicalDeviceMemoryProperties(phys_device, &desc.mem_properties);
#if defined(VK_API_VERSION_1_1)
desc.device_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
#if defined(VK_API_VERSION_1_2)
desc.device_features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
desc.device_features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
desc.device_features2.pNext = &desc.device_features_11;
desc.device_features_11.pNext = &desc.device_features_12;
#endif
if (instance_version >= VK_API_VERSION_1_1) {
detail::vulkan_functions().fp_vkGetPhysicalDeviceFeatures2(phys_device, &desc.device_features2);
}
#endif
return desc; return desc;
} }
@ -1012,7 +1092,7 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(Phys
detail::get_separate_transfer_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE; detail::get_separate_transfer_queue_index(pd.queue_families) != detail::QUEUE_INDEX_MAX_VALUE;
bool present_queue = bool present_queue =
detail::get_present_queue_index(pd.phys_device, system_info.surface, pd.queue_families) != detail::get_present_queue_index(pd.phys_device, instance_info.surface, pd.queue_families) !=
detail::QUEUE_INDEX_MAX_VALUE; detail::QUEUE_INDEX_MAX_VALUE;
if (criteria.require_dedicated_compute_queue && !dedicated_compute) return Suitable::no; if (criteria.require_dedicated_compute_queue && !dedicated_compute) return Suitable::no;
@ -1036,18 +1116,18 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(Phys
bool swapChainAdequate = false; bool swapChainAdequate = false;
if (criteria.defer_surface_initialization) { if (criteria.defer_surface_initialization) {
swapChainAdequate = true; swapChainAdequate = true;
} else if (!system_info.headless) { } else if (!instance_info.headless) {
std::vector<VkSurfaceFormatKHR> formats; std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> present_modes; std::vector<VkPresentModeKHR> present_modes;
auto formats_ret = detail::get_vector<VkSurfaceFormatKHR>(formats, auto formats_ret = detail::get_vector<VkSurfaceFormatKHR>(formats,
detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceFormatsKHR, detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfaceFormatsKHR,
pd.phys_device, pd.phys_device,
system_info.surface); instance_info.surface);
auto present_modes_ret = detail::get_vector<VkPresentModeKHR>(present_modes, auto present_modes_ret = detail::get_vector<VkPresentModeKHR>(present_modes,
detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfacePresentModesKHR, detail::vulkan_functions().fp_vkGetPhysicalDeviceSurfacePresentModesKHR,
pd.phys_device, pd.phys_device,
system_info.surface); instance_info.surface);
if (formats_ret == VK_SUCCESS && present_modes_ret == VK_SUCCESS) { if (formats_ret == VK_SUCCESS && present_modes_ret == VK_SUCCESS) {
swapChainAdequate = !formats.empty() && !present_modes.empty(); swapChainAdequate = !formats.empty() && !present_modes.empty();
@ -1065,6 +1145,18 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(Phys
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);
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++) {
@ -1084,16 +1176,17 @@ PhysicalDeviceSelector::Suitable PhysicalDeviceSelector::is_device_suitable(Phys
} }
PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance) { PhysicalDeviceSelector::PhysicalDeviceSelector(Instance const& instance) {
system_info.instance = instance.instance; instance_info.instance = instance.instance;
system_info.headless = instance.headless; instance_info.headless = instance.headless;
instance_info.version = instance.instance_version;
criteria.require_present = !instance.headless; criteria.require_present = !instance.headless;
criteria.required_version = instance.instance_version; criteria.required_version = instance.instance_version;
criteria.desired_version = instance.instance_version; criteria.desired_version = instance.instance_version;
} }
detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const { detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const {
if (!system_info.headless && !criteria.defer_surface_initialization) { if (!instance_info.headless && !criteria.defer_surface_initialization) {
if (system_info.surface == VK_NULL_HANDLE) if (instance_info.surface == VK_NULL_HANDLE)
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_surface_provided }; return detail::Result<PhysicalDevice>{ PhysicalDeviceError::no_surface_provided };
} }
@ -1101,7 +1194,7 @@ detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const {
std::vector<VkPhysicalDevice> physical_devices; std::vector<VkPhysicalDevice> physical_devices;
auto physical_devices_ret = detail::get_vector<VkPhysicalDevice>( auto physical_devices_ret = detail::get_vector<VkPhysicalDevice>(
physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, system_info.instance); physical_devices, detail::vulkan_functions().fp_vkEnumeratePhysicalDevices, instance_info.instance);
if (physical_devices_ret != VK_SUCCESS) { if (physical_devices_ret != VK_SUCCESS) {
return detail::Result<PhysicalDevice>{ PhysicalDeviceError::failed_enumerate_physical_devices, return detail::Result<PhysicalDevice>{ PhysicalDeviceError::failed_enumerate_physical_devices,
physical_devices_ret }; physical_devices_ret };
@ -1112,7 +1205,7 @@ 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(phys_device)); phys_device_descriptions.push_back(populate_device_details(instance_info.version, phys_device));
} }
PhysicalDeviceDesc selected_device{}; PhysicalDeviceDesc selected_device{};
@ -1136,7 +1229,7 @@ detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const {
} }
PhysicalDevice out_device{}; PhysicalDevice out_device{};
out_device.physical_device = selected_device.phys_device; out_device.physical_device = selected_device.phys_device;
out_device.surface = system_info.surface; out_device.surface = instance_info.surface;
out_device.features = criteria.required_features; out_device.features = criteria.required_features;
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;
@ -1155,8 +1248,8 @@ detail::Result<PhysicalDevice> PhysicalDeviceSelector::select() const {
} }
PhysicalDeviceSelector& PhysicalDeviceSelector::set_surface(VkSurfaceKHR surface) { PhysicalDeviceSelector& PhysicalDeviceSelector::set_surface(VkSurfaceKHR surface) {
system_info.surface = surface; instance_info.surface = surface;
system_info.headless = false; instance_info.headless = false;
return *this; return *this;
} }
PhysicalDeviceSelector& PhysicalDeviceSelector::prefer_gpu_device_type(PreferredDeviceType type) { PhysicalDeviceSelector& PhysicalDeviceSelector::prefer_gpu_device_type(PreferredDeviceType type) {
@ -1221,10 +1314,22 @@ 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 features) { PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features(VkPhysicalDeviceFeatures const& features) {
criteria.required_features = features; criteria.required_features = features;
return *this; return *this;
} }
#if defined(VK_API_VERSION_1_2)
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_11(
VkPhysicalDeviceVulkan11Features const& features_11) {
criteria.required_features_11 = features_11;
return *this;
}
PhysicalDeviceSelector& PhysicalDeviceSelector::set_required_features_12(
VkPhysicalDeviceVulkan12Features const& features_12) {
criteria.required_features_12 = features_12;
return *this;
}
#endif
PhysicalDeviceSelector& PhysicalDeviceSelector::defer_surface_initialization() { PhysicalDeviceSelector& PhysicalDeviceSelector::defer_surface_initialization() {
criteria.defer_surface_initialization = true; criteria.defer_surface_initialization = true;
return *this; return *this;
@ -1327,14 +1432,7 @@ void destroy_device(Device device) {
detail::vulkan_functions().fp_vkDestroyDevice(device.device, device.allocation_callbacks); detail::vulkan_functions().fp_vkDestroyDevice(device.device, device.allocation_callbacks);
} }
DeviceBuilder::DeviceBuilder(PhysicalDevice phys_device) { DeviceBuilder::DeviceBuilder(PhysicalDevice phys_device) { physical_device = phys_device; }
info.physical_device = phys_device;
info.surface = phys_device.surface;
info.queue_families = phys_device.queue_families;
info.features = phys_device.features;
info.extensions_to_enable = phys_device.extensions_to_enable;
info.defer_surface_initialization = phys_device.defer_surface_initialization;
}
detail::Result<Device> DeviceBuilder::build() const { detail::Result<Device> DeviceBuilder::build() const {
@ -1343,7 +1441,7 @@ detail::Result<Device> DeviceBuilder::build() const {
queue_descriptions.end(), info.queue_descriptions.begin(), info.queue_descriptions.end()); queue_descriptions.end(), info.queue_descriptions.begin(), info.queue_descriptions.end());
if (queue_descriptions.size() == 0) { if (queue_descriptions.size() == 0) {
for (uint32_t i = 0; i < info.queue_families.size(); i++) { for (uint32_t i = 0; i < physical_device.queue_families.size(); i++) {
queue_descriptions.push_back(CustomQueueDescription{ i, 1, std::vector<float>{ 1.0f } }); queue_descriptions.push_back(CustomQueueDescription{ i, 1, std::vector<float>{ 1.0f } });
} }
} }
@ -1358,41 +1456,77 @@ detail::Result<Device> DeviceBuilder::build() const {
queueCreateInfos.push_back(queue_create_info); queueCreateInfos.push_back(queue_create_info);
} }
std::vector<const char*> extensions = info.extensions_to_enable; std::vector<const char*> extensions = physical_device.extensions_to_enable;
if (info.surface != VK_NULL_HANDLE || info.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 });
// VUID-VkDeviceCreateInfo-pNext-00373 - don't add pEnabledFeatures if the phys_dev_features_2 is present std::vector<VkBaseOutStructure*> pNext_chain = info.pNext_chain;
// check if certain structs were added in the pNext chain by the user
bool has_phys_dev_features_2 = false; bool has_phys_dev_features_2 = false;
for (auto& pNext_struct : info.pNext_chain) { 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) { if (pNext_struct->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2) {
has_phys_dev_features_2 = true; 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)
VkPhysicalDeviceFeatures2 local_features2{};
if (physical_device.instance_version >= VK_MAKE_VERSION(1, 1, 0) && !has_phys_dev_features_2) {
local_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
local_features2.features = physical_device.features;
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features2));
has_phys_dev_features_2 = true;
}
#if defined(VK_API_VERSION_1_2)
VkPhysicalDeviceVulkan11Features local_features_11 = physical_device.features_11;
VkPhysicalDeviceVulkan12Features local_features_12 = physical_device.features_12;
if (physical_device.instance_version >= VK_MAKE_VERSION(1, 2, 0)) {
if (!has_phys_dev_vulkan_features_11) {
pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(&local_features_11));
has_phys_dev_vulkan_features_11 = 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
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, info.pNext_chain); 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
if (!has_phys_dev_features_2) { if (!has_phys_dev_features_2) {
device_create_info.pEnabledFeatures = &info.features; device_create_info.pEnabledFeatures = &physical_device.features;
} }
Device device; Device device;
VkResult res = detail::vulkan_functions().fp_vkCreateDevice(info.physical_device.physical_device, VkResult res = detail::vulkan_functions().fp_vkCreateDevice(
&device_create_info, physical_device.physical_device, &device_create_info, info.allocation_callbacks, &device.device);
info.allocation_callbacks,
&device.device);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS) {
return { DeviceError::failed_create_device, res }; return { DeviceError::failed_create_device, res };
} }
device.physical_device = info.physical_device; device.physical_device = physical_device;
device.surface = info.surface; device.surface = physical_device.surface;
device.queue_families = info.queue_families; device.queue_families = physical_device.queue_families;
device.allocation_callbacks = info.allocation_callbacks; device.allocation_callbacks = info.allocation_callbacks;
return device; return device;
} }

View File

@ -335,6 +335,10 @@ 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{};
@ -352,6 +356,7 @@ struct PhysicalDevice {
std::vector<VkQueueFamilyProperties> get_queue_families() const; std::vector<VkQueueFamilyProperties> get_queue_families() const;
private: private:
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;
bool defer_surface_initialization = false; bool defer_surface_initialization = false;
@ -415,7 +420,16 @@ class PhysicalDeviceSelector {
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 the features in VkPhysicalDeviceFeatures.
PhysicalDeviceSelector& set_required_features(VkPhysicalDeviceFeatures features); PhysicalDeviceSelector& set_required_features(VkPhysicalDeviceFeatures const& features);
#if defined(VK_API_VERSION_1_2)
// 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
PhysicalDeviceSelector& set_required_features_11(VkPhysicalDeviceVulkan11Features const& features_11);
// Require a physical device which supports the features in VkPhysicalDeviceVulkan12Features.
// Must have vulkan version 1.2
PhysicalDeviceSelector& set_required_features_12(VkPhysicalDeviceVulkan12Features const& features_12);
#endif
// Used when surface creation happens after physical device selection. // Used when surface creation happens after physical device selection.
// Warning: This disables checking if the physical device supports a given surface. // Warning: This disables checking if the physical device supports a given surface.
@ -426,11 +440,12 @@ class PhysicalDeviceSelector {
PhysicalDeviceSelector& select_first_device_unconditionally(bool unconditionally = true); PhysicalDeviceSelector& select_first_device_unconditionally(bool unconditionally = true);
private: private:
struct SystemInfo { struct InstanceInfo {
VkInstance instance = VK_NULL_HANDLE; VkInstance instance = VK_NULL_HANDLE;
VkSurfaceKHR surface = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE;
uint32_t version = VK_MAKE_VERSION(1, 0, 0);
bool headless = false; bool headless = false;
} system_info; } instance_info;
struct PhysicalDeviceDesc { struct PhysicalDeviceDesc {
VkPhysicalDevice phys_device = VK_NULL_HANDLE; VkPhysicalDevice phys_device = VK_NULL_HANDLE;
@ -439,8 +454,15 @@ class PhysicalDeviceSelector {
VkPhysicalDeviceFeatures device_features{}; VkPhysicalDeviceFeatures device_features{};
VkPhysicalDeviceProperties device_properties{}; VkPhysicalDeviceProperties device_properties{};
VkPhysicalDeviceMemoryProperties mem_properties{}; VkPhysicalDeviceMemoryProperties mem_properties{};
#if defined(VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 device_features2{};
#endif
#if defined(VK_API_VERSION_1_2)
VkPhysicalDeviceVulkan11Features device_features_11{};
VkPhysicalDeviceVulkan12Features device_features_12{};
#endif
}; };
PhysicalDeviceDesc populate_device_details(VkPhysicalDevice phys_device) const; PhysicalDeviceDesc populate_device_details(uint32_t instance_version, VkPhysicalDevice phys_device) const;
struct SelectionCriteria { struct SelectionCriteria {
PreferredDeviceType preferred_type = PreferredDeviceType::discrete; PreferredDeviceType preferred_type = PreferredDeviceType::discrete;
@ -460,6 +482,14 @@ class PhysicalDeviceSelector {
uint32_t desired_version = VK_MAKE_VERSION(1, 0, 0); uint32_t desired_version = VK_MAKE_VERSION(1, 0, 0);
VkPhysicalDeviceFeatures required_features{}; VkPhysicalDeviceFeatures required_features{};
#if defined(VK_API_VERSION_1_1)
VkPhysicalDeviceFeatures2 required_features2{};
#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;
@ -528,15 +558,11 @@ class DeviceBuilder {
DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks); DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
private: private:
PhysicalDevice physical_device;
struct DeviceInfo { struct DeviceInfo {
VkDeviceCreateFlags flags = 0; VkDeviceCreateFlags flags = 0;
std::vector<VkBaseOutStructure*> pNext_chain; std::vector<VkBaseOutStructure*> pNext_chain;
PhysicalDevice physical_device;
VkSurfaceKHR surface = VK_NULL_HANDLE;
bool defer_surface_initialization = false;
std::vector<VkQueueFamilyProperties> queue_families;
VkPhysicalDeviceFeatures features{};
std::vector<const char*> extensions_to_enable;
std::vector<CustomQueueDescription> queue_descriptions; std::vector<CustomQueueDescription> queue_descriptions;
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
} info; } info;

View File

@ -5,408 +5,450 @@
// TODO // TODO
// changing present modes and/or image formats // changing present modes and/or image formats
void destroy_surface (vkb::detail::Result<vkb::Instance> instance_ret, VkSurfaceKHR surface) { void destroy_surface(vkb::detail::Result<vkb::Instance> instance_ret, VkSurfaceKHR surface) {
PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR> ( PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR>(
instance_ret->fp_vkGetInstanceProcAddr (instance_ret->instance, "vkDestroySurfaceKHR")); instance_ret->fp_vkGetInstanceProcAddr(instance_ret->instance, "vkDestroySurfaceKHR"));
fp_vkDestroySurfaceKHR (instance_ret->instance, surface, nullptr); fp_vkDestroySurfaceKHR(instance_ret->instance, surface, nullptr);
} }
TEST_CASE ("Instance with surface", "[VkBootstrap.bootstrap]") { TEST_CASE("Instance with surface", "[VkBootstrap.bootstrap]") {
GIVEN ("A window and a vulkan instance") { GIVEN("A window and a vulkan instance") {
auto window = create_window_glfw ("Instance with surface"); auto window = create_window_glfw("Instance with surface");
auto sys_info_ret = vkb::SystemInfo::get_system_info (); auto sys_info_ret = vkb::SystemInfo::get_system_info();
REQUIRE (sys_info_ret); REQUIRE(sys_info_ret);
vkb::InstanceBuilder instance_builder; vkb::InstanceBuilder instance_builder;
auto instance_ret = instance_builder.use_default_debug_messenger ().build (); auto instance_ret = instance_builder.use_default_debug_messenger().build();
REQUIRE (instance_ret); REQUIRE(instance_ret);
vkb::Instance instance = instance_ret.value (); vkb::Instance instance = instance_ret.value();
auto surface = create_surface_glfw (instance.instance, window); auto surface = create_surface_glfw(instance.instance, window);
GIVEN ("A default selected physical device") { GIVEN("A default selected physical device") {
vkb::PhysicalDeviceSelector phys_device_selector (instance); vkb::PhysicalDeviceSelector phys_device_selector(instance);
auto phys_device_ret = phys_device_selector.set_surface (surface).select (); auto phys_device_ret = phys_device_selector.set_surface(surface).select();
REQUIRE (phys_device_ret); REQUIRE(phys_device_ret);
vkb::PhysicalDevice physical_device = phys_device_ret.value (); vkb::PhysicalDevice physical_device = phys_device_ret.value();
GIVEN ("A device created with default parameters") { GIVEN("A device created with default parameters") {
vkb::DeviceBuilder device_builder (physical_device); vkb::DeviceBuilder device_builder(physical_device);
auto device_ret = device_builder.build (); auto device_ret = device_builder.build();
REQUIRE (device_ret); REQUIRE(device_ret);
vkb::Device device = device_ret.value (); vkb::Device device = device_ret.value();
// possible swapchain creation... // possible swapchain creation...
vkb::destroy_device (device); vkb::destroy_device(device);
} }
} }
THEN ("Can select physical device with customized requirements") { THEN("Can select physical device with customized requirements") {
vkb::PhysicalDeviceSelector selector (instance); vkb::PhysicalDeviceSelector selector(instance);
auto phys_dev_ret = selector.set_surface (surface) auto phys_dev_ret = selector.set_surface(surface)
.add_desired_extension (VK_KHR_MULTIVIEW_EXTENSION_NAME) .add_desired_extension(VK_KHR_MULTIVIEW_EXTENSION_NAME)
.add_required_extension (VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) .add_required_extension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)
.set_minimum_version (1, 0) .set_minimum_version(1, 0)
.set_desired_version (1, 1) .set_desired_version(1, 1)
.select (); .select();
REQUIRE (phys_dev_ret.has_value ()); REQUIRE(phys_dev_ret.has_value());
} }
destroy_surface (instance_ret, surface); destroy_surface(instance_ret, surface);
vkb::destroy_instance (instance); vkb::destroy_instance(instance);
destroy_window_glfw (window); destroy_window_glfw(window);
} }
} }
TEST_CASE ("instance configuration", "[VkBootstrap.bootstrap]") { TEST_CASE("instance configuration", "[VkBootstrap.bootstrap]") {
SECTION ("custom debug callback") { SECTION("custom debug callback") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = auto instance_ret =
builder.request_validation_layers () builder.request_validation_layers()
.set_app_name ("test app") .set_app_name("test app")
.set_app_version (1, 0, 0) .set_app_version(1, 0, 0)
.set_engine_name ("engine_name") .set_engine_name("engine_name")
.set_engine_version (9, 9, 9) .set_engine_version(9, 9, 9)
.set_debug_callback ([] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, .set_debug_callback([](VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType, VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void * void*
/*pUserData*/) -> VkBool32 { /*pUserData*/) -> VkBool32 {
auto ms = vkb::to_string_message_severity (messageSeverity); auto ms = vkb::to_string_message_severity(messageSeverity);
auto mt = vkb::to_string_message_type (messageType); auto mt = vkb::to_string_message_type(messageType);
printf ("[%s: %s](user defined)\n%s\n", ms, mt, pCallbackData->pMessage); printf("[%s: %s](user defined)\n%s\n", ms, mt, pCallbackData->pMessage);
return VK_FALSE; return VK_FALSE;
}) })
.build (); .build();
REQUIRE (instance_ret.has_value ()); REQUIRE(instance_ret.has_value());
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance(instance_ret.value());
} }
SECTION ("Validation configuration") { SECTION("Validation configuration") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = auto instance_ret =
builder.request_validation_layers () builder.request_validation_layers()
.require_api_version (1, 0, 34) .require_api_version(1, 0, 34)
.use_default_debug_messenger () .use_default_debug_messenger()
.add_validation_feature_enable (VkValidationFeatureEnableEXT::VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT) .add_validation_feature_enable(VkValidationFeatureEnableEXT::VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT)
.add_validation_feature_disable ( .add_validation_feature_disable(
VkValidationFeatureDisableEXT::VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT) VkValidationFeatureDisableEXT::VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT)
.add_validation_disable (VkValidationCheckEXT::VK_VALIDATION_CHECK_SHADERS_EXT) .add_validation_disable(VkValidationCheckEXT::VK_VALIDATION_CHECK_SHADERS_EXT)
.build (); .build();
REQUIRE (instance_ret.has_value ()); REQUIRE(instance_ret.has_value());
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance(instance_ret.value());
} }
} }
TEST_CASE ("Headless Vulkan", "[VkBootstrap.bootstrap]") { TEST_CASE("Headless Vulkan", "[VkBootstrap.bootstrap]") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = builder.request_validation_layers ().set_headless ().build (); auto instance_ret = builder.request_validation_layers().set_headless().build();
REQUIRE (instance_ret.has_value ()); REQUIRE(instance_ret.has_value());
vkb::PhysicalDeviceSelector phys_device_selector (instance_ret.value ()); vkb::PhysicalDeviceSelector phys_device_selector(instance_ret.value());
auto phys_device_ret = phys_device_selector.select (); auto phys_device_ret = phys_device_selector.select();
REQUIRE (phys_device_ret.has_value ()); REQUIRE(phys_device_ret.has_value());
auto phys_device = phys_device_ret.value (); auto phys_device = phys_device_ret.value();
vkb::DeviceBuilder device_builder (phys_device); vkb::DeviceBuilder device_builder(phys_device);
auto device_ret = device_builder.build (); auto device_ret = device_builder.build();
REQUIRE (device_ret.has_value ()); REQUIRE(device_ret.has_value());
vkb::destroy_device (device_ret.value ()); vkb::destroy_device(device_ret.value());
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance(instance_ret.value());
} }
TEST_CASE ("Device Configuration", "[VkBootstrap.bootstrap]") { TEST_CASE("Device Configuration", "[VkBootstrap.bootstrap]") {
auto window = create_window_glfw ("Device Configuration"); auto window = create_window_glfw("Device Configuration");
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = builder.request_validation_layers ().require_api_version (1, 1).build (); auto instance_ret = builder.request_validation_layers().require_api_version(1, 1).build();
REQUIRE (instance_ret.has_value ()); REQUIRE(instance_ret.has_value());
auto surface = create_surface_glfw (instance_ret.value ().instance, window); auto surface = create_surface_glfw(instance_ret.value().instance, window);
vkb::PhysicalDeviceSelector phys_device_selector (instance_ret.value ()); vkb::PhysicalDeviceSelector phys_device_selector(instance_ret.value());
auto phys_device_ret = phys_device_selector.set_minimum_version (1, 1).set_surface (surface).select (); auto phys_device_ret = phys_device_selector.set_minimum_version(1, 1).set_surface(surface).select();
REQUIRE (phys_device_ret.has_value ()); REQUIRE(phys_device_ret.has_value());
auto phys_device = phys_device_ret.value (); auto phys_device = phys_device_ret.value();
SECTION ("Custom queue setup") { SECTION("Custom queue setup") {
std::vector<vkb::CustomQueueDescription> queue_descriptions; std::vector<vkb::CustomQueueDescription> queue_descriptions;
auto queue_families = phys_device.get_queue_families (); auto queue_families = phys_device.get_queue_families();
for (uint32_t i = 0; i < (uint32_t)queue_families.size (); i++) { for (uint32_t i = 0; i < (uint32_t)queue_families.size(); i++) {
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
queue_descriptions.push_back (vkb::CustomQueueDescription ( queue_descriptions.push_back(vkb::CustomQueueDescription(
i, queue_families[i].queueCount, std::vector<float> (queue_families[i].queueCount, 1.0f))); i, queue_families[i].queueCount, std::vector<float>(queue_families[i].queueCount, 1.0f)));
} }
} }
if (phys_device.has_dedicated_compute_queue ()) { if (phys_device.has_dedicated_compute_queue()) {
for (uint32_t i = 0; i < (uint32_t)queue_families.size (); i++) { for (uint32_t i = 0; i < (uint32_t)queue_families.size(); i++) {
if ((queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) && if ((queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 &&
(queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0) (queue_families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0)
queue_descriptions.push_back (vkb::CustomQueueDescription (i, queue_descriptions.push_back(vkb::CustomQueueDescription(i,
queue_families[i].queueCount, queue_families[i].queueCount,
std::vector<float> (queue_families[i].queueCount, 1.0f))); std::vector<float>(queue_families[i].queueCount, 1.0f)));
} }
} else if (phys_device.has_separate_compute_queue ()) { } else if (phys_device.has_separate_compute_queue()) {
for (uint32_t i = 0; i < (uint32_t)queue_families.size (); i++) { for (uint32_t i = 0; i < (uint32_t)queue_families.size(); i++) {
if ((queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) && if ((queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) &&
((queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) { ((queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
queue_descriptions.push_back (vkb::CustomQueueDescription (i, queue_descriptions.push_back(vkb::CustomQueueDescription(i,
queue_families[i].queueCount, queue_families[i].queueCount,
std::vector<float> (queue_families[i].queueCount, 1.0f))); std::vector<float>(queue_families[i].queueCount, 1.0f)));
} }
} }
} }
vkb::DeviceBuilder device_builder (phys_device); vkb::DeviceBuilder device_builder(phys_device);
auto device_ret = device_builder.custom_queue_setup (queue_descriptions).build (); auto device_ret = device_builder.custom_queue_setup(queue_descriptions).build();
REQUIRE (device_ret.has_value ()); REQUIRE(device_ret.has_value());
vkb::destroy_device (device_ret.value ()); vkb::destroy_device(device_ret.value());
} }
SECTION ("VkPhysicalDeviceFeatures2 in pNext Chain") { SECTION("VkPhysicalDeviceFeatures2 in pNext Chain") {
VkPhysicalDeviceShaderDrawParameterFeatures shader_draw_features{}; VkPhysicalDeviceShaderDrawParameterFeatures shader_draw_features{};
shader_draw_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES; shader_draw_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
vkb::DeviceBuilder device_builder (phys_device_ret.value ()); vkb::DeviceBuilder device_builder(phys_device_ret.value());
auto device_ret = device_builder.add_pNext (&shader_draw_features).build (); auto device_ret = device_builder.add_pNext(&shader_draw_features).build();
REQUIRE (device_ret.has_value ()); REQUIRE(device_ret.has_value());
vkb::destroy_device (device_ret.value ()); vkb::destroy_device(device_ret.value());
} }
destroy_surface (instance_ret, surface); destroy_surface(instance_ret, surface);
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance(instance_ret.value());
} }
TEST_CASE ("Swapchain", "[VkBootstrap.bootstrap]") { TEST_CASE("Swapchain", "[VkBootstrap.bootstrap]") {
GIVEN ("A working instance, window, surface, and device") { GIVEN("A working instance, window, surface, and device") {
auto window = create_window_glfw ("Swapchain"); auto window = create_window_glfw("Swapchain");
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = builder.request_validation_layers ().build (); auto instance_ret = builder.request_validation_layers().build();
REQUIRE (instance_ret.has_value ()); REQUIRE(instance_ret.has_value());
auto surface = create_surface_glfw (instance_ret.value ().instance, window); auto surface = create_surface_glfw(instance_ret.value().instance, window);
vkb::PhysicalDeviceSelector phys_device_selector (instance_ret.value ()); vkb::PhysicalDeviceSelector phys_device_selector(instance_ret.value());
auto phys_device_ret = phys_device_selector.set_surface (surface).select (); auto phys_device_ret = phys_device_selector.set_surface(surface).select();
REQUIRE (phys_device_ret.has_value ()); REQUIRE(phys_device_ret.has_value());
auto phys_device = phys_device_ret.value (); auto phys_device = phys_device_ret.value();
vkb::DeviceBuilder device_builder (phys_device); vkb::DeviceBuilder device_builder(phys_device);
auto device_ret = device_builder.build (); auto device_ret = device_builder.build();
REQUIRE (device_ret.has_value ()); REQUIRE(device_ret.has_value());
vkb::Device device = device_ret.value (); vkb::Device device = device_ret.value();
auto graphics_queue_index = device.get_queue_index (vkb::QueueType::graphics).value (); auto graphics_queue_index = device.get_queue_index(vkb::QueueType::graphics).value();
auto present_queue_index = device.get_queue_index (vkb::QueueType::present).value (); auto present_queue_index = device.get_queue_index(vkb::QueueType::present).value();
THEN ("Swapchain can be made") { THEN("Swapchain can be made") {
vkb::SwapchainBuilder swapchain_builder (device); vkb::SwapchainBuilder swapchain_builder(device);
auto swapchain_ret = swapchain_builder.build (); auto swapchain_ret = swapchain_builder.build();
REQUIRE (swapchain_ret.has_value ()); REQUIRE(swapchain_ret.has_value());
auto swapchain = swapchain_ret.value (); auto swapchain = swapchain_ret.value();
THEN ("Acquire swapchain images and views") { THEN("Acquire swapchain images and views") {
auto images = swapchain.get_images (); auto images = swapchain.get_images();
REQUIRE (images.has_value ()); REQUIRE(images.has_value());
REQUIRE (images.value ().size () > 0); REQUIRE(images.value().size() > 0);
auto image_views = swapchain.get_image_views (); auto image_views = swapchain.get_image_views();
REQUIRE (image_views.has_value ()); REQUIRE(image_views.has_value());
REQUIRE (image_views.value ().size () > 0); REQUIRE(image_views.value().size() > 0);
swapchain.destroy_image_views (image_views.value ()); swapchain.destroy_image_views(image_views.value());
} }
vkb::destroy_swapchain (swapchain_ret.value ()); vkb::destroy_swapchain(swapchain_ret.value());
} }
AND_THEN ("Swapchain configuration") { AND_THEN("Swapchain configuration") {
vkb::SwapchainBuilder swapchain_builder (device); vkb::SwapchainBuilder swapchain_builder(device);
auto swapchain_ret = auto swapchain_ret =
swapchain_builder.set_desired_extent (256, 256) swapchain_builder.set_desired_extent(256, 256)
.set_desired_format ({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }) .set_desired_format({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR })
.set_desired_present_mode (VK_PRESENT_MODE_IMMEDIATE_KHR) .set_desired_present_mode(VK_PRESENT_MODE_IMMEDIATE_KHR)
.set_pre_transform_flags (VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) .set_pre_transform_flags(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
.set_composite_alpha_flags (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) .set_composite_alpha_flags(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
.set_clipped (false) .set_clipped(false)
.set_image_array_layer_count (1) .set_image_array_layer_count(1)
.build (); .build();
REQUIRE (swapchain_ret.has_value ()); REQUIRE(swapchain_ret.has_value());
vkb::destroy_swapchain (swapchain_ret.value ()); vkb::destroy_swapchain(swapchain_ret.value());
} }
AND_THEN ("Swapchain defaults can be used") { AND_THEN("Swapchain defaults can be used") {
vkb::SwapchainBuilder swapchain_builder (device); vkb::SwapchainBuilder swapchain_builder(device);
auto swapchain_ret = swapchain_builder.use_default_format_selection () auto swapchain_ret = swapchain_builder.use_default_format_selection()
.use_default_present_mode_selection () .use_default_present_mode_selection()
.use_default_image_usage_flags () .use_default_image_usage_flags()
.build (); .build();
REQUIRE (swapchain_ret.has_value ()); REQUIRE(swapchain_ret.has_value());
vkb::destroy_swapchain (swapchain_ret.value ()); vkb::destroy_swapchain(swapchain_ret.value());
} }
AND_THEN ("Swapchain can be recreated") { AND_THEN("Swapchain can be recreated") {
vkb::SwapchainBuilder swapchain_builder (device); vkb::SwapchainBuilder swapchain_builder(device);
auto swapchain_ret = swapchain_builder.build (); auto swapchain_ret = swapchain_builder.build();
REQUIRE (swapchain_ret.has_value ()); REQUIRE(swapchain_ret.has_value());
auto swapchain = swapchain_ret.value (); auto swapchain = swapchain_ret.value();
auto recreated_swapchain_ret = swapchain_builder.set_old_swapchain (swapchain).build (); auto recreated_swapchain_ret = swapchain_builder.set_old_swapchain(swapchain).build();
REQUIRE (recreated_swapchain_ret.has_value ()); REQUIRE(recreated_swapchain_ret.has_value());
vkb::destroy_swapchain (recreated_swapchain_ret.value ()); vkb::destroy_swapchain(recreated_swapchain_ret.value());
} }
AND_THEN ("Swapchain can be created from individual handles") { AND_THEN("Swapchain can be created from individual handles") {
vkb::SwapchainBuilder swapchain_builder ( vkb::SwapchainBuilder swapchain_builder(
device.physical_device.physical_device, device.device, surface, graphics_queue_index, present_queue_index); device.physical_device.physical_device, device.device, surface, graphics_queue_index, present_queue_index);
auto swapchain_ret = swapchain_builder.build (); auto swapchain_ret = swapchain_builder.build();
REQUIRE (swapchain_ret.has_value ()); REQUIRE(swapchain_ret.has_value());
auto swapchain = swapchain_ret.value (); auto swapchain = swapchain_ret.value();
auto recreated_swapchain_ret = swapchain_builder.set_old_swapchain (swapchain).build (); auto recreated_swapchain_ret = swapchain_builder.set_old_swapchain(swapchain).build();
REQUIRE (recreated_swapchain_ret.has_value ()); REQUIRE(recreated_swapchain_ret.has_value());
vkb::destroy_swapchain (recreated_swapchain_ret.value ()); vkb::destroy_swapchain(recreated_swapchain_ret.value());
} }
AND_THEN ("Swapchain can be create with default gotten handles") { AND_THEN("Swapchain can be create with default gotten handles") {
vkb::SwapchainBuilder swapchain_builder ( vkb::SwapchainBuilder swapchain_builder(
device.physical_device.physical_device, device.device, surface); device.physical_device.physical_device, device.device, surface);
auto swapchain_ret = swapchain_builder.build (); auto swapchain_ret = swapchain_builder.build();
REQUIRE (swapchain_ret.has_value ()); REQUIRE(swapchain_ret.has_value());
auto swapchain = swapchain_ret.value (); auto swapchain = swapchain_ret.value();
auto recreated_swapchain_ret = swapchain_builder.set_old_swapchain (swapchain).build (); auto recreated_swapchain_ret = swapchain_builder.set_old_swapchain(swapchain).build();
REQUIRE (recreated_swapchain_ret.has_value ()); REQUIRE(recreated_swapchain_ret.has_value());
vkb::destroy_swapchain (recreated_swapchain_ret.value ()); vkb::destroy_swapchain(recreated_swapchain_ret.value());
} }
vkb::destroy_device (device_ret.value ()); vkb::destroy_device(device_ret.value());
destroy_surface (instance_ret, surface); destroy_surface(instance_ret, surface);
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance(instance_ret.value());
} }
} }
void* VKAPI_PTR shim_vkAllocationFunction ( void* VKAPI_PTR shim_vkAllocationFunction(
void* /*pUserData*/, size_t size, size_t /*alignment*/, VkSystemAllocationScope /*allocationScope*/) { void* /*pUserData*/, size_t size, size_t /*alignment*/, VkSystemAllocationScope /*allocationScope*/) {
return malloc (size); return malloc(size);
} }
void* VKAPI_PTR shim_vkReallocationFunction ( void* VKAPI_PTR shim_vkReallocationFunction(
void* /*pUserData*/, void* pOriginal, size_t size, size_t /*alignment*/, VkSystemAllocationScope /*allocationScope*/) { void* /*pUserData*/, void* pOriginal, size_t size, size_t /*alignment*/, VkSystemAllocationScope /*allocationScope*/) {
return realloc (pOriginal, size); return realloc(pOriginal, size);
} }
void VKAPI_PTR shim_vkFreeFunction (void* /*pUserData*/, void* pMemory) { return free (pMemory); } void VKAPI_PTR shim_vkFreeFunction(void* /*pUserData*/, void* pMemory) { return free(pMemory); }
TEST_CASE ("Allocation Callbacks", "[VkBootstrap.bootstrap]") { TEST_CASE("Allocation Callbacks", "[VkBootstrap.bootstrap]") {
VkAllocationCallbacks allocation_callbacks{}; VkAllocationCallbacks allocation_callbacks{};
allocation_callbacks.pfnAllocation = &shim_vkAllocationFunction; allocation_callbacks.pfnAllocation = &shim_vkAllocationFunction;
allocation_callbacks.pfnReallocation = &shim_vkReallocationFunction; allocation_callbacks.pfnReallocation = &shim_vkReallocationFunction;
allocation_callbacks.pfnFree = &shim_vkFreeFunction; allocation_callbacks.pfnFree = &shim_vkFreeFunction;
auto window = create_window_glfw ("Allocation Callbacks"); auto window = create_window_glfw("Allocation Callbacks");
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto instance_ret = auto instance_ret =
builder.request_validation_layers ().set_allocation_callbacks (&allocation_callbacks).build (); builder.request_validation_layers().set_allocation_callbacks(&allocation_callbacks).build();
REQUIRE (instance_ret.has_value ()); REQUIRE(instance_ret.has_value());
auto surface = create_surface_glfw (instance_ret.value ().instance, window); auto surface = create_surface_glfw(instance_ret.value().instance, window);
vkb::PhysicalDeviceSelector phys_device_selector (instance_ret.value ()); vkb::PhysicalDeviceSelector phys_device_selector(instance_ret.value());
auto phys_device_ret = phys_device_selector.set_surface (surface).select (); auto phys_device_ret = phys_device_selector.set_surface(surface).select();
REQUIRE (phys_device_ret.has_value ()); REQUIRE(phys_device_ret.has_value());
auto phys_device = phys_device_ret.value (); auto phys_device = phys_device_ret.value();
vkb::DeviceBuilder device_builder (phys_device); vkb::DeviceBuilder device_builder(phys_device);
auto device_ret = device_builder.set_allocation_callbacks (&allocation_callbacks).build (); auto device_ret = device_builder.set_allocation_callbacks(&allocation_callbacks).build();
REQUIRE (device_ret.has_value ()); REQUIRE(device_ret.has_value());
vkb::Device device = device_ret.value (); vkb::Device device = device_ret.value();
vkb::SwapchainBuilder swapchain_builder (device); vkb::SwapchainBuilder swapchain_builder(device);
auto swapchain_ret = swapchain_builder.set_allocation_callbacks (&allocation_callbacks).build (); auto swapchain_ret = swapchain_builder.set_allocation_callbacks(&allocation_callbacks).build();
REQUIRE (swapchain_ret.has_value ()); REQUIRE(swapchain_ret.has_value());
// auto swapchain = swapchain_ret.value (); // auto swapchain = swapchain_ret.value ();
vkb::destroy_swapchain (swapchain_ret.value ()); vkb::destroy_swapchain(swapchain_ret.value());
vkb::destroy_device (device_ret.value ()); vkb::destroy_device(device_ret.value());
destroy_surface (instance_ret, surface); destroy_surface(instance_ret, surface);
vkb::destroy_instance (instance_ret.value ()); vkb::destroy_instance(instance_ret.value());
} }
TEST_CASE ("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") { TEST_CASE("SystemInfo Loading Vulkan Automatically", "[VkBootstrap.loading]") {
auto info_ret = vkb::SystemInfo::get_system_info (); auto info_ret = vkb::SystemInfo::get_system_info();
REQUIRE (info_ret); REQUIRE(info_ret);
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto ret = builder.build (); auto ret = builder.build();
REQUIRE (ret); REQUIRE(ret);
} }
TEST_CASE ("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") { TEST_CASE("SystemInfo Loading Vulkan Manually", "[VkBootstrap.loading]") {
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
REQUIRE (vk_lib.vkGetInstanceProcAddr != NULL); REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
auto info_ret = vkb::SystemInfo::get_system_info (vk_lib.vkGetInstanceProcAddr); auto info_ret = vkb::SystemInfo::get_system_info(vk_lib.vkGetInstanceProcAddr);
REQUIRE (info_ret); REQUIRE(info_ret);
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto ret = builder.build (); auto ret = builder.build();
REQUIRE (ret); REQUIRE(ret);
vk_lib.close (); vk_lib.close();
} }
TEST_CASE ("InstanceBuilder Loading Vulkan Automatically", "[VkBootstrap.loading]") { TEST_CASE("InstanceBuilder Loading Vulkan Automatically", "[VkBootstrap.loading]") {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto ret = builder.build (); auto ret = builder.build();
REQUIRE (ret); REQUIRE(ret);
} }
TEST_CASE ("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") { TEST_CASE("InstanceBuilder Loading Vulkan Manually", "[VkBootstrap.loading]") {
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
REQUIRE (vk_lib.vkGetInstanceProcAddr != NULL); REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr }; vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr };
auto ret = builder.build (); auto ret = builder.build();
vk_lib.close (); vk_lib.close();
} }
TEST_CASE ("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") { TEST_CASE("ReLoading Vulkan Automatically", "[VkBootstrap.loading]") {
{ {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto ret = builder.build (); auto ret = builder.build();
REQUIRE (ret); REQUIRE(ret);
} }
{ {
vkb::InstanceBuilder builder; vkb::InstanceBuilder builder;
auto ret = builder.build (); auto ret = builder.build();
REQUIRE (ret); REQUIRE(ret);
} }
} }
TEST_CASE ("ReLoading Vulkan Manually", "[VkBootstrap.loading]") { TEST_CASE("ReLoading Vulkan Manually", "[VkBootstrap.loading]") {
{ {
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
REQUIRE (vk_lib.vkGetInstanceProcAddr != NULL); REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr }; vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr };
auto ret = builder.build (); auto ret = builder.build();
REQUIRE (ret); REQUIRE(ret);
vk_lib.close (); vk_lib.close();
} }
{ {
VulkanLibrary vk_lib; VulkanLibrary vk_lib;
REQUIRE (vk_lib.vkGetInstanceProcAddr != NULL); REQUIRE(vk_lib.vkGetInstanceProcAddr != NULL);
vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr }; vkb::InstanceBuilder builder{ vk_lib.vkGetInstanceProcAddr };
auto ret = builder.build (); auto ret = builder.build();
REQUIRE (ret); REQUIRE(ret);
vk_lib.close (); vk_lib.close();
} }
} }
#if defined(VK_API_VERSION_1_2)
TEST_CASE("Querying Vulkan 1.1 and 1.2 features", "[VkBootstrap.version]") {
GIVEN("A working instance") {
vkb::InstanceBuilder builder;
auto instance_ret =
builder.request_validation_layers().require_api_version(1, 2).set_headless().build();
REQUIRE(instance_ret.has_value());
// Requires a device that supports multiview and bufferDeviceAddress
{
VkPhysicalDeviceVulkan11Features features_11{};
features_11.multiview = true;
VkPhysicalDeviceVulkan12Features features_12{};
features_12.bufferDeviceAddress = true;
vkb::PhysicalDeviceSelector selector(instance_ret.value());
auto phys_dev_ret =
selector.set_required_features_11(features_11).set_required_features_12(features_12).select();
// Ignore if hardware support isn't true
REQUIRE(phys_dev_ret.has_value());
vkb::DeviceBuilder device_builder(phys_dev_ret.value());
auto device_ret = device_builder.build();
REQUIRE(device_ret.has_value());
vkb::destroy_device(device_ret.value());
}
// protectedMemory should NOT be supported
{
VkPhysicalDeviceVulkan11Features features_11{};
features_11.protectedMemory = true;
vkb::PhysicalDeviceSelector selector(instance_ret.value());
auto phys_dev_ret = selector.set_required_features_11(features_11).select();
// Ignore if hardware support differs
REQUIRE(!phys_dev_ret.has_value());
}
vkb::destroy_instance(instance_ret.value());
}
}
#endif