Skip to content

Commit

Permalink
Refactor getting/adding extension features to create a VkDevice with. (
Browse files Browse the repository at this point in the history
…KhronosGroup#1013)

* Refactor getting/adding extension features to create a VkDevice with.

* Add functions and macros to simplify setting feature flags.

* Rebasing and adjustments to latest changes

* Adjusted function request_gpu_features in samples async_compute and multithreading_render_passes.

* Adjusted feature requesting in samples dynamic_rendering_local_read and host_image_copy.
  • Loading branch information
asuessenbach authored Sep 23, 2024
1 parent 4c911f7 commit 5daac4d
Show file tree
Hide file tree
Showing 45 changed files with 500 additions and 345 deletions.
10 changes: 8 additions & 2 deletions framework/core/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,17 @@ Device::Device(PhysicalDevice &gpu,
if (is_extension_supported("VK_KHR_performance_query") &&
is_extension_supported("VK_EXT_host_query_reset"))
{
auto perf_counter_features = gpu.request_extension_features<VkPhysicalDevicePerformanceQueryFeaturesKHR>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR);
auto host_query_reset_features = gpu.request_extension_features<VkPhysicalDeviceHostQueryResetFeatures>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES);
auto perf_counter_features =
gpu.get_extension_features<VkPhysicalDevicePerformanceQueryFeaturesKHR>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR);
auto host_query_reset_features =
gpu.get_extension_features<VkPhysicalDeviceHostQueryResetFeatures>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES);

