Add VulkanFeatureConfig, mechanism to select pre-made configs

This makes it easy to enable a set of features, extensions, and a Vulkan Version that are
pre-defined.
This commit is contained in:
Charles Giessen 2021-05-27 10:05:38 -06:00
parent 8922a41bd4
commit d6d63121e9
6 changed files with 265 additions and 4 deletions

View File

@ -1227,6 +1227,15 @@ PhysicalDeviceSelector& PhysicalDeviceSelector::allow_any_gpu_device_type(bool a
criteria.allow_any_type = allow_any_type;
return *this;
}
PhysicalDeviceSelector& PhysicalDeviceSelector::set_vulkan_feature_config(VulkanFeatureConfig& feature_config) {
set_minimum_version(feature_config.api_major_version, feature_config.api_minor_version);
require_present(feature_config.require_presentation);
add_required_extensions(feature_config.required_extensions);
set_required_features(feature_config.features_1_0);
set_required_features_11(feature_config.features_1_1);
set_required_features_12(feature_config.features_1_2);
return *this;
}
PhysicalDeviceSelector& PhysicalDeviceSelector::require_present(bool require) {
criteria.require_present = require;
return *this;

View File

@ -25,6 +25,7 @@
#include <vulkan/vulkan.h>
#include "VkBootstrapDispatch.h"
#include "VulkanFeatureConfig.h"
namespace vkb {
@ -444,6 +445,11 @@ class PhysicalDeviceSelector {
// Allow selection of a gpu device type that isn't the preferred physical device type. Defaults to true.
PhysicalDeviceSelector& allow_any_gpu_device_type(bool allow_any_type = true);
// Sets the "Vulkan Feature Config" to use when selecting a VkPhysicalDevice.
// A Feature Config is a pre defined collection of extensions, features, and properties that are
// required to be supported. For more information, go to `VulkanFeatureConfig.h`
PhysicalDeviceSelector& set_vulkan_feature_config(VulkanFeatureConfig& feature_config);
// Require that a physical device supports presentation. Defaults to true.
PhysicalDeviceSelector& require_present(bool require = true);

205
src/VulkanFeatureConfig.h Normal file
View File

@ -0,0 +1,205 @@
#pragma once
#include <vulkan/vulkan.h>
/*
The VulkanFeatureConfig mechanism of vk-bootstrap provides an easy way to select a VkPhysicalDevice based off of list of pre-made
configurations that specify the required version, features, extensions, and properties.
*/
namespace vkb {
namespace detail {
struct StructureWrapper {
template <typename T> StructureWrapper(T const& structure) noexcept {
T* ptr = new T();
*ptr = structure;
pStructure = reinterpret_cast<VkBaseOutStructure*>(ptr);
}
~StructureWrapper() noexcept { delete pStructure; }
StructureWrapper(StructureWrapper const&) = delete;
StructureWrapper& operator=(StructureWrapper const&) = delete;
StructureWrapper(StructureWrapper&& other) noexcept : pStructure(other.pStructure) {
other.pStructure = nullptr;
}
StructureWrapper& operator=(StructureWrapper&& other) noexcept {
delete pStructure;
pStructure = other.pStructure;
other.pStructure = nullptr;
return *this;
}
VkBaseOutStructure* pStructure = nullptr;
};
inline VkPhysicalDeviceFeatures get_common_1_0_features() {
VkPhysicalDeviceFeatures features{};
features.fullDrawIndexUint32 = true;
features.imageCubeArray = true;
features.independentBlend = true;
features.geometryShader = true;
features.tessellationShader = true;
features.sampleRateShading = true;
features.dualSrcBlend = true;
features.logicOp = true;
features.multiDrawIndirect = true;
features.drawIndirectFirstInstance = true;
features.depthClamp = true;
features.depthBiasClamp = true;
features.fillModeNonSolid = true;
features.wideLines = true;
features.largePoints = true;
features.multiViewport = true;
features.samplerAnisotropy = true;
features.pipelineStatisticsQuery = true;
features.textureCompressionBC = true;
features.occlusionQueryPrecise = true;
features.vertexPipelineStoresAndAtomics = true;
features.fragmentStoresAndAtomics = true;
features.shaderTessellationAndGeometryPointSize = true;
features.shaderImageGatherExtended = true;
features.shaderStorageImageExtendedFormats = true;
features.shaderStorageImageWriteWithoutFormat = true;
features.shaderUniformBufferArrayDynamicIndexing = true;
features.shaderSampledImageArrayDynamicIndexing = true;
features.shaderStorageBufferArrayDynamicIndexing = true;
features.shaderStorageImageArrayDynamicIndexing = true;
features.shaderClipDistance = true;
features.shaderCullDistance = true;
features.variableMultisampleRate = true;
return features;
}
inline VkPhysicalDeviceVulkan11Features get_common_1_1_features() {
VkPhysicalDeviceVulkan11Features features;
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
features.storageBuffer16BitAccess = true;
features.uniformAndStorageBuffer16BitAccess = true;
features.multiview = true;
features.multiviewTessellationShader = true;
features.variablePointersStorageBuffer = true;
features.variablePointers = true;
features.shaderDrawParameters = true;
return features;
}
inline VkPhysicalDeviceVulkan12Features get_common_1_2_features() {
VkPhysicalDeviceVulkan12Features features{};
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
features.samplerMirrorClampToEdge = true;
features.drawIndirectCount = true;
features.descriptorIndexing = true;
features.scalarBlockLayout = true;
features.imagelessFramebuffer = true;
features.uniformBufferStandardLayout = true;
features.shaderSubgroupExtendedTypes = true;
features.separateDepthStencilLayouts = true;
features.hostQueryReset = true;
features.timelineSemaphore = true;
features.bufferDeviceAddress = true;
features.subgroupBroadcastDynamicId = true;
return features;
}
} // namespace detail
/*
Stores all the possible versions, features, extensions, and properties for a VulkanFeatureConfig
*/
struct VulkanFeatureConfig {
VulkanFeatureConfig() {
features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
}
uint32_t api_major_version = 1;
uint32_t api_minor_version = 0;
bool require_presentation = true;
std::vector<const char*> required_extensions;
VkPhysicalDeviceFeatures features_1_0{};
VkPhysicalDeviceVulkan11Features features_1_1{};
VkPhysicalDeviceVulkan12Features features_1_2{};
VkPhysicalDeviceProperties properties_1_0{};
};
/*
Configuration for commonly available features in Vulkan 1.0 devices
*/
static VulkanFeatureConfig& get_feature_config_vulkan_1_0_desktop() {
static VulkanFeatureConfig config{};
config.features_1_0 = detail::get_common_1_0_features();
return config;
}
/*
Configuration for commonly available features in Vulkan 1.1 devices
*/
static VulkanFeatureConfig& get_feature_config_vulkan_1_1_desktop() {
static VulkanFeatureConfig config{};
config.api_minor_version = 1;
config.features_1_0 = detail::get_common_1_0_features();
config.features_1_1 = detail::get_common_1_1_features();
return config;
}
/*
Configuration for commonly available features in Vulkan 1.2 devices
*/
static VulkanFeatureConfig& get_feature_config_vulkan_1_2_desktop() {
static VulkanFeatureConfig config{};
config.api_minor_version = 2;
config.features_1_0 = detail::get_common_1_0_features();
config.features_1_1 = detail::get_common_1_1_features();
config.features_1_2 = detail::get_common_1_2_features();
return config;
}
/*
Configuration that requests features available only found in the most recent hardware
*/
static VulkanFeatureConfig& get_feature_config_bleeding_edge_desktop() {
static VulkanFeatureConfig config{};
config.api_minor_version = 2;
config.required_extensions.push_back("VK_KHR_deferred_host_operations");
config.required_extensions.push_back("VK_KHR_acceleration_structure");
config.required_extensions.push_back("VK_KHR_ray_query");
config.required_extensions.push_back("VK_KHR_pipeline_library");
config.required_extensions.push_back("VK_KHR_ray_tracing_pipeline");
config.required_extensions.push_back("VK_KHR_fragment_shading_rate");
config.features_1_0 = detail::get_common_1_0_features();
config.features_1_1 = detail::get_common_1_1_features();
config.features_1_2 = detail::get_common_1_2_features();
return config;
}
static VulkanFeatureConfig& get_feature_config_vulkan_1_0_mobile() {
static VulkanFeatureConfig config{};
return config;
}
static VulkanFeatureConfig& get_feature_config_vulkan_1_1_mobile() {
static VulkanFeatureConfig config{};
config.api_minor_version = 1;
return config;
}
static VulkanFeatureConfig& get_feature_config_vulkan_1_2_mobile() {
static VulkanFeatureConfig config{};
config.api_minor_version = 2;
return config;
}
static VulkanFeatureConfig& get_feature_config_virtual_reality_base() {
static VulkanFeatureConfig config{};
config.api_minor_version = 1;
config.features_1_0 = detail::get_common_1_0_features();
config.features_1_1 = detail::get_common_1_1_features();
return config;
}
} // namespace vkb

View File

@ -1,4 +1,4 @@
add_executable(vk-bootstrap-test main.cpp bootstrap_tests.cpp error_code_tests.cpp unit_tests.cpp)
add_executable(vk-bootstrap-test main.cpp bootstrap_tests.cpp error_code_tests.cpp unit_tests.cpp feature_config.cpp)
target_link_libraries(vk-bootstrap-test
PRIVATE
vk-bootstrap

View File

@ -20,18 +20,18 @@
#include "../src/VkBootstrap.h"
GLFWwindow* create_window_glfw(const char* window_name = "", bool resize = true) {
inline GLFWwindow* create_window_glfw(const char* window_name = "", bool resize = true) {
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
if (!resize) glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
return glfwCreateWindow(1024, 1024, window_name, NULL, NULL);
}
void destroy_window_glfw(GLFWwindow* window) {
inline void destroy_window_glfw(GLFWwindow* window) {
glfwDestroyWindow(window);
glfwTerminate();
}
VkSurfaceKHR create_surface_glfw(
inline VkSurfaceKHR create_surface_glfw(
VkInstance instance, GLFWwindow* window, VkAllocationCallbacks* allocator = nullptr) {
VkSurfaceKHR surface = VK_NULL_HANDLE;
VkResult err = glfwCreateWindowSurface(instance, window, allocator, &surface);
@ -48,6 +48,12 @@ VkSurfaceKHR create_surface_glfw(
return surface;
}
inline void destroy_surface(vkb::Instance& instance_ret, VkSurfaceKHR surface) {
PFN_vkDestroySurfaceKHR fp_vkDestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR>(
instance_ret.fp_vkGetInstanceProcAddr(instance_ret.instance, "vkDestroySurfaceKHR"));
fp_vkDestroySurfaceKHR(instance_ret.instance, surface, nullptr);
}
struct VulkanLibrary {
#if defined(__linux__) || defined(__APPLE__)
void* library;

35
tests/feature_config.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "common.h"
#include <catch2/catch.hpp>
TEST_CASE("TargetBaseVulkanDesktop", "[VkBootstrap.feature_config]") {
auto window = create_window_glfw("Instance with surface");
vkb::InstanceBuilder instance_builder;
auto instance_ret = instance_builder.use_default_debug_messenger().request_validation_layers().build();
REQUIRE(instance_ret);
vkb::Instance instance = instance_ret.value();
auto surface = create_surface_glfw(instance.instance, window);
GIVEN("A window and a vulkan instance") {
vkb::PhysicalDeviceSelector selector(instance);
auto phys_dev_ret = selector.set_surface(surface)
.set_vulkan_feature_config(vkb::get_feature_config_vulkan_1_0_desktop())
.select();
REQUIRE(phys_dev_ret);
GIVEN("A physical device created with the TargetBaseVulkanDesktop") {
vkb::DeviceBuilder device_builder(phys_dev_ret.value());
auto device_ret = device_builder.build();
REQUIRE(device_ret);
vkb::Device device = device_ret.value();
// possible swapchain creation...
vkb::destroy_device(device);
}
}
destroy_surface(*instance_ret, surface);
vkb::destroy_instance(instance);
destroy_window_glfw(window);
}