Class Device

Class Documentation

class Device

RAII wrapper class for VkDevice, VkPhysicalDevice and VkQueue.

Note

There is no method is_layer_supported in this wrapper class because device layers are deprecated.

Public Functions

Device(const Instance &inst, VkSurfaceKHR surface, VkPhysicalDevice physical_device, const VkPhysicalDeviceFeatures &required_features, std::span<const char*> required_extensions)

Default constructor

Note

The creation of the physical device will not fail if one of the optional device features is not available

Parameters:
  • inst – The Vulkan instance

  • surface – The window surface

  • desired_gpu – The physical device

  • required_features – The required device features which the physical device must all support

  • required_extensions – The required device extensions

Throws:
  • std::runtime_error – The physical device is not suitable

  • std::runtime_error – No graphics queue could be found

  • std::runtime_error – No presentation queue could be found

  • VulkanException – vkCreateDevice call failed

  • VulkanException – vmaCreateAllocator call failed

Device(const Device&) = delete
Device(Device&&) noexcept
~Device()
Device &operator=(const Device&) = delete
Device &operator=(Device&&) = delete
inline auto device() const
VkSurfaceCapabilitiesKHR get_surface_capabilities(VkSurfaceKHR surface) const

Call vkGetPhysicalDeviceSurfaceCapabilitiesKHR.

Parameters:

surface – The window surface.

Throws:

VulkanException – Calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed

Returns:

The surface capabilities

bool is_presentation_supported(VkSurfaceKHR surface, std::uint32_t queue_family_index) const

Call vkGetPhysicalDeviceSurfaceSupportKHR.

Note

It was decided to place this function here into the device wrapper and not into the surface wrapper because the VkPhysicalDevice is required to call vkGetPhysicalDeviceSurfaceSupportKHR.

Parameters:
  • surface – The window surface.

  • queue_family_index – The queue family index.

Throws:

VulkanException – Calling vkGetPhysicalDeviceSurfaceSupportKHR failed.

Returns:

true if presentation is supported.

void execute(const std::string &name, const VulkanQueueType queue_type, const std::function<void(const CommandBuffer &cmd_buf)> &cmd_lambda) const

A wrapper method for beginning, ending and submitting command buffers. This method calls the request method for the given command pool, begins the command buffer, executes the lambda, ends recording the command buffer, submits it and waits for it.

Parameters:
  • name – The internal debug name of the command buffer (must not be empty).

  • queue_type – The queue type which determines which command pool is used.

  • cmd_lambda – The command lambda to execute.

inline VkPhysicalDevice physical_device() const
inline VmaAllocator allocator() const
inline const VkPhysicalDeviceFeatures &enabled_features() const
inline const std::string &gpu_name() const
inline std::span<const std::uint8_t, VK_UUID_SIZE> pipeline_cache_uuid() const

Get the pipeline cache UUID for the physical device

Returns:

A span view of the pipeline cache UUID bytes

inline bool has_any_compute_queue() const
inline bool has_any_transfer_queue() const
inline bool has_any_sparse_binding_queue() const
inline VkQueue compute_queue() const
inline VkQueue graphics_queue() const
inline VkQueue present_queue() const
inline VkQueue transfer_queue() const
const CommandBuffer &request_command_buffer(VulkanQueueType queue_type, const std::string &name)

Request a command buffer from the thread_local command pool.

Parameters:
  • queue_type – The Vulkan queue type which is required because a command pool is created with a queue family index associated with it.

  • name – The name which will be assigned to the command buffer.

Returns:

A command buffer from the thread_local command pool.

bool surface_supports_usage(VkSurfaceKHR surface, VkImageUsageFlagBits usage) const

Check if a surface supports a certain image usage.

Parameters:
  • surface – The window surface.

  • usage – The requested image usage.

Returns:

true if the format feature is supported.

template<typename VulkanObjectType>
inline void set_debug_name(const VulkanObjectType &vk_object, const std::string &name) const

Automatically detect the type of a Vulkan object and set the internal debug name to it

Template Parameters:

VulkanObjectType – The Vulkan object type. This template parameter will be automatically translated into the matching VkObjectType using vk_tools::get_vulkan_object_type(vk_object). This is the most advanced abstraction that we found and it’s really easy to use set_debug_name now because it’s not possible to make a mistake because you don’t have to specify the VkObjectType manually when naming a Vulkan object.

Parameters:
  • vk_object – The Vulkan object to assign a name to.

  • name – The internal debug name of the Vulkan object (must not be empty!).

void wait_idle(VkQueue queue = VK_NULL_HANDLE) const

Call vkDeviceWaitIdle or vkQueueWaitIdle depending on whether queue is specified.

Warning

Avoid using those methods because they result in bad gpu performance due to global stalls!

Parameters:

queue – (VK_NULL_HANDLE by default).

Throws:
  • VulkanExceptionvkDeviceWaitIdle call failed.

  • VulkanExceptionvkQueueWaitIdle call failed.

Private Functions

CommandPool &get_thread_command_pool(VulkanQueueType queue_type) const

Get the thread_local command pool.

Note

This method will create a command pool for the thread if it doesn’t already exist.

Parameters:

queue_type – The Vulkan queue type

Private Members

VkDevice m_device = {VK_NULL_HANDLE}
VkPhysicalDevice m_physical_device = {VK_NULL_HANDLE}
VmaAllocator m_allocator = {VK_NULL_HANDLE}
std::string m_gpu_name
VkPhysicalDeviceFeatures m_enabled_features = {}
std::array<std::uint8_t, VK_UUID_SIZE> m_pipeline_cache_uuid = {}
VkQueue m_graphics_queue = {VK_NULL_HANDLE}
VkQueue m_transfer_queue = {VK_NULL_HANDLE}
VkQueue m_compute_queue = {VK_NULL_HANDLE}
VkQueue m_sparse_binding_queue = {VK_NULL_HANDLE}
VkQueue m_present_queue = {VK_NULL_HANDLE}
std::optional<std::uint32_t> m_graphics_queue_family_index = {0}
std::optional<std::uint32_t> m_compute_queue_family_index = {0}
std::optional<std::uint32_t> m_transfer_queue_family_index = {0}
std::optional<std::uint32_t> m_sparse_binding_queue_family_index = {0}
std::optional<std::uint32_t> m_present_queue_family_index = {0}
mutable std::vector<std::unique_ptr<CommandPool>> m_cmd_pools

According to NVidia, we should aim for one command pool per thread https://developer.nvidia.com/blog/vulkan-dos-donts/

mutable std::shared_mutex m_mutex