if (perf_counter_features.performanceCounterQueryPools && host_query_reset_features.hostQueryReset)
{
gpu.add_extension_features<VkPhysicalDevicePerformanceQueryFeaturesKHR>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR)
.performanceCounterQueryPools = VK_TRUE;
gpu.add_extension_features<VkPhysicalDeviceHostQueryResetFeatures>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES).hostQueryReset =
VK_TRUE;
enabled_extensions.push_back("VK_KHR_performance_query");
enabled_extensions.push_back("VK_EXT_host_query_reset");
LOGI("Performance query enabled");
Expand Down
6 changes: 4 additions & 2 deletions framework/core/hpp_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,13 @@ HPPDevice::HPPDevice(vkb::core::HPPPhysicalDevice &gpu,
// live in the same command buffer as beginQuery
if (is_extension_supported(VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME) && is_extension_supported(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME))
{
auto perf_counter_features = gpu.request_extension_features<vk::PhysicalDevicePerformanceQueryFeaturesKHR>();
auto host_query_reset_features = gpu.request_extension_features<vk::PhysicalDeviceHostQueryResetFeatures>();
auto perf_counter_features = gpu.get_extension_features<vk::PhysicalDevicePerformanceQueryFeaturesKHR>();
auto host_query_reset_features = gpu.get_extension_features<vk::PhysicalDeviceHostQueryResetFeatures>();

if (perf_counter_features.performanceCounterQueryPools && host_query_reset_features.hostQueryReset)
{
gpu.add_extension_features<vk::PhysicalDevicePerformanceQueryFeaturesKHR>().performanceCounterQueryPools = true;
gpu.add_extension_features<vk::PhysicalDeviceHostQueryResetFeatures>().hostQueryReset = true;
enabled_extensions.push_back(VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME);
enabled_extensions.push_back(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME);
LOGI("Performance query enabled");
Expand Down
102 changes: 79 additions & 23 deletions framework/core/hpp_physical_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,29 @@ class HPPPhysicalDevice
vk::PhysicalDeviceFeatures &get_mutable_requested_features();

/**
* @brief Requests a third party extension to be used by the framework
* @brief Get an extension features struct
*
* Gets the actual extension features struct with the supported flags set.
* The flags you're interested in can be set in a corresponding struct in the structure chain
* by calling PhysicalDevice::add_extension_features()
* @returns The extension feature struct
*/
template <typename HPPStructureType>
HPPStructureType get_extension_features()
{
// We cannot request extension features if the physical device properties 2 instance extension isn't enabled
if (!instance.is_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
{
throw std::runtime_error("Couldn't request feature from device as " + std::string(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) +
" isn't enabled!");
}

// Get the extension feature
return handle.getFeatures2KHR<vk::PhysicalDeviceFeatures2KHR, HPPStructureType>().template get<HPPStructureType>();
}

/**
* @brief Add an extension features struct to the structure chain used for device creation
*
* To have the features enabled, this function must be called before the logical device
* is created. To do this request sample specific features inside
Expand All @@ -100,43 +122,73 @@ class HPPPhysicalDevice
* If the feature extension requires you to ask for certain features to be enabled, you can
* modify the struct returned by this function, it will propagate the changes to the logical
* device.
* @returns The extension feature struct
* @returns A reference to the extension feature struct in the structure chain
*/
template <typename HPPStructureType>
HPPStructureType &request_extension_features()
HPPStructureType &add_extension_features()
{
// We cannot request extension features if the physical device properties 2 instance extension isn't enabled
if (!instance.is_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
{
throw std::runtime_error("Couldn't request feature from device as " + std::string(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) + " isn't enabled!");
throw std::runtime_error("Couldn't request feature from device as " + std::string(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) +
" isn't enabled!");
}

// If the type already exists in the map, return a casted pointer to get the extension feature struct
vk::StructureType structureType = HPPStructureType::structureType; // need to instantiate this value to be usable in find()!
auto extension_features_it = extension_features.find(structureType);
if (extension_features_it != extension_features.end())
// Add an (empty) extension features into the map of extension features
auto [it, added] = extension_features.insert({HPPStructureType::structureType, std::make_shared<HPPStructureType>()});
if (added)
{
return *static_cast<HPPStructureType *>(extension_features_it->second.get());
// if it was actually added, also add it to the structure chain
if (last_requested_extension_feature)
{
static_cast<HPPStructureType *>(it->second.get())->pNext = last_requested_extension_feature;
}
last_requested_extension_feature = it->second.get();
}

// Get the extension feature
vk::StructureChain<vk::PhysicalDeviceFeatures2KHR, HPPStructureType> featureChain = handle.getFeatures2KHR<vk::PhysicalDeviceFeatures2KHR, HPPStructureType>();

// Insert the extension feature into the extension feature map so its ownership is held
extension_features.insert({structureType, std::make_shared<HPPStructureType>(featureChain.template get<HPPStructureType>())});

// Pull out the dereferenced void pointer, we can assume its type based on the template
auto *extension_ptr = static_cast<HPPStructureType *>(extension_features.find(structureType)->second.get());
return *static_cast<HPPStructureType *>(it->second.get());
}

// If an extension feature has already been requested, we shift the linked list down by one
// Making this current extension the new base pointer
if (last_requested_extension_feature)
/**
* @brief Request an optional features flag
*
* Calls get_extension_features to get the support of the requested flag. If it's supported,
* add_extension_features is called, otherwise a log message is generated.
*
* @returns true if the requested feature is supported, otherwise false
*/
template <typename Feature>
vk::Bool32 request_optional_feature(vk::Bool32 Feature::*flag, std::string const &featureName, std::string const &flagName)
{
vk::Bool32 supported = get_extension_features<Feature>().*flag;
if (supported)
{
extension_ptr->pNext = last_requested_extension_feature;
add_extension_features<Feature>().*flag = true;
}
last_requested_extension_feature = extension_ptr;
else
{
LOGI("Requested optional feature <{}::{}> is not supported", featureName, flagName);
}
return supported;
}

return *extension_ptr;
/**
* @brief Request a required features flag
*
* Calls get_extension_features to get the support of the requested flag. If it's supported,
* add_extension_features is called, otherwise a runtime_error is thrown.
*/
template <typename Feature>
void request_required_feature(vk::Bool32 Feature::*flag, std::string const &featureName, std::string const &flagName)
{
if (get_extension_features<Feature>().*flag)
{
add_extension_features<Feature>().*flag = true;
}
else
{
throw std::runtime_error(std::string("Requested required feature <") + featureName + "::" + flagName + "> is not supported");
}
}

/**
Expand Down Expand Up @@ -192,5 +244,9 @@ class HPPPhysicalDevice

bool high_priority_graphics_queue{false};
};

#define HPP_REQUEST_OPTIONAL_FEATURE(gpu, Feature, flag) gpu.request_optional_feature<Feature>(&Feature::flag, #Feature, #flag)
#define HPP_REQUEST_REQUIRED_FEATURE(gpu, Feature, flag) gpu.request_required_feature<Feature>(&Feature::flag, #Feature, #flag)

} // namespace core
} // namespace vkb
114 changes: 87 additions & 27 deletions framework/core/physical_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ class PhysicalDevice

void enumerate_queue_family_performance_query_counters(
uint32_t queue_family_index,
uint32_t * count,
VkPerformanceCounterKHR * counters,
uint32_t *count,
VkPerformanceCounterKHR *counters,
VkPerformanceCounterDescriptionKHR *descriptions) const;

const VkPhysicalDeviceFeatures get_requested_features() const;
Expand All @@ -79,7 +79,35 @@ class PhysicalDevice
void *get_extension_feature_chain() const;

/**
* @brief Requests a third party extension to be used by the framework
* @brief Get an extension features struct
*
* Gets the actual extension features struct with the supported flags set.
* The flags you're interested in can be set in a corresponding struct in the structure chain
* by calling PhysicalDevice::add_extension_features()
* @param type The VkStructureType for the extension you are requesting
* @returns The extension feature struct
*/
template <typename T>
T get_extension_features(VkStructureType type)
{
// We cannot request extension features if the physical device properties 2 instance extension isn't enabled
if (!instance.is_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
{
throw std::runtime_error("Couldn't request feature from device as " + std::string(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) +
" isn't enabled!");
}

// Get the extension features
T features{type};
VkPhysicalDeviceFeatures2KHR physical_device_features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR};
physical_device_features.pNext = &features;
vkGetPhysicalDeviceFeatures2KHR(handle, &physical_device_features);

return features;
}

/**
* @brief Add an extension features struct to the structure chain used for device creation
*
* To have the features enabled, this function must be called before the logical device
* is created. To do this request sample specific features inside
Expand All @@ -89,45 +117,73 @@ class PhysicalDevice
* modify the struct returned by this function, it will propagate the changes to the logical
* device.
* @param type The VkStructureType for the extension you are requesting
* @returns The extension feature struct
* @returns A reference to extension feature struct in the structure chain
*/
template <typename T>
T &request_extension_features(VkStructureType type)
T &add_extension_features(VkStructureType type)
{
// We cannot request extension features if the physical device properties 2 instance extension isn't enabled
if (!instance.is_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
{
throw std::runtime_error("Couldn't request feature from device as " + std::string(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) + " isn't enabled!");
throw std::runtime_error("Couldn't request feature from device as " + std::string(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) +
" isn't enabled!");
}

// If the type already exists in the map, return a casted pointer to get the extension feature struct
auto extension_features_it = extension_features.find(type);
if (extension_features_it != extension_features.end())
// Add an (empty) extension features into the map of extension features
auto [it, added] = extension_features.insert({type, std::make_shared<T>(T{type})});
if (added)
{
return *static_cast<T *>(extension_features_it->second.get());
// if it was actually added, also add it to the structure chain
if (last_requested_extension_feature)
{
static_cast<T *>(it->second.get())->pNext = last_requested_extension_feature;
}
last_requested_extension_feature = it->second.get();
}

// Get the extension feature
VkPhysicalDeviceFeatures2KHR physical_device_features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR};
T extension{type};
physical_device_features.pNext = &extension;
vkGetPhysicalDeviceFeatures2KHR(handle, &physical_device_features);

// Insert the extension feature into the extension feature map so its ownership is held
extension_features.insert({type, std::make_shared<T>(extension)});

// Pull out the dereferenced void pointer, we can assume its type based on the template
auto *extension_ptr = static_cast<T *>(extension_features.find(type)->second.get());
return *static_cast<T *>(it->second.get());
}

// If an extension feature has already been requested, we shift the linked list down by one
// Making this current extension the new base pointer
if (last_requested_extension_feature)
/**
* @brief Request an optional features flag
*
* Calls get_extension_features to get the support of the requested flag. If it's supported,
* add_extension_features is called, otherwise a log message is generated.
*
* @returns true if the requested feature is supported, otherwise false
*/
template <typename Feature>
VkBool32 request_optional_feature(VkStructureType type, VkBool32 Feature::*flag, std::string const &featureName, std::string const &flagName)
{
VkBool32 supported = get_extension_features<Feature>(type).*flag;
if (supported)
{
extension_ptr->pNext = last_requested_extension_feature;
add_extension_features<Feature>(type).*flag = true;
}
last_requested_extension_feature = extension_ptr;
else
{
LOGI("Requested optional feature <{}::{}> is not supported", featureName, flagName);
}
return supported;
}

return *extension_ptr;
/**
* @brief Request a required features flag
*
* Calls get_extension_features to get the support of the requested flag. If it's supported,
* add_extension_features is called, otherwise a runtime_error is thrown.
*/
template <typename Feature>
void request_required_feature(VkStructureType type, VkBool32 Feature::*flag, std::string const &featureName, std::string const &flagName)
{
if (get_extension_features<Feature>(type).*flag)
{
add_extension_features<Feature>(type).*flag = true;
}
else
{
throw std::runtime_error(std::string("Requested required feature <") + featureName + "::" + flagName + "> is not supported");
}
}

/**
Expand Down Expand Up @@ -183,4 +239,8 @@ class PhysicalDevice

bool high_priority_graphics_queue{};
};

#define REQUEST_OPTIONAL_FEATURE(gpu, Feature, type, flag) gpu.request_optional_feature<Feature>(type, &Feature::flag, #Feature, #flag)
#define REQUEST_REQUIRED_FEATURE(gpu, Feature, type, flag) gpu.request_required_feature<Feature>(type, &Feature::flag, #Feature, #flag)

} // namespace vkb
3 changes: 1 addition & 2 deletions samples/api/hpp_timestamp_queries/hpp_timestamp_queries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ bool HPPTimestampQueries::resize(const uint32_t width, const uint32_t height)
void HPPTimestampQueries::request_gpu_features(vkb::core::HPPPhysicalDevice &gpu)
{
// We need to enable the command pool reset feature in the extension struct
auto &requested_extension_features = gpu.request_extension_features<vk::PhysicalDeviceHostQueryResetFeaturesEXT>();
requested_extension_features.hostQueryReset = true;
HPP_REQUEST_REQUIRED_FEATURE(gpu, vk::PhysicalDeviceHostQueryResetFeaturesEXT, hostQueryReset);

// Enable anisotropic filtering if supported
if (gpu.get_features().samplerAnisotropy)
Expand Down
3 changes: 1 addition & 2 deletions samples/api/timestamp_queries/timestamp_queries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ TimestampQueries::~TimestampQueries()
void TimestampQueries::request_gpu_features(vkb::PhysicalDevice &gpu)
{
// We need to enable the command pool reset feature in the extension struct
auto &requested_extension_features = gpu.request_extension_features<VkPhysicalDeviceHostQueryResetFeaturesEXT>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT);
requested_extension_features.hostQueryReset = VK_TRUE;
REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDeviceHostQueryResetFeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, hostQueryReset);

// Enable anisotropic filtering if supported
if (gpu.get_features().samplerAnisotropy)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,10 @@ void BufferDeviceAddress::render(float delta_time)
void BufferDeviceAddress::request_gpu_features(vkb::PhysicalDevice &gpu)
{
// Need to enable the bufferDeviceAddress feature.
auto &features = gpu.request_extension_features<VkPhysicalDeviceBufferDeviceAddressFeaturesKHR>(
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR);
features.bufferDeviceAddress = VK_TRUE;
REQUEST_REQUIRED_FEATURE(gpu,
VkPhysicalDeviceBufferDeviceAddressFeaturesKHR,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR,
bufferDeviceAddress);
}

std::unique_ptr<vkb::VulkanSampleC> create_buffer_device_address()
Expand Down
11 changes: 6 additions & 5 deletions samples/extensions/color_write_enable/color_write_enable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,11 @@ void ColorWriteEnable::create_attachments()

void ColorWriteEnable::request_gpu_features(vkb::PhysicalDevice &gpu)
{
{
auto &features = gpu.request_extension_features<VkPhysicalDeviceColorWriteEnableFeaturesEXT>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT);
features.colorWriteEnable = VK_TRUE;
}
REQUEST_REQUIRED_FEATURE(gpu,
VkPhysicalDeviceColorWriteEnableFeaturesEXT,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT,
colorWriteEnable);

{
auto &features = gpu.get_mutable_requested_features();
features.independentBlend = VK_TRUE;
Expand Down Expand Up @@ -544,7 +545,7 @@ void ColorWriteEnable::on_update_ui_overlay(vkb::Drawer &drawer)
ImGuiColorEditFlags_NoSidePreview |
ImGuiColorEditFlags_NoSmallPreview |
ImGuiColorEditFlags_Float |
ImGuiColorEditFlags_HDR))
ImGuiColorEditFlags_HDR))
{
rebuild_command_buffers();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ ConditionalRendering::~ConditionalRendering()
void ConditionalRendering::request_gpu_features(vkb::PhysicalDevice &gpu)
{
// We need to enable conditional rendering using a new feature struct
auto &requested_extension_features = gpu.request_extension_features<VkPhysicalDeviceConditionalRenderingFeaturesEXT>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT);
requested_extension_features.conditionalRendering = VK_TRUE;
REQUEST_REQUIRED_FEATURE(gpu,
VkPhysicalDeviceConditionalRenderingFeaturesEXT,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT,
conditionalRendering);
}

void ConditionalRendering::build_command_buffers()
Expand Down
Loading

0 comments on commit 5daac4d

Please sign in to comment.