VkBootstrap.h 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /*
  2. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  3. * documentation files (the “Software”), to deal in the Software without restriction, including without
  4. * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  5. * of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  6. *
  7. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  8. *
  9. * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  10. * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  11. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  12. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  13. *
  14. * Copyright © 2020 Charles Giessen ([email protected])
  15. */
  16. #pragma once
  17. #include <cassert>
  18. #include <cstdio>
  19. #include <cstring>
  20. #include <vector>
  21. #include <string>
  22. #include <system_error>
  23. #include <vulkan/vulkan.h>
  24. #include "VkBootstrapDispatch.h"
  25. #ifdef VK_MAKE_API_VERSION
  26. #define VKB_MAKE_VK_VERSION(variant, major, minor, patch) VK_MAKE_API_VERSION(variant, major, minor, patch)
  27. #elif defined(VK_MAKE_VERSION)
  28. #define VKB_MAKE_VK_VERSION(variant, major, minor, patch) VK_MAKE_VERSION(major, minor, patch)
  29. #endif
  30. #if defined(VK_API_VERSION_1_3) || defined(VK_VERSION_1_3)
  31. #define VKB_VK_API_VERSION_1_3 VKB_MAKE_VK_VERSION(0, 1, 3, 0)
  32. #endif
  33. #if defined(VK_API_VERSION_1_2) || defined(VK_VERSION_1_2)
  34. #define VKB_VK_API_VERSION_1_2 VKB_MAKE_VK_VERSION(0, 1, 2, 0)
  35. #endif
  36. #if defined(VK_API_VERSION_1_1) || defined(VK_VERSION_1_1)
  37. #define VKB_VK_API_VERSION_1_1 VKB_MAKE_VK_VERSION(0, 1, 1, 0)
  38. #endif
  39. #if defined(VK_API_VERSION_1_0) || defined(VK_VERSION_1_0)
  40. #define VKB_VK_API_VERSION_1_0 VKB_MAKE_VK_VERSION(0, 1, 0, 0)
  41. #endif
  42. namespace vkb {
  43. struct Error {
  44. std::error_code type;
  45. VkResult vk_result = VK_SUCCESS; // optional error value if a vulkan call failed
  46. };
  47. template <typename T> class Result {
  48. public:
  49. Result(const T& value) noexcept : m_value{ value }, m_init{ true } {}
  50. Result(T&& value) noexcept : m_value{ std::move(value) }, m_init{ true } {}
  51. Result(Error error) noexcept : m_error{ error }, m_init{ false } {}
  52. Result(std::error_code error_code, VkResult result = VK_SUCCESS) noexcept
  53. : m_error{ error_code, result }, m_init{ false } {}
  54. ~Result() noexcept { destroy(); }
  55. Result(Result const& expected) noexcept : m_init(expected.m_init) {
  56. if (m_init)
  57. new (&m_value) T{ expected.m_value };
  58. else
  59. m_error = expected.m_error;
  60. }
  61. Result& operator=(Result const& result) noexcept {
  62. m_init = result.m_init;
  63. if (m_init)
  64. new (&m_value) T{ result.m_value };
  65. else
  66. m_error = result.m_error;
  67. }
  68. Result(Result&& expected) noexcept : m_init(expected.m_init) {
  69. if (m_init)
  70. new (&m_value) T{ std::move(expected.m_value) };
  71. else
  72. m_error = std::move(expected.m_error);
  73. expected.destroy();
  74. }
  75. Result& operator=(Result&& result) noexcept {
  76. m_init = result.m_init;
  77. if (m_init)
  78. new (&m_value) T{ std::move(result.m_value) };
  79. else
  80. m_error = std::move(result.m_error);
  81. }
  82. Result& operator=(const T& expect) noexcept {
  83. destroy();
  84. m_init = true;
  85. new (&m_value) T{ expect };
  86. return *this;
  87. }
  88. Result& operator=(T&& expect) noexcept {
  89. destroy();
  90. m_init = true;
  91. new (&m_value) T{ std::move(expect) };
  92. return *this;
  93. }
  94. Result& operator=(const Error& error) noexcept {
  95. destroy();
  96. m_init = false;
  97. m_error = error;
  98. return *this;
  99. }
  100. Result& operator=(Error&& error) noexcept {
  101. destroy();
  102. m_init = false;
  103. m_error = error;
  104. return *this;
  105. }
  106. // clang-format off
  107. const T* operator-> () const noexcept { assert (m_init); return &m_value; }
  108. T* operator-> () noexcept { assert (m_init); return &m_value; }
  109. const T& operator* () const& noexcept { assert (m_init); return m_value; }
  110. T& operator* () & noexcept { assert (m_init); return m_value; }
  111. T&& operator* () && noexcept { assert (m_init); return std::move (m_value); }
  112. const T& value () const& noexcept { assert (m_init); return m_value; }
  113. T& value () & noexcept { assert (m_init); return m_value; }
  114. const T&& value () const&& noexcept { assert (m_init); return std::move (m_value); }
  115. T&& value () && noexcept { assert (m_init); return std::move (m_value); }
  116. // std::error_code associated with the error
  117. std::error_code error() const { assert (!m_init); return m_error.type; }
  118. // optional VkResult that could of been produced due to the error
  119. VkResult vk_result() const { assert (!m_init); return m_error.vk_result; }
  120. // Returns the struct that holds the std::error_code and VkResult
  121. Error full_error() const { assert (!m_init); return m_error; }
  122. // clang-format on
  123. // check if the result has an error that matches a specific error case
  124. template <typename E> bool matches_error(E error_enum_value) const {
  125. return !m_init && static_cast<E>(m_error.type.value()) == error_enum_value;
  126. }
  127. bool has_value() const { return m_init; }
  128. explicit operator bool() const { return m_init; }
  129. private:
  130. void destroy() {
  131. if (m_init) m_value.~T();
  132. }
  133. union {
  134. T m_value;
  135. Error m_error;
  136. };
  137. bool m_init;
  138. };
  139. namespace detail {
  140. struct GenericFeaturesPNextNode {
  141. static const uint32_t field_capacity = 256;
  142. GenericFeaturesPNextNode();
  143. template <typename T> GenericFeaturesPNextNode(T const& features) noexcept {
  144. memset(fields, UINT8_MAX, sizeof(VkBool32) * field_capacity);
  145. memcpy(this, &features, sizeof(T));
  146. }
  147. static bool match(GenericFeaturesPNextNode const& requested, GenericFeaturesPNextNode const& supported) noexcept;
  148. VkStructureType sType = static_cast<VkStructureType>(0);
  149. void* pNext = nullptr;
  150. VkBool32 fields[field_capacity];
  151. };
  152. } // namespace detail
  153. enum class InstanceError {
  154. vulkan_unavailable,
  155. vulkan_version_unavailable,
  156. vulkan_version_1_1_unavailable,
  157. vulkan_version_1_2_unavailable,
  158. failed_create_instance,
  159. failed_create_debug_messenger,
  160. requested_layers_not_present,
  161. requested_extensions_not_present,
  162. windowing_extensions_not_present,
  163. };
  164. enum class PhysicalDeviceError {
  165. no_surface_provided,
  166. failed_enumerate_physical_devices,
  167. no_physical_devices_found,
  168. no_suitable_device,
  169. };
  170. enum class QueueError {
  171. present_unavailable,
  172. graphics_unavailable,
  173. compute_unavailable,
  174. transfer_unavailable,
  175. queue_index_out_of_range,
  176. invalid_queue_family_index
  177. };
  178. enum class DeviceError {
  179. failed_create_device,
  180. VkPhysicalDeviceFeatures2_in_pNext_chain_while_using_add_required_extension_features,
  181. };
  182. enum class SwapchainError {
  183. surface_handle_not_provided,
  184. failed_query_surface_support_details,
  185. failed_create_swapchain,
  186. failed_get_swapchain_images,
  187. failed_create_swapchain_image_views,
  188. required_min_image_count_too_low,
  189. required_usage_not_supported
  190. };
  191. std::error_code make_error_code(InstanceError instance_error);
  192. std::error_code make_error_code(PhysicalDeviceError physical_device_error);
  193. std::error_code make_error_code(QueueError queue_error);
  194. std::error_code make_error_code(DeviceError device_error);
  195. std::error_code make_error_code(SwapchainError swapchain_error);
  196. const char* to_string_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT s);
  197. const char* to_string_message_type(VkDebugUtilsMessageTypeFlagsEXT s);
  198. const char* to_string(InstanceError err);
  199. const char* to_string(PhysicalDeviceError err);
  200. const char* to_string(QueueError err);
  201. const char* to_string(DeviceError err);
  202. const char* to_string(SwapchainError err);
  203. // Gathers useful information about the available vulkan capabilities, like layers and instance
  204. // extensions. Use this for enabling features conditionally, ie if you would like an extension but
  205. // can use a fallback if it isn't supported but need to know if support is available first.
  206. struct SystemInfo {
  207. private:
  208. SystemInfo();
  209. public:
  210. // Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail.
  211. static Result<SystemInfo> get_system_info();
  212. static Result<SystemInfo> get_system_info(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
  213. // Returns true if a layer is available
  214. bool is_layer_available(const char* layer_name) const;
  215. // Returns true if an extension is available
  216. bool is_extension_available(const char* extension_name) const;
  217. std::vector<VkLayerProperties> available_layers;
  218. std::vector<VkExtensionProperties> available_extensions;
  219. bool validation_layers_available = false;
  220. bool debug_utils_available = false;
  221. };
  222. // Forward declared - check VkBoostrap.cpp for implementations
  223. const char* to_string_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT s);
  224. const char* to_string_message_type(VkDebugUtilsMessageTypeFlagsEXT s);
  225. // Default debug messenger
  226. // Feel free to copy-paste it into your own code, change it as needed, then call `set_debug_callback()` to use that instead
  227. inline VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
  228. VkDebugUtilsMessageTypeFlagsEXT messageType,
  229. const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
  230. void*) {
  231. auto ms = to_string_message_severity(messageSeverity);
  232. auto mt = to_string_message_type(messageType);
  233. printf("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);
  234. return VK_FALSE; // Applications must return false here
  235. }
  236. class InstanceBuilder;
  237. class PhysicalDeviceSelector;
  238. struct Instance {
  239. VkInstance instance = VK_NULL_HANDLE;
  240. VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
  241. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  242. PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
  243. PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr;
  244. // A conversion function which allows this Instance to be used
  245. // in places where VkInstance would have been used.
  246. operator VkInstance() const;
  247. private:
  248. bool headless = false;
  249. bool properties2_ext_enabled = false;
  250. uint32_t instance_version = VKB_VK_API_VERSION_1_0;
  251. uint32_t api_version = VKB_VK_API_VERSION_1_0;
  252. friend class InstanceBuilder;
  253. friend class PhysicalDeviceSelector;
  254. };
  255. void destroy_surface(Instance instance, VkSurfaceKHR surface); // release surface handle
  256. void destroy_surface(VkInstance instance, VkSurfaceKHR surface, VkAllocationCallbacks* callbacks = nullptr); // release surface handle
  257. void destroy_instance(Instance instance); // release instance resources
  258. /* If headless mode is false, by default vk-bootstrap use the following logic to enable the windowing extensions
  259. #if defined(_WIN32)
  260. VK_KHR_win32_surface
  261. #elif defined(__linux__)
  262. VK_KHR_xcb_surface
  263. VK_KHR_xlib_surface
  264. VK_KHR_wayland_surface
  265. #elif defined(__APPLE__)
  266. VK_EXT_metal_surface
  267. #elif defined(__ANDROID__)
  268. VK_KHR_android_surface
  269. #elif defined(_DIRECT2DISPLAY)
  270. VK_KHR_display
  271. #endif
  272. Use `InstanceBuilder::enable_extension()` to add new extensions without altering the default behavior
  273. Feel free to make a PR or raise an issue to include additional platforms.
  274. */
  275. class InstanceBuilder {
  276. public:
  277. // Default constructor, will load vulkan.
  278. explicit InstanceBuilder();
  279. // Optional: Can use your own PFN_vkGetInstanceProcAddr
  280. explicit InstanceBuilder(PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
  281. // Create a VkInstance. Return an error if it failed.
  282. Result<Instance> build() const;
  283. // Sets the name of the application. Defaults to "" if none is provided.
  284. InstanceBuilder& set_app_name(const char* app_name);
  285. // Sets the name of the engine. Defaults to "" if none is provided.
  286. InstanceBuilder& set_engine_name(const char* engine_name);
  287. // Sets the version of the application.
  288. // Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
  289. InstanceBuilder& set_app_version(uint32_t app_version);
  290. // Sets the (major, minor, patch) version of the application.
  291. InstanceBuilder& set_app_version(uint32_t major, uint32_t minor, uint32_t patch = 0);
  292. // Sets the version of the engine.
  293. // Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
  294. InstanceBuilder& set_engine_version(uint32_t engine_version);
  295. // Sets the (major, minor, patch) version of the engine.
  296. InstanceBuilder& set_engine_version(uint32_t major, uint32_t minor, uint32_t patch = 0);
  297. // Require a vulkan API version. Will fail to create if this version isn't available.
  298. // Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
  299. InstanceBuilder& require_api_version(uint32_t required_api_version);
  300. // Require a vulkan API version. Will fail to create if this version isn't available.
  301. InstanceBuilder& require_api_version(uint32_t major, uint32_t minor, uint32_t patch = 0);
  302. // Overrides required API version for instance creation. Will fail to create if this version isn't available.
  303. // Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
  304. InstanceBuilder& set_minimum_instance_version(uint32_t minimum_instance_version);
  305. // Overrides required API version for instance creation. Will fail to create if this version isn't available.
  306. InstanceBuilder& set_minimum_instance_version(uint32_t major, uint32_t minor, uint32_t patch = 0);
  307. // Prefer a vulkan instance API version. If the desired version isn't available, it will use the
  308. // highest version available. Should be constructed with VK_MAKE_VERSION or VK_MAKE_API_VERSION.
  309. [[deprecated("Use require_api_version + set_minimum_instance_version instead.")]] InstanceBuilder&
  310. desire_api_version(uint32_t preferred_vulkan_version);
  311. // Prefer a vulkan instance API version. If the desired version isn't available, it will use the highest version available.
  312. [[deprecated("Use require_api_version + set_minimum_instance_version instead.")]] InstanceBuilder&
  313. desire_api_version(uint32_t major, uint32_t minor, uint32_t patch = 0);
  314. // Adds a layer to be enabled. Will fail to create an instance if the layer isn't available.
  315. InstanceBuilder& enable_layer(const char* layer_name);
  316. // Adds an extension to be enabled. Will fail to create an instance if the extension isn't available.
  317. InstanceBuilder& enable_extension(const char* extension_name);
  318. // Headless Mode does not load the required extensions for presentation. Defaults to true.
  319. InstanceBuilder& set_headless(bool headless = true);
  320. // Enables the validation layers. Will fail to create an instance if the validation layers aren't available.
  321. InstanceBuilder& enable_validation_layers(bool require_validation = true);
  322. // Checks if the validation layers are available and loads them if they are.
  323. InstanceBuilder& request_validation_layers(bool enable_validation = true);
  324. // Use a default debug callback that prints to standard out.
  325. InstanceBuilder& use_default_debug_messenger();
  326. // Provide a user defined debug callback.
  327. InstanceBuilder& set_debug_callback(PFN_vkDebugUtilsMessengerCallbackEXT callback);
  328. // Sets the void* to use in the debug messenger - only useful with a custom callback
  329. InstanceBuilder& set_debug_callback_user_data_pointer(void* user_data_pointer);
  330. // Set what message severity is needed to trigger the callback.
  331. InstanceBuilder& set_debug_messenger_severity(VkDebugUtilsMessageSeverityFlagsEXT severity);
  332. // Add a message severity to the list that triggers the callback.
  333. InstanceBuilder& add_debug_messenger_severity(VkDebugUtilsMessageSeverityFlagsEXT severity);
  334. // Set what message type triggers the callback.
  335. InstanceBuilder& set_debug_messenger_type(VkDebugUtilsMessageTypeFlagsEXT type);
  336. // Add a message type to the list of that triggers the callback.
  337. InstanceBuilder& add_debug_messenger_type(VkDebugUtilsMessageTypeFlagsEXT type);
  338. // Disable some validation checks.
  339. // Checks: All, and Shaders
  340. InstanceBuilder& add_validation_disable(VkValidationCheckEXT check);
  341. // Enables optional parts of the validation layers.
  342. // Parts: best practices, gpu assisted, and gpu assisted reserve binding slot.
  343. InstanceBuilder& add_validation_feature_enable(VkValidationFeatureEnableEXT enable);
  344. // Disables sections of the validation layers.
  345. // Options: All, shaders, thread safety, api parameters, object lifetimes, core checks, and unique handles.
  346. InstanceBuilder& add_validation_feature_disable(VkValidationFeatureDisableEXT disable);
  347. // Provide custom allocation callbacks.
  348. InstanceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
  349. private:
  350. struct InstanceInfo {
  351. // VkApplicationInfo
  352. const char* app_name = nullptr;
  353. const char* engine_name = nullptr;
  354. uint32_t application_version = 0;
  355. uint32_t engine_version = 0;
  356. uint32_t minimum_instance_version = 0;
  357. uint32_t required_api_version = VKB_VK_API_VERSION_1_0;
  358. uint32_t desired_api_version = VKB_VK_API_VERSION_1_0;
  359. // VkInstanceCreateInfo
  360. std::vector<const char*> layers;
  361. std::vector<const char*> extensions;
  362. VkInstanceCreateFlags flags = static_cast<VkInstanceCreateFlags>(0);
  363. std::vector<VkBaseOutStructure*> pNext_elements;
  364. // debug callback - use the default so it is not nullptr
  365. PFN_vkDebugUtilsMessengerCallbackEXT debug_callback = default_debug_callback;
  366. VkDebugUtilsMessageSeverityFlagsEXT debug_message_severity =
  367. VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
  368. VkDebugUtilsMessageTypeFlagsEXT debug_message_type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
  369. VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
  370. VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
  371. void* debug_user_data_pointer = nullptr;
  372. // validation features
  373. std::vector<VkValidationCheckEXT> disabled_validation_checks;
  374. std::vector<VkValidationFeatureEnableEXT> enabled_validation_features;
  375. std::vector<VkValidationFeatureDisableEXT> disabled_validation_features;
  376. // Custom allocator
  377. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  378. bool request_validation_layers = false;
  379. bool enable_validation_layers = false;
  380. bool use_debug_messenger = false;
  381. bool headless_context = false;
  382. PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
  383. } info;
  384. };
  385. VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
  386. VkDebugUtilsMessageTypeFlagsEXT messageType,
  387. const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
  388. void* pUserData);
  389. void destroy_debug_utils_messenger(
  390. VkInstance const instance, VkDebugUtilsMessengerEXT const messenger, VkAllocationCallbacks* allocation_callbacks = nullptr);
  391. // ---- Physical Device ---- //
  392. class PhysicalDeviceSelector;
  393. class DeviceBuilder;
  394. struct PhysicalDevice {
  395. std::string name;
  396. VkPhysicalDevice physical_device = VK_NULL_HANDLE;
  397. VkSurfaceKHR surface = VK_NULL_HANDLE;
  398. // Note that this reflects selected features carried over from required features, not all features the physical device supports.
  399. VkPhysicalDeviceFeatures features{};
  400. VkPhysicalDeviceProperties properties{};
  401. VkPhysicalDeviceMemoryProperties memory_properties{};
  402. // Has a queue family that supports compute operations but not graphics nor transfer.
  403. bool has_dedicated_compute_queue() const;
  404. // Has a queue family that supports transfer operations but not graphics nor compute.
  405. bool has_dedicated_transfer_queue() const;
  406. // Has a queue family that supports transfer operations but not graphics.
  407. bool has_separate_compute_queue() const;
  408. // Has a queue family that supports transfer operations but not graphics.
  409. bool has_separate_transfer_queue() const;
  410. // Advanced: Get the VkQueueFamilyProperties of the device if special queue setup is needed
  411. std::vector<VkQueueFamilyProperties> get_queue_families() const;
  412. // Query the list of extensions which should be enabled
  413. std::vector<std::string> get_extensions() const;
  414. // A conversion function which allows this PhysicalDevice to be used
  415. // in places where VkPhysicalDevice would have been used.
  416. operator VkPhysicalDevice() const;
  417. private:
  418. uint32_t instance_version = VKB_VK_API_VERSION_1_0;
  419. std::vector<std::string> extensions;
  420. std::vector<VkQueueFamilyProperties> queue_families;
  421. std::vector<detail::GenericFeaturesPNextNode> extended_features_chain;
  422. VkPhysicalDeviceFeatures2 features2{};
  423. bool defer_surface_initialization = false;
  424. bool properties2_ext_enabled = false;
  425. enum class Suitable { yes, partial, no };
  426. Suitable suitable = Suitable::yes;
  427. friend class PhysicalDeviceSelector;
  428. friend class DeviceBuilder;
  429. };
  430. enum class PreferredDeviceType { other = 0, integrated = 1, discrete = 2, virtual_gpu = 3, cpu = 4 };
  431. enum class DeviceSelectionMode {
  432. // return all suitable and partially suitable devices
  433. partially_and_fully_suitable,
  434. // return only physical devices which are fully suitable
  435. only_fully_suitable
  436. };
  437. // Enumerates the physical devices on the system, and based on the added criteria, returns a physical device or list of physical devies
  438. // A device is considered suitable if it meets all the 'required' and 'desired' criteria.
  439. // A device is considered partially suitable if it meets only the 'required' criteria.
  440. class PhysicalDeviceSelector {
  441. public:
  442. // Requires a vkb::Instance to construct, needed to pass instance creation info.
  443. explicit PhysicalDeviceSelector(Instance const& instance);
  444. // Requires a vkb::Instance to construct, needed to pass instance creation info, optionally specify the surface here
  445. explicit PhysicalDeviceSelector(Instance const& instance, VkSurfaceKHR surface);
  446. // Return the first device which is suitable
  447. // use the `selection` parameter to configure if partially
  448. Result<PhysicalDevice> select(DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const;
  449. // Return all devices which are considered suitable - intended for applications which want to let the user pick the physical device
  450. Result<std::vector<PhysicalDevice>> select_devices(
  451. DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const;
  452. // Return the names of all devices which are considered suitable - intended for applications which want to let the user pick the physical device
  453. Result<std::vector<std::string>> select_device_names(
  454. DeviceSelectionMode selection = DeviceSelectionMode::partially_and_fully_suitable) const;
  455. // Set the surface in which the physical device should render to.
  456. // Be sure to set it if swapchain functionality is to be used.
  457. PhysicalDeviceSelector& set_surface(VkSurfaceKHR surface);
  458. // Set the name of the device to select.
  459. PhysicalDeviceSelector& set_name(std::string const& name);
  460. // Set the desired physical device type to select. Defaults to PreferredDeviceType::discrete.
  461. PhysicalDeviceSelector& prefer_gpu_device_type(PreferredDeviceType type = PreferredDeviceType::discrete);
  462. // Allow selection of a gpu device type that isn't the preferred physical device type. Defaults to true.
  463. PhysicalDeviceSelector& allow_any_gpu_device_type(bool allow_any_type = true);
  464. // Require that a physical device supports presentation. Defaults to true.
  465. PhysicalDeviceSelector& require_present(bool require = true);
  466. // Require a queue family that supports compute operations but not graphics nor transfer.
  467. PhysicalDeviceSelector& require_dedicated_compute_queue();
  468. // Require a queue family that supports transfer operations but not graphics nor compute.
  469. PhysicalDeviceSelector& require_dedicated_transfer_queue();
  470. // Require a queue family that supports compute operations but not graphics.
  471. PhysicalDeviceSelector& require_separate_compute_queue();
  472. // Require a queue family that supports transfer operations but not graphics.
  473. PhysicalDeviceSelector& require_separate_transfer_queue();
  474. // Require a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available.
  475. PhysicalDeviceSelector& required_device_memory_size(VkDeviceSize size);
  476. // Prefer a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available.
  477. PhysicalDeviceSelector& desired_device_memory_size(VkDeviceSize size);
  478. // Require a physical device which supports a specific extension.
  479. PhysicalDeviceSelector& add_required_extension(const char* extension);
  480. // Require a physical device which supports a set of extensions.
  481. PhysicalDeviceSelector& add_required_extensions(std::vector<const char*> extensions);
  482. // Prefer a physical device which supports a specific extension.
  483. PhysicalDeviceSelector& add_desired_extension(const char* extension);
  484. // Prefer a physical device which supports a set of extensions.
  485. PhysicalDeviceSelector& add_desired_extensions(std::vector<const char*> extensions);
  486. // Prefer a physical device that supports a (major, minor) version of vulkan.
  487. [[deprecated("Use set_minimum_version + InstanceBuilder::require_api_version.")]] PhysicalDeviceSelector&
  488. set_desired_version(uint32_t major, uint32_t minor);
  489. // Require a physical device that supports a (major, minor) version of vulkan.
  490. PhysicalDeviceSelector& set_minimum_version(uint32_t major, uint32_t minor);
  491. // By default PhysicalDeviceSelector enables the portability subset if available
  492. // This function disables that behavior
  493. PhysicalDeviceSelector& disable_portability_subset();
  494. // Require a physical device which supports a specific set of general/extension features.
  495. // If this function is used, the user should not put their own VkPhysicalDeviceFeatures2 in
  496. // the pNext chain of VkDeviceCreateInfo.
  497. template <typename T> PhysicalDeviceSelector& add_required_extension_features(T const& features) {
  498. criteria.extended_features_chain.push_back(features);
  499. return *this;
  500. }
  501. // Require a physical device which supports the features in VkPhysicalDeviceFeatures.
  502. PhysicalDeviceSelector& set_required_features(VkPhysicalDeviceFeatures const& features);
  503. #if defined(VKB_VK_API_VERSION_1_2)
  504. // Require a physical device which supports the features in VkPhysicalDeviceVulkan11Features.
  505. // Must have vulkan version 1.2 - This is due to the VkPhysicalDeviceVulkan11Features struct being added in 1.2, not 1.1
  506. PhysicalDeviceSelector& set_required_features_11(VkPhysicalDeviceVulkan11Features features_11);
  507. // Require a physical device which supports the features in VkPhysicalDeviceVulkan12Features.
  508. // Must have vulkan version 1.2
  509. PhysicalDeviceSelector& set_required_features_12(VkPhysicalDeviceVulkan12Features features_12);
  510. #endif
  511. #if defined(VKB_VK_API_VERSION_1_3)
  512. // Require a physical device which supports the features in VkPhysicalDeviceVulkan13Features.
  513. // Must have vulkan version 1.3
  514. PhysicalDeviceSelector& set_required_features_13(VkPhysicalDeviceVulkan13Features features_13);
  515. #endif
  516. // Used when surface creation happens after physical device selection.
  517. // Warning: This disables checking if the physical device supports a given surface.
  518. PhysicalDeviceSelector& defer_surface_initialization();
  519. // Ignore all criteria and choose the first physical device that is available.
  520. // Only use when: The first gpu in the list may be set by global user preferences and an application may wish to respect it.
  521. PhysicalDeviceSelector& select_first_device_unconditionally(bool unconditionally = true);
  522. private:
  523. struct InstanceInfo {
  524. VkInstance instance = VK_NULL_HANDLE;
  525. VkSurfaceKHR surface = VK_NULL_HANDLE;
  526. uint32_t version = VKB_VK_API_VERSION_1_0;
  527. bool headless = false;
  528. bool properties2_ext_enabled = false;
  529. } instance_info;
  530. // We copy the extension features stored in the selector criteria under the prose of a
  531. // "template" to ensure that after fetching everything is compared 1:1 during a match.
  532. struct SelectionCriteria {
  533. std::string name;
  534. PreferredDeviceType preferred_type = PreferredDeviceType::discrete;
  535. bool allow_any_type = true;
  536. bool require_present = true;
  537. bool require_dedicated_transfer_queue = false;
  538. bool require_dedicated_compute_queue = false;
  539. bool require_separate_transfer_queue = false;
  540. bool require_separate_compute_queue = false;
  541. VkDeviceSize required_mem_size = 0;
  542. VkDeviceSize desired_mem_size = 0;
  543. std::vector<std::string> required_extensions;
  544. std::vector<std::string> desired_extensions;
  545. uint32_t required_version = VKB_VK_API_VERSION_1_0;
  546. uint32_t desired_version = VKB_VK_API_VERSION_1_0;
  547. VkPhysicalDeviceFeatures required_features{};
  548. VkPhysicalDeviceFeatures2 required_features2{};
  549. std::vector<detail::GenericFeaturesPNextNode> extended_features_chain;
  550. bool defer_surface_initialization = false;
  551. bool use_first_gpu_unconditionally = false;
  552. bool enable_portability_subset = true;
  553. } criteria;
  554. PhysicalDevice populate_device_details(VkPhysicalDevice phys_device,
  555. std::vector<detail::GenericFeaturesPNextNode> const& src_extended_features_chain) const;
  556. PhysicalDevice::Suitable is_device_suitable(PhysicalDevice const& phys_device) const;
  557. Result<std::vector<PhysicalDevice>> select_impl(DeviceSelectionMode selection) const;
  558. };
  559. // ---- Queue ---- //
  560. enum class QueueType { present, graphics, compute, transfer };
  561. namespace detail {
  562. // Sentinel value, used in implementation only
  563. const uint32_t QUEUE_INDEX_MAX_VALUE = 65536;
  564. } // namespace detail
  565. // ---- Device ---- //
  566. struct Device {
  567. VkDevice device = VK_NULL_HANDLE;
  568. PhysicalDevice physical_device;
  569. VkSurfaceKHR surface = VK_NULL_HANDLE;
  570. std::vector<VkQueueFamilyProperties> queue_families;
  571. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  572. PFN_vkGetDeviceProcAddr fp_vkGetDeviceProcAddr = nullptr;
  573. uint32_t instance_version = VKB_VK_API_VERSION_1_0;
  574. Result<uint32_t> get_queue_index(QueueType type) const;
  575. // Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue index
  576. Result<uint32_t> get_dedicated_queue_index(QueueType type) const;
  577. Result<VkQueue> get_queue(QueueType type) const;
  578. // Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue
  579. Result<VkQueue> get_dedicated_queue(QueueType type) const;
  580. // Return a loaded dispatch table
  581. DispatchTable make_table() const;
  582. // A conversion function which allows this Device to be used
  583. // in places where VkDevice would have been used.
  584. operator VkDevice() const;
  585. private:
  586. struct {
  587. PFN_vkGetDeviceQueue fp_vkGetDeviceQueue = nullptr;
  588. PFN_vkDestroyDevice fp_vkDestroyDevice = nullptr;
  589. } internal_table;
  590. friend class DeviceBuilder;
  591. friend void destroy_device(Device device);
  592. };
  593. // For advanced device queue setup
  594. struct CustomQueueDescription {
  595. explicit CustomQueueDescription(uint32_t index, uint32_t count, std::vector<float> priorities);
  596. uint32_t index = 0;
  597. uint32_t count = 0;
  598. std::vector<float> priorities;
  599. };
  600. void destroy_device(Device device);
  601. class DeviceBuilder {
  602. public:
  603. // Any features and extensions that are requested/required in PhysicalDeviceSelector are automatically enabled.
  604. explicit DeviceBuilder(PhysicalDevice physical_device);
  605. Result<Device> build() const;
  606. // For Advanced Users: specify the exact list of VkDeviceQueueCreateInfo's needed for the application.
  607. // If a custom queue setup is provided, getting the queues and queue indexes is up to the application.
  608. DeviceBuilder& custom_queue_setup(std::vector<CustomQueueDescription> queue_descriptions);
  609. // Add a structure to the pNext chain of VkDeviceCreateInfo.
  610. // The structure must be valid when DeviceBuilder::build() is called.
  611. template <typename T> DeviceBuilder& add_pNext(T* structure) {
  612. info.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
  613. return *this;
  614. }
  615. // Provide custom allocation callbacks.
  616. DeviceBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
  617. private:
  618. PhysicalDevice physical_device;
  619. struct DeviceInfo {
  620. VkDeviceCreateFlags flags = static_cast<VkDeviceCreateFlags>(0);
  621. std::vector<VkBaseOutStructure*> pNext_chain;
  622. std::vector<CustomQueueDescription> queue_descriptions;
  623. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  624. } info;
  625. };
  626. // ---- Swapchain ---- //
  627. struct Swapchain {
  628. VkDevice device = VK_NULL_HANDLE;
  629. VkSwapchainKHR swapchain = VK_NULL_HANDLE;
  630. uint32_t image_count = 0;
  631. VkFormat image_format = VK_FORMAT_UNDEFINED; // The image format actually used when creating the swapchain.
  632. VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; // The color space actually used when creating the swapchain.
  633. VkImageUsageFlags image_usage_flags = 0;
  634. VkExtent2D extent = { 0, 0 };
  635. // The value of minImageCount actually used when creating the swapchain; note that the presentation engine is always free to create more images than that.
  636. uint32_t requested_min_image_count = 0;
  637. VkPresentModeKHR present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; // The present mode actually used when creating the swapchain.
  638. uint32_t instance_version = VKB_VK_API_VERSION_1_0;
  639. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  640. // Returns a vector of VkImage handles to the swapchain.
  641. Result<std::vector<VkImage>> get_images();
  642. // Returns a vector of VkImageView's to the VkImage's of the swapchain.
  643. // VkImageViews must be destroyed. The pNext chain must be a nullptr or a valid
  644. // structure.
  645. Result<std::vector<VkImageView>> get_image_views();
  646. Result<std::vector<VkImageView>> get_image_views(const void* pNext);
  647. void destroy_image_views(std::vector<VkImageView> const& image_views);
  648. // A conversion function which allows this Swapchain to be used
  649. // in places where VkSwapchainKHR would have been used.
  650. operator VkSwapchainKHR() const;
  651. private:
  652. struct {
  653. PFN_vkGetSwapchainImagesKHR fp_vkGetSwapchainImagesKHR = nullptr;
  654. PFN_vkCreateImageView fp_vkCreateImageView = nullptr;
  655. PFN_vkDestroyImageView fp_vkDestroyImageView = nullptr;
  656. PFN_vkDestroySwapchainKHR fp_vkDestroySwapchainKHR = nullptr;
  657. } internal_table;
  658. friend class SwapchainBuilder;
  659. friend void destroy_swapchain(Swapchain const& swapchain);
  660. };
  661. void destroy_swapchain(Swapchain const& swapchain);
  662. class SwapchainBuilder {
  663. public:
  664. // Construct a SwapchainBuilder with a `vkb::Device`
  665. explicit SwapchainBuilder(Device const& device);
  666. // Construct a SwapchainBuilder with a specific VkSurfaceKHR handle and `vkb::Device`
  667. explicit SwapchainBuilder(Device const& device, VkSurfaceKHR const surface);
  668. // Construct a SwapchainBuilder with Vulkan handles for the physical device, device, and surface
  669. // Optionally can provide the uint32_t indices for the graphics and present queue
  670. // Note: The constructor will query the graphics & present queue if the indices are not provided
  671. explicit SwapchainBuilder(VkPhysicalDevice const physical_device,
  672. VkDevice const device,
  673. VkSurfaceKHR const surface,
  674. uint32_t graphics_queue_index = detail::QUEUE_INDEX_MAX_VALUE,
  675. uint32_t present_queue_index = detail::QUEUE_INDEX_MAX_VALUE);
  676. Result<Swapchain> build() const;
  677. // Set the oldSwapchain member of VkSwapchainCreateInfoKHR.
  678. // For use in rebuilding a swapchain.
  679. SwapchainBuilder& set_old_swapchain(VkSwapchainKHR old_swapchain);
  680. SwapchainBuilder& set_old_swapchain(Swapchain const& swapchain);
  681. // Desired size of the swapchain. By default, the swapchain will use the size
  682. // of the window being drawn to.
  683. SwapchainBuilder& set_desired_extent(uint32_t width, uint32_t height);
  684. // When determining the surface format, make this the first to be used if supported.
  685. SwapchainBuilder& set_desired_format(VkSurfaceFormatKHR format);
  686. // Add this swapchain format to the end of the list of formats selected from.
  687. SwapchainBuilder& add_fallback_format(VkSurfaceFormatKHR format);
  688. // Use the default swapchain formats. This is done if no formats are provided.
  689. // Default surface format is {VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}
  690. SwapchainBuilder& use_default_format_selection();
  691. // When determining the present mode, make this the first to be used if supported.
  692. SwapchainBuilder& set_desired_present_mode(VkPresentModeKHR present_mode);
  693. // Add this present mode to the end of the list of present modes selected from.
  694. SwapchainBuilder& add_fallback_present_mode(VkPresentModeKHR present_mode);
  695. // Use the default presentation mode. This is done if no present modes are provided.
  696. // Default present modes: VK_PRESENT_MODE_MAILBOX_KHR with fallback VK_PRESENT_MODE_FIFO_KHR
  697. SwapchainBuilder& use_default_present_mode_selection();
  698. // Set the bitmask of the image usage for acquired swapchain images.
  699. // If the surface capabilities cannot allow it, building the swapchain will result in the `SwapchainError::required_usage_not_supported` error.
  700. SwapchainBuilder& set_image_usage_flags(VkImageUsageFlags usage_flags);
  701. // Add a image usage to the bitmask for acquired swapchain images.
  702. SwapchainBuilder& add_image_usage_flags(VkImageUsageFlags usage_flags);
  703. // Use the default image usage bitmask values. This is the default if no image usages
  704. // are provided. The default is VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
  705. SwapchainBuilder& use_default_image_usage_flags();
  706. // Set the number of views in for multiview/stereo surface
  707. SwapchainBuilder& set_image_array_layer_count(uint32_t array_layer_count);
  708. // Convenient named constants for passing to set_desired_min_image_count().
  709. // Note that it is not an `enum class`, so its constants can be passed as an integer value without casting
  710. // In other words, these might as well be `static const int`, but they benefit from being grouped together this way.
  711. enum BufferMode {
  712. SINGLE_BUFFERING = 1,
  713. DOUBLE_BUFFERING = 2,
  714. TRIPLE_BUFFERING = 3,
  715. };
  716. // Sets the desired minimum image count for the swapchain.
  717. // Note that the presentation engine is always free to create more images than requested.
  718. // You may pass one of the values specified in the BufferMode enum, or any integer value.
  719. // For instance, if you pass DOUBLE_BUFFERING, the presentation engine is allowed to give you a double buffering setup, triple buffering, or more. This is up to the drivers.
  720. SwapchainBuilder& set_desired_min_image_count(uint32_t min_image_count);
  721. // Sets a required minimum image count for the swapchain.
  722. // If the surface capabilities cannot allow it, building the swapchain will result in the `SwapchainError::required_min_image_count_too_low` error.
  723. // Otherwise, the same observations from set_desired_min_image_count() apply.
  724. // A value of 0 is specially interpreted as meaning "no requirement", and is the behavior by default.
  725. SwapchainBuilder& set_required_min_image_count(uint32_t required_min_image_count);
  726. // Set whether the Vulkan implementation is allowed to discard rendering operations that
  727. // affect regions of the surface that are not visible. Default is true.
  728. // Note: Applications should use the default of true if they do not expect to read back the content
  729. // of presentable images before presenting them or after reacquiring them, and if their fragment
  730. // shaders do not have any side effects that require them to run for all pixels in the presentable image.
  731. SwapchainBuilder& set_clipped(bool clipped = true);
  732. // Set the VkSwapchainCreateFlagBitsKHR.
  733. SwapchainBuilder& set_create_flags(VkSwapchainCreateFlagBitsKHR create_flags);
  734. // Set the transform to be applied, like a 90 degree rotation. Default is no transform.
  735. SwapchainBuilder& set_pre_transform_flags(VkSurfaceTransformFlagBitsKHR pre_transform_flags);
  736. // Set the alpha channel to be used with other windows in on the system. Default is VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR.
  737. SwapchainBuilder& set_composite_alpha_flags(VkCompositeAlphaFlagBitsKHR composite_alpha_flags);
  738. // Add a structure to the pNext chain of VkSwapchainCreateInfoKHR.
  739. // The structure must be valid when SwapchainBuilder::build() is called.
  740. template <typename T> SwapchainBuilder& add_pNext(T* structure) {
  741. info.pNext_chain.push_back(reinterpret_cast<VkBaseOutStructure*>(structure));
  742. return *this;
  743. }
  744. // Provide custom allocation callbacks.
  745. SwapchainBuilder& set_allocation_callbacks(VkAllocationCallbacks* callbacks);
  746. private:
  747. void add_desired_formats(std::vector<VkSurfaceFormatKHR>& formats) const;
  748. void add_desired_present_modes(std::vector<VkPresentModeKHR>& modes) const;
  749. struct SwapchainInfo {
  750. VkPhysicalDevice physical_device = VK_NULL_HANDLE;
  751. VkDevice device = VK_NULL_HANDLE;
  752. std::vector<VkBaseOutStructure*> pNext_chain;
  753. VkSwapchainCreateFlagBitsKHR create_flags = static_cast<VkSwapchainCreateFlagBitsKHR>(0);
  754. VkSurfaceKHR surface = VK_NULL_HANDLE;
  755. std::vector<VkSurfaceFormatKHR> desired_formats;
  756. uint32_t instance_version = VKB_VK_API_VERSION_1_0;
  757. uint32_t desired_width = 256;
  758. uint32_t desired_height = 256;
  759. uint32_t array_layer_count = 1;
  760. uint32_t min_image_count = 0;
  761. uint32_t required_min_image_count = 0;
  762. VkImageUsageFlags image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  763. uint32_t graphics_queue_index = 0;
  764. uint32_t present_queue_index = 0;
  765. VkSurfaceTransformFlagBitsKHR pre_transform = static_cast<VkSurfaceTransformFlagBitsKHR>(0);
  766. #if defined(__ANDROID__)
  767. VkCompositeAlphaFlagBitsKHR composite_alpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
  768. #else
  769. VkCompositeAlphaFlagBitsKHR composite_alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  770. #endif
  771. std::vector<VkPresentModeKHR> desired_present_modes;
  772. bool clipped = true;
  773. VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
  774. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  775. } info;
  776. };
  777. } // namespace vkb
  778. namespace std {
  779. template <> struct is_error_code_enum<vkb::InstanceError> : true_type {};
  780. template <> struct is_error_code_enum<vkb::PhysicalDeviceError> : true_type {};
  781. template <> struct is_error_code_enum<vkb::QueueError> : true_type {};
  782. template <> struct is_error_code_enum<vkb::DeviceError> : true_type {};
  783. template <> struct is_error_code_enum<vkb::SwapchainError> : true_type {};
  784. } // namespace std