Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions framework/core/device.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
/* Copyright (c) 2025-2026, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
Expand Down Expand Up @@ -87,7 +87,7 @@ class Device
Device(PhysicalDevice<bindingType> &gpu,
SurfaceType surface,
std::unique_ptr<DebugUtilsType> &&debug_utils,
std::unordered_map<const char *, bool> const &requested_extensions = {},
std::unordered_map<std::string, vkb::RequestMode> const &requested_extensions = {},
std::function<void(vkb::core::PhysicalDevice<bindingType> &)> request_gpu_features = {});

/**
Expand Down Expand Up @@ -136,12 +136,12 @@ class Device
void flush_command_buffer_impl(
vk::Device device, vk::CommandBuffer command_buffer, vk::Queue queue, bool free = true, vk::Semaphore signal_semaphore = nullptr) const;
vkb::core::HPPQueue const &get_queue_by_flags_impl(vk::QueueFlags queue_flags, uint32_t queue_index) const;
void init(std::unordered_map<const char *, bool> const &requested_extensions, std::function<void(vkb::core::PhysicalDevice<bindingType> &)> request_gpu_features);
void init(std::unordered_map<std::string, vkb::RequestMode> const &requested_extensions, std::function<void(vkb::core::PhysicalDevice<bindingType> &)> request_gpu_features);

private:
std::unique_ptr<vkb::core::CommandPoolCpp> command_pool;
std::unique_ptr<vkb::core::HPPDebugUtils> debug_utils;
std::vector<const char *> enabled_extensions{};
std::vector<std::string> enabled_extensions;
std::unique_ptr<vkb::HPPFencePool> fence_pool;
vkb::core::PhysicalDeviceCpp &gpu;
std::vector<std::vector<vkb::core::HPPQueue>> queues;
Expand All @@ -163,22 +163,22 @@ namespace core
{

template <>
inline Device<vkb::BindingType::Cpp>::Device(vkb::core::PhysicalDeviceCpp &gpu,
vk::SurfaceKHR surface,
std::unique_ptr<vkb::core::HPPDebugUtils> &&debug_utils,
std::unordered_map<const char *, bool> const &requested_extensions,
std::function<void(vkb::core::PhysicalDeviceCpp &)> request_gpu_features) :
inline Device<vkb::BindingType::Cpp>::Device(vkb::core::PhysicalDeviceCpp &gpu,
vk::SurfaceKHR surface,
std::unique_ptr<vkb::core::HPPDebugUtils> &&debug_utils,
std::unordered_map<std::string, vkb::RequestMode> const &requested_extensions,
std::function<void(vkb::core::PhysicalDeviceCpp &)> request_gpu_features) :
vkb::core::VulkanResourceCpp<vk::Device>{nullptr, this}, debug_utils{std::move(debug_utils)}, gpu{gpu}, resource_cache{*this}, surface(surface)
{
init(requested_extensions, request_gpu_features);
}

template <>
inline Device<vkb::BindingType::C>::Device(vkb::core::PhysicalDeviceC &gpu,
VkSurfaceKHR surface,
std::unique_ptr<vkb::DebugUtils> &&debug_utils,
std::unordered_map<const char *, bool> const &requested_extensions,
std::function<void(vkb::core::PhysicalDeviceC &)> request_gpu_features) :
inline Device<vkb::BindingType::C>::Device(vkb::core::PhysicalDeviceC &gpu,
VkSurfaceKHR surface,
std::unique_ptr<vkb::DebugUtils> &&debug_utils,
std::unordered_map<std::string, vkb::RequestMode> const &requested_extensions,
std::function<void(vkb::core::PhysicalDeviceC &)> request_gpu_features) :
vkb::core::VulkanResourceC<VkDevice>{VK_NULL_HANDLE, this}, debug_utils{reinterpret_cast<vkb::core::HPPDebugUtils *>(debug_utils.release())}, gpu{reinterpret_cast<vkb::core::PhysicalDeviceCpp &>(gpu)}, resource_cache{*reinterpret_cast<vkb::core::DeviceCpp *>(this)}, surface(static_cast<vk::SurfaceKHR>(surface))
{
init(requested_extensions, request_gpu_features);
Expand Down Expand Up @@ -472,7 +472,7 @@ inline typename Device<bindingType>::ResourceCacheType &Device<bindingType>::get
template <vkb::BindingType bindingType>
inline bool Device<bindingType>::is_extension_enabled(const char *extension) const
{
return std::ranges::find_if(enabled_extensions, [extension](const char *enabled_extension) { return strcmp(extension, enabled_extension) == 0; }) !=
return std::ranges::find_if(enabled_extensions, [extension](std::string const &enabled_extension) { return enabled_extension == extension; }) !=
enabled_extensions.end();
}

Expand Down Expand Up @@ -619,7 +619,7 @@ vkb::core::HPPQueue const &Device<bindingType>::get_queue_by_flags_impl(vk::Queu
}

template <vkb::BindingType bindingType>
inline void Device<bindingType>::init(std::unordered_map<const char *, bool> const &requested_extensions, std::function<void(vkb::core::PhysicalDevice<bindingType> &)> request_gpu_features)
inline void Device<bindingType>::init(std::unordered_map<std::string, vkb::RequestMode> const &requested_extensions, std::function<void(vkb::core::PhysicalDevice<bindingType> &)> request_gpu_features)
{
LOGI("Selected GPU: {}", *gpu.get_properties().deviceName);

Expand Down Expand Up @@ -677,7 +677,7 @@ inline void Device<bindingType>::init(std::unordered_map<const char *, bool> con
}

// Check that extensions are supported before trying to create the device
std::vector<const char *> unsupported_extensions{};
std::vector<std::string> unsupported_extensions{};
for (auto &extension : requested_extensions)
{
if (gpu.is_extension_supported(extension.first))
Expand Down Expand Up @@ -706,7 +706,7 @@ inline void Device<bindingType>::init(std::unordered_map<const char *, bool> con
{
auto extIt = requested_extensions.find(extension);
assert(extIt != requested_extensions.end());
if (extIt->second)
if (extIt->second == vkb::RequestMode::Optional)
{
LOGW("Optional device extension {} not available, some features may be disabled", extension);
}
Expand All @@ -732,12 +732,18 @@ inline void Device<bindingType>::init(std::unordered_map<const char *, bool> con
request_gpu_features(reinterpret_cast<vkb::core::PhysicalDeviceC &>(gpu));
}

std::vector<char const *> enabled_extensions_cstr;
for (auto &extension : enabled_extensions)
{
enabled_extensions_cstr.push_back(extension.c_str());
}

// Latest requested feature will have the pNext's all set up for device creation.
vk::DeviceCreateInfo create_info{.pNext = gpu.get_extension_feature_chain(),
.queueCreateInfoCount = static_cast<uint32_t>(queue_create_infos.size()),
.pQueueCreateInfos = queue_create_infos.data(),
.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()),
.ppEnabledExtensionNames = enabled_extensions.data(),
.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_cstr.size()),
.ppEnabledExtensionNames = enabled_extensions_cstr.data(),
.pEnabledFeatures = &gpu.get_requested_features()};

this->set_handle(gpu.get_handle().createDevice(create_info));
Expand Down
117 changes: 40 additions & 77 deletions framework/vulkan_sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ class VulkanSample : public vkb::Application
* @param command_buffer The command buffer to record the commands to
*/
virtual void render(vkb::core::CommandBuffer<bindingType> &command_buffer);
virtual void request_device_extensions(std::unordered_map<std::string, vkb::RequestMode> &requested_extensions) const;

/**
* @brief Request features from the gpu based on what is supported
Expand All @@ -236,16 +237,6 @@ class VulkanSample : public vkb::Application
*/
virtual void update_debug_window();

/// <summary>
/// PROTECTED INTERFACE
/// </summary>
/**
* @brief Add a sample-specific device extension
* @param extension The extension name
* @param optional (Optional) Whether the extension is optional
*/
void add_device_extension(const char *extension, bool optional = false);

void create_gui(const Window &window, vkb::stats::Stats<bindingType> const *stats = nullptr, const float font_size = 21.0f, bool explicit_update = false);

/**
Expand Down Expand Up @@ -340,13 +331,6 @@ class VulkanSample : public vkb::Application
void request_layer_settings_impl(std::vector<vk::LayerSettingEXT> &requested_layer_settings, vkb::StructureChainBuilderCpp<vk::InstanceCreateInfo> &scb) const;
static void set_viewport_and_scissor_impl(vkb::core::CommandBufferCpp const &command_buffer, vk::Extent2D const &extent);

/**
* @brief Get sample-specific device extensions.
*
* @return Map of device extensions and whether or not they are optional. Default is empty map.
*/
std::unordered_map<const char *, bool> const &get_device_extensions() const;

/// <summary>
/// PRIVATE MEMBERS
/// </summary>
Expand Down Expand Up @@ -407,9 +391,6 @@ class VulkanSample : public vkb::Application
*/
Configuration configuration{};

/** @brief Set of device extensions to be enabled for this example and whether they are optional (must be set in the derived constructor) */
std::unordered_map<const char *, bool> device_extensions;

/** @brief Whether or not we want a high priority graphics queue. */
bool high_priority_graphics_queue{false};

Expand Down Expand Up @@ -457,27 +438,24 @@ inline VulkanSample<bindingType>::~VulkanSample()
instance.reset();
}

template <vkb::BindingType bindingType>
inline void VulkanSample<bindingType>::add_device_extension(const char *extension, bool optional)
{
device_extensions[extension] = optional;
}

template <vkb::BindingType bindingType>
inline std::unique_ptr<typename vkb::core::Device<bindingType>>
VulkanSample<bindingType>::create_device(vkb::core::PhysicalDevice<bindingType> &gpu)
{
std::unordered_map<std::string, vkb::RequestMode> requested_extensions;
request_device_extensions(requested_extensions);

if constexpr (bindingType == BindingType::Cpp)
{
return std::make_unique<vkb::core::DeviceCpp>(
gpu, surface, std::move(debug_utils), get_device_extensions(), [this](vkb::core::PhysicalDeviceCpp &gpu) { request_gpu_features(gpu); });
gpu, surface, std::move(debug_utils), requested_extensions, [this](vkb::core::PhysicalDeviceCpp &gpu) { request_gpu_features(gpu); });
}
else
{
return std::make_unique<vkb::core::DeviceC>(gpu,
static_cast<VkSurfaceKHR>(surface),
std::unique_ptr<vkb::DebugUtils>(reinterpret_cast<vkb::DebugUtils *>(debug_utils.release())),
get_device_extensions(),
requested_extensions,
[this](vkb::core::PhysicalDeviceC &gpu) { request_gpu_features(gpu); });
}
}
Expand Down Expand Up @@ -933,12 +911,6 @@ inline vkb::core::Device<bindingType> &VulkanSample<bindingType>::get_device()
}
}

template <vkb::BindingType bindingType>
inline std::unordered_map<const char *, bool> const &VulkanSample<bindingType>::get_device_extensions() const
{
return device_extensions;
}

template <vkb::BindingType bindingType>
inline vkb::Gui<bindingType> &VulkanSample<bindingType>::get_gui()
{
Expand Down Expand Up @@ -1226,21 +1198,6 @@ inline bool VulkanSample<bindingType>::prepare(const ApplicationOptions &options
throw VulkanException(result, "Failed to initialize volk.");
}

#ifdef VKB_VULKAN_DEBUG
{
std::vector<vk::ExtensionProperties> available_instance_extensions = vk::enumerateInstanceExtensionProperties();
auto debugExtensionIt =
std::ranges::find_if(available_instance_extensions,
[](vk::ExtensionProperties const &ep) { return strcmp(ep.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0; });
if (debugExtensionIt != available_instance_extensions.end())
{
LOGI("Vulkan debug utils enabled ({})", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);

debug_utils = std::make_unique<vkb::core::HPPDebugUtilsExtDebugUtils>();
}
}
#endif

if constexpr (bindingType == BindingType::Cpp)
{
instance = create_instance();
Expand All @@ -1253,6 +1210,9 @@ inline bool VulkanSample<bindingType>::prepare(const ApplicationOptions &options
// initialize debug utils or report callback based on enabled extensions, if any
if (instance->is_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME))
{
#ifdef VKB_VULKAN_DEBUG
debug_utils = std::make_unique<vkb::core::HPPDebugUtilsExtDebugUtils>();
#endif
auto const *debug_utils_messenger_create_info = get_debug_utils_messenger_create_info();
if (debug_utils_messenger_create_info)
{
Expand Down Expand Up @@ -1299,31 +1259,6 @@ inline bool VulkanSample<bindingType>::prepare(const ApplicationOptions &options
physical_device->get_mutable_requested_features().textureCompressionASTC_LDR = true;
}

// Creating vulkan device, specifying the swapchain extension always
// If using VK_EXT_headless_surface, we still create and use a swap-chain
{
add_device_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);

if (instance->is_extension_enabled(VK_KHR_DISPLAY_EXTENSION_NAME))
{
add_device_extension(VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME, /*optional=*/true);
}
}

// Shaders generated by Slang require a certain SPIR-V environment that can't be satisfied by Vulkan 1.0, so we need to expliclity up that to at least 1.1 and enable some required extensions
if (get_shading_language() == ShadingLanguage::SLANG)
{
assert(VK_API_VERSION_1_1 <= get_api_version());
add_device_extension(VK_KHR_SPIRV_1_4_EXTENSION_NAME);
add_device_extension(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
add_device_extension(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME);
}

#ifdef VKB_ENABLE_PORTABILITY
// VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled)
add_device_extension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, /*optional=*/true);
#endif

#ifdef VKB_VULKAN_DEBUG
if (!debug_utils)
{
Expand All @@ -1336,16 +1271,13 @@ inline bool VulkanSample<bindingType>::prepare(const ApplicationOptions &options
LOGI("Vulkan debug utils enabled ({})", VK_EXT_DEBUG_MARKER_EXTENSION_NAME);

debug_utils = std::make_unique<vkb::core::HPPDebugMarkerExtDebugUtils>();
add_device_extension(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
}
}

if (!debug_utils)
{
LOGW("Vulkan debug utils were requested, but no extension that provides them was found");
}
#endif

if (!debug_utils)
{
debug_utils = std::make_unique<vkb::core::HPPDummyDebugUtils>();
Expand Down Expand Up @@ -1419,6 +1351,37 @@ inline void VulkanSample<bindingType>::render_impl(vkb::core::CommandBufferCpp &
}
}

template <vkb::BindingType bindingType>
inline void VulkanSample<bindingType>::request_device_extensions(std::unordered_map<std::string, vkb::RequestMode> &requested_extensions) const
{
// Creating vulkan device, specifying the swapchain extension always
// If using VK_EXT_headless_surface, we still create and use a swap-chain
requested_extensions[VK_KHR_SWAPCHAIN_EXTENSION_NAME] = vkb::RequestMode::Required;

if (instance->is_extension_enabled(VK_KHR_DISPLAY_EXTENSION_NAME))
{
requested_extensions[VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME] = vkb::RequestMode::Optional;
}

// Shaders generated by Slang require a certain SPIR-V environment that can't be satisfied by Vulkan 1.0, so we need to expliclity up that to at least 1.1 and enable some required extensions
if (get_shading_language() == ShadingLanguage::SLANG)
{
assert(VK_API_VERSION_1_1 <= get_api_version());
requested_extensions[VK_KHR_SPIRV_1_4_EXTENSION_NAME] = vkb::RequestMode::Required;
requested_extensions[VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME] = vkb::RequestMode::Required;
requested_extensions[VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME] = vkb::RequestMode::Required;
}

#ifdef VKB_ENABLE_PORTABILITY
// VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled)
requested_extensions[VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME] = vkb::RequestMode::Optional;
#endif

#ifdef VKB_VULKAN_DEBUG
requested_extensions[VK_EXT_DEBUG_MARKER_EXTENSION_NAME] = vkb::RequestMode::Optional;
#endif
}

template <vkb::BindingType bindingType>
inline void VulkanSample<bindingType>::request_gpu_features(vkb::core::PhysicalDevice<bindingType> &gpu)
{
Expand Down
9 changes: 7 additions & 2 deletions samples/api/hpp_oit_linked_lists/hpp_oit_linked_lists.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
HPPOITLinkedLists::HPPOITLinkedLists()
{
title = "HPP OIT linked lists";

add_device_extension(vk::KHRSynchronization2ExtensionName);
}

HPPOITLinkedLists::~HPPOITLinkedLists()
Expand Down Expand Up @@ -77,6 +75,13 @@ bool HPPOITLinkedLists::resize(const uint32_t width, const uint32_t height)
return HPPApiVulkanSample::resize(width, height);
}

void HPPOITLinkedLists::request_device_extensions(std::unordered_map<std::string, vkb::RequestMode> &requested_extensions) const
{
vkb::VulkanSampleCpp::request_device_extensions(requested_extensions);

requested_extensions[vk::KHRSynchronization2ExtensionName] = vkb::RequestMode::Required;
}

void HPPOITLinkedLists::request_gpu_features(vkb::core::PhysicalDeviceCpp &gpu)
{
auto &requested_features = gpu.get_mutable_requested_features();
Expand Down
3 changes: 2 additions & 1 deletion samples/api/hpp_oit_linked_lists/hpp_oit_linked_lists.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2023-2025, NVIDIA
/* Copyright (c) 2023-2026, NVIDIA
*
* SPDX-License-Identifier: Apache-2.0
*
Expand Down Expand Up @@ -31,6 +31,7 @@ class HPPOITLinkedLists : public HPPApiVulkanSample
bool resize(const uint32_t width, const uint32_t height) override;

// from vkb::VulkanSample
void request_device_extensions(std::unordered_map<std::string, vkb::RequestMode> &requested_extensions) const override;
void request_gpu_features(vkb::core::PhysicalDeviceCpp &gpu) override;

// from HPPApiVulkanSample
Expand Down
9 changes: 7 additions & 2 deletions samples/api/oit_linked_lists/oit_linked_lists.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
OITLinkedLists::OITLinkedLists()
{
title = "OIT linked lists";

add_device_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
}

OITLinkedLists::~OITLinkedLists()
Expand Down Expand Up @@ -108,6 +106,13 @@ void OITLinkedLists::render(float delta_time)
update_scene_constants();
}

void OITLinkedLists::request_device_extensions(std::unordered_map<std::string, vkb::RequestMode> &requested_extensions) const
{
vkb::VulkanSampleC::request_device_extensions(requested_extensions);
Comment thread
SaschaWillems marked this conversation as resolved.

requested_extensions[VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME] = vkb::RequestMode::Required;
}

void OITLinkedLists::request_gpu_features(vkb::core::PhysicalDeviceC &gpu)
{
if (gpu.get_features().fragmentStoresAndAtomics)
Expand Down
Loading
Loading