VkBootstrap.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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 <vector>
  19. #include <system_error>
  20. #include <vulkan/vulkan.h>
  21. namespace vkb {
  22. namespace detail {
  23. struct Error {
  24. std::error_code type;
  25. VkResult vk_result = VK_SUCCESS; // optional error value if a vulkan call failed
  26. };
  27. template <typename T> class Result {
  28. public:
  29. Result (const T& value) : m_value{ value }, m_init{ true } {}
  30. Result (T&& value) : m_value{ std::move (value) }, m_init{ true } {}
  31. Result (Error error) : m_error{ error }, m_init{ false } {}
  32. Result (std::error_code error_code, VkResult result = VK_SUCCESS)
  33. : m_error{ error_code, result }, m_init{ false } {}
  34. ~Result () { destroy (); }
  35. Result (Result const& expected) : m_init (expected.m_init) {
  36. if (m_init)
  37. new (&m_value) T{ expected.m_value };
  38. else
  39. m_error = expected.m_error;
  40. }
  41. Result (Result&& expected) : m_init (expected.m_init) {
  42. if (m_init)
  43. new (&m_value) T{ std::move (expected.m_value) };
  44. else
  45. m_error = std::move (expected.m_error);
  46. expected.destroy ();
  47. }
  48. Result& operator= (const T& expect) {
  49. destroy ();
  50. m_init = true;
  51. new (&m_value) T{ expect };
  52. return *this;
  53. }
  54. Result& operator= (T&& expect) {
  55. destroy ();
  56. m_init = true;
  57. new (&m_value) T{ std::move (expect) };
  58. return *this;
  59. }
  60. Result& operator= (const Error& error) {
  61. destroy ();
  62. m_init = false;
  63. m_error = error;
  64. return *this;
  65. }
  66. Result& operator= (Error&& error) {
  67. destroy ();
  68. m_init = false;
  69. m_error = error;
  70. return *this;
  71. }
  72. // clang-format off
  73. const T* operator-> () const { assert (m_init); return &m_value; }
  74. T* operator-> () { assert (m_init); return &m_value; }
  75. const T& operator* () const& { assert (m_init); return m_value; }
  76. T& operator* () & { assert (m_init); return m_value; }
  77. T&& operator* () && { assert (m_init); return std::move (m_value); }
  78. const T& value () const& { assert (m_init); return m_value; }
  79. T& value () & { assert (m_init); return m_value; }
  80. const T&& value () const&& { assert (m_init); return std::move (m_value); }
  81. T&& value () && { assert (m_init); return std::move (m_value); }
  82. std::error_code error() const { assert (!m_init); return m_error.type; }
  83. VkResult vk_result() const { assert (!m_init); return m_error.vk_result; }
  84. // clang-format on
  85. bool has_value () const { return m_init; }
  86. explicit operator bool () const { return m_init; }
  87. private:
  88. void destroy () {
  89. if (m_init) m_value.~T ();
  90. }
  91. union {
  92. T m_value;
  93. Error m_error;
  94. };
  95. bool m_init;
  96. };
  97. } // namespace detail
  98. enum class InstanceError {
  99. vulkan_unavailable,
  100. vulkan_version_unavailable,
  101. vulkan_version_1_1_unavailable,
  102. vulkan_version_1_2_unavailable,
  103. failed_create_instance,
  104. failed_create_debug_messenger,
  105. requested_layers_not_present,
  106. requested_extensions_not_present,
  107. windowing_extensions_not_present,
  108. };
  109. enum class PhysicalDeviceError {
  110. no_surface_provided,
  111. failed_enumerate_physical_devices,
  112. no_physical_devices_found,
  113. no_suitable_device,
  114. };
  115. enum class QueueError {
  116. present_unavailable,
  117. graphics_unavailable,
  118. compute_unavailable,
  119. transfer_unavailable,
  120. queue_index_out_of_range,
  121. invalid_queue_family_index
  122. };
  123. enum class DeviceError {
  124. failed_create_device,
  125. };
  126. enum class SwapchainError {
  127. surface_handle_not_provided,
  128. failed_query_surface_support_details,
  129. failed_create_swapchain,
  130. failed_get_swapchain_images,
  131. failed_create_swapchain_image_views,
  132. };
  133. std::error_code make_error_code (InstanceError instance_error);
  134. std::error_code make_error_code (PhysicalDeviceError physical_device_error);
  135. std::error_code make_error_code (QueueError queue_error);
  136. std::error_code make_error_code (DeviceError device_error);
  137. std::error_code make_error_code (SwapchainError swapchain_error);
  138. const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s);
  139. const char* to_string_message_type (VkDebugUtilsMessageTypeFlagsEXT s);
  140. const char* to_string (InstanceError err);
  141. const char* to_string (PhysicalDeviceError err);
  142. const char* to_string (QueueError err);
  143. const char* to_string (DeviceError err);
  144. const char* to_string (SwapchainError err);
  145. // Gathers useful information about the available vulkan capabilities, like layers and instance extensions.
  146. // Use this for enabling features conditionally, ie if you would like an extension but can use a fallback if
  147. // it isn't supported but need to know if support is available first.
  148. struct SystemInfo {
  149. private:
  150. SystemInfo ();
  151. public:
  152. // Use get_system_info to create a SystemInfo struct. This is because loading vulkan could fail.
  153. static detail::Result<SystemInfo> get_system_info ();
  154. static detail::Result<SystemInfo> get_system_info (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
  155. // Returns true if a layer is available
  156. bool is_layer_available (const char* layer_name) const;
  157. // Returns true if an extension is available
  158. bool is_extension_available (const char* extension_name) const;
  159. std::vector<VkLayerProperties> available_layers;
  160. std::vector<VkExtensionProperties> available_extensions;
  161. bool validation_layers_available = false;
  162. bool debug_utils_available = false;
  163. };
  164. class InstanceBuilder;
  165. class PhysicalDeviceSelector;
  166. struct Instance {
  167. VkInstance instance = VK_NULL_HANDLE;
  168. VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
  169. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  170. PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
  171. private:
  172. bool headless = false;
  173. uint32_t instance_version = VK_MAKE_VERSION (1, 0, 0);
  174. friend class InstanceBuilder;
  175. friend class PhysicalDeviceSelector;
  176. };
  177. void destroy_instance (Instance instance); // release instance resources
  178. class InstanceBuilder {
  179. public:
  180. // Default constructor, will load vulkan.
  181. explicit InstanceBuilder ();
  182. // Optional: Can use your own PFN_vkGetInstanceProcAddr
  183. explicit InstanceBuilder (PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr);
  184. // Create a VkInstance. Return an error if it failed.
  185. detail::Result<Instance> build () const;
  186. // Sets the name of the application. Defaults to "" if none is provided.
  187. InstanceBuilder& set_app_name (const char* app_name);
  188. // Sets the name of the engine. Defaults to "" if none is provided.
  189. InstanceBuilder& set_engine_name (const char* engine_name);
  190. // Sets the (major, minor, patch) version of the application.
  191. InstanceBuilder& set_app_version (uint32_t major, uint32_t minor, uint32_t patch = 0);
  192. // Sets the (major, minor, patch) version of the engine.
  193. InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch = 0);
  194. // Require a vulkan instance API version. Will fail to create if this version isn't available.
  195. InstanceBuilder& require_api_version (uint32_t major, uint32_t minor, uint32_t patch = 0);
  196. // Prefer a vulkan instance API version. If the desired version isn't available, it will use the highest version available.
  197. InstanceBuilder& desire_api_version (uint32_t major, uint32_t minor, uint32_t patch = 0);
  198. // Adds a layer to be enabled. Will fail to create an instance if the layer isn't available.
  199. InstanceBuilder& enable_layer (const char* layer_name);
  200. // Adds an extension to be enabled. Will fail to create an instance if the extension isn't available.
  201. InstanceBuilder& enable_extension (const char* extension_name);
  202. // Headless Mode does not load the required extensions for presentation. Defaults to true.
  203. InstanceBuilder& set_headless (bool headless = true);
  204. // Enables the validation layers. Will fail to create an instance if the validation layers aren't available.
  205. InstanceBuilder& enable_validation_layers (bool require_validation = true);
  206. // Checks if the validation layers are available and loads them if they are.
  207. InstanceBuilder& request_validation_layers (bool enable_validation = true);
  208. // Use a default debug callback that prints to standard out.
  209. InstanceBuilder& use_default_debug_messenger ();
  210. // Provide a user defined debug callback.
  211. InstanceBuilder& set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback);
  212. // Set what message severity is needed to trigger the callback.
  213. InstanceBuilder& set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
  214. // Add a message severity to the list that triggers the callback.
  215. InstanceBuilder& add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity);
  216. // Set what message type triggers the callback.
  217. InstanceBuilder& set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
  218. // Add a message type to the list of that triggers the callback.
  219. InstanceBuilder& add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type);
  220. // Disable some validation checks.
  221. // Checks: All, and Shaders
  222. InstanceBuilder& add_validation_disable (VkValidationCheckEXT check);
  223. // Enables optional parts of the validation layers.
  224. // Parts: best practices, gpu assisted, and gpu assisted reserve binding slot.
  225. InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable);
  226. // Disables sections of the validation layers.
  227. // Options: All, shaders, thread safety, api parameters, object lifetimes, core checks, and unique handles.
  228. InstanceBuilder& add_validation_feature_disable (VkValidationFeatureDisableEXT disable);
  229. // Provide custom allocation callbacks.
  230. InstanceBuilder& set_allocation_callbacks (VkAllocationCallbacks* callbacks);
  231. private:
  232. struct InstanceInfo {
  233. // VkApplicationInfo
  234. const char* app_name = nullptr;
  235. const char* engine_name = nullptr;
  236. uint32_t application_version = 0;
  237. uint32_t engine_version = 0;
  238. uint32_t required_api_version = VK_MAKE_VERSION (1, 0, 0);
  239. uint32_t desired_api_version = VK_MAKE_VERSION (1, 0, 0);
  240. // VkInstanceCreateInfo
  241. std::vector<const char*> layers;
  242. std::vector<const char*> extensions;
  243. VkInstanceCreateFlags flags = 0;
  244. std::vector<VkBaseOutStructure*> pNext_elements;
  245. // debug callback
  246. PFN_vkDebugUtilsMessengerCallbackEXT debug_callback = nullptr;
  247. VkDebugUtilsMessageSeverityFlagsEXT debug_message_severity =
  248. VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
  249. VkDebugUtilsMessageTypeFlagsEXT debug_message_type =
  250. VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
  251. VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
  252. // validation features
  253. std::vector<VkValidationCheckEXT> disabled_validation_checks;
  254. std::vector<VkValidationFeatureEnableEXT> enabled_validation_features;
  255. std::vector<VkValidationFeatureDisableEXT> disabled_validation_features;
  256. // Custom allocator
  257. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  258. bool request_validation_layers = false;
  259. bool enable_validation_layers = false;
  260. bool use_debug_messenger = false;
  261. bool headless_context = false;
  262. PFN_vkGetInstanceProcAddr fp_vkGetInstanceProcAddr = nullptr;
  263. } info;
  264. };
  265. VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
  266. VkDebugUtilsMessageTypeFlagsEXT messageType,
  267. const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
  268. void* pUserData);
  269. void destroy_debug_utils_messenger(VkInstance const instance, VkDebugUtilsMessengerEXT const messenger, VkAllocationCallbacks* allocation_callbacks = nullptr);
  270. // ---- Physical Device ---- //
  271. class PhysicalDeviceSelector;
  272. class DeviceBuilder;
  273. struct PhysicalDevice {
  274. VkPhysicalDevice physical_device = VK_NULL_HANDLE;
  275. VkSurfaceKHR surface = VK_NULL_HANDLE;
  276. VkPhysicalDeviceFeatures features{};
  277. VkPhysicalDeviceProperties properties{};
  278. VkPhysicalDeviceMemoryProperties memory_properties{};
  279. // Has a queue family that supports compute operations but not graphics nor transfer.
  280. bool has_dedicated_compute_queue () const;
  281. // Has a queue family that supports transfer operations but not graphics nor compute.
  282. bool has_dedicated_transfer_queue () const;
  283. // Has a queue family that supports transfer operations but not graphics.
  284. bool has_separate_compute_queue () const;
  285. // Has a queue family that supports transfer operations but not graphics.
  286. bool has_separate_transfer_queue () const;
  287. // Advanced: Get the VkQueueFamilyProperties of the device if special queue setup is needed
  288. std::vector<VkQueueFamilyProperties> get_queue_families () const;
  289. private:
  290. std::vector<const char*> extensions_to_enable;
  291. std::vector<VkQueueFamilyProperties> queue_families;
  292. bool defer_surface_initialization = false;
  293. friend class PhysicalDeviceSelector;
  294. friend class DeviceBuilder;
  295. };
  296. enum class PreferredDeviceType {
  297. other = 0,
  298. integrated = 1,
  299. discrete = 2,
  300. virtual_gpu = 3,
  301. cpu = 4
  302. };
  303. class PhysicalDeviceSelector {
  304. public:
  305. // Requires a vkb::Instance to construct, needed to pass instance creation info.
  306. explicit PhysicalDeviceSelector (Instance const& instance);
  307. detail::Result<PhysicalDevice> select () const;
  308. // Set the surface in which the physical device should render to.
  309. PhysicalDeviceSelector& set_surface (VkSurfaceKHR surface);
  310. // Set the desired physical device type to select. Defaults to PreferredDeviceType::discrete.
  311. PhysicalDeviceSelector& prefer_gpu_device_type (PreferredDeviceType type = PreferredDeviceType::discrete);
  312. // Allow selection of a gpu device type that isn't the preferred physical device type. Defaults to true.
  313. PhysicalDeviceSelector& allow_any_gpu_device_type (bool allow_any_type = true);
  314. // Require that a physical device supports presentation. Defaults to true.
  315. PhysicalDeviceSelector& require_present (bool require = true);
  316. // Require a queue family that supports compute operations but not graphics nor transfer.
  317. PhysicalDeviceSelector& require_dedicated_compute_queue ();
  318. // Require a queue family that supports transfer operations but not graphics nor compute.
  319. PhysicalDeviceSelector& require_dedicated_transfer_queue ();
  320. // Require a queue family that supports compute operations but not graphics.
  321. PhysicalDeviceSelector& require_separate_compute_queue ();
  322. // Require a queue family that supports transfer operations but not graphics.
  323. PhysicalDeviceSelector& require_separate_transfer_queue ();
  324. // Require a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available.
  325. PhysicalDeviceSelector& required_device_memory_size (VkDeviceSize size);
  326. // Prefer a memory heap from VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT with `size` memory available.
  327. PhysicalDeviceSelector& desired_device_memory_size (VkDeviceSize size);
  328. // Require a physical device which supports a specific extension.
  329. PhysicalDeviceSelector& add_required_extension (const char* extension);
  330. // Require a physical device which supports a set of extensions.
  331. PhysicalDeviceSelector& add_required_extensions (std::vector<const char*> extensions);
  332. // Prefer a physical device which supports a specific extension.
  333. PhysicalDeviceSelector& add_desired_extension (const char* extension);
  334. // Prefer a physical device which supports a set of extensions.
  335. PhysicalDeviceSelector& add_desired_extensions (std::vector<const char*> extensions);
  336. // Prefer a physical device that supports a (major, minor) version of vulkan.
  337. PhysicalDeviceSelector& set_desired_version (uint32_t major, uint32_t minor);
  338. // Require a physical device that supports a (major, minor) version of vulkan.
  339. PhysicalDeviceSelector& set_minimum_version (uint32_t major, uint32_t minor);
  340. // Require a physical device which supports the features in VkPhysicalDeviceFeatures.
  341. PhysicalDeviceSelector& set_required_features (VkPhysicalDeviceFeatures features);
  342. // Used when surface creation happens after physical device selection.
  343. // Warning: This disables checking if the physical device supports a given surface.
  344. PhysicalDeviceSelector& defer_surface_initialization ();
  345. // Ignore all criteria and choose the first physical device that is available.
  346. // Only use when: The first gpu in the list may be set by global user preferences and an application may wish to respect it.
  347. PhysicalDeviceSelector& select_first_device_unconditionally (bool unconditionally = true);
  348. private:
  349. struct SystemInfo {
  350. VkInstance instance = VK_NULL_HANDLE;
  351. VkSurfaceKHR surface = VK_NULL_HANDLE;
  352. bool headless = false;
  353. } system_info;
  354. struct PhysicalDeviceDesc {
  355. VkPhysicalDevice phys_device = VK_NULL_HANDLE;
  356. std::vector<VkQueueFamilyProperties> queue_families;
  357. VkPhysicalDeviceFeatures device_features{};
  358. VkPhysicalDeviceProperties device_properties{};
  359. VkPhysicalDeviceMemoryProperties mem_properties{};
  360. };
  361. PhysicalDeviceDesc populate_device_details (VkPhysicalDevice phys_device) const;
  362. struct SelectionCriteria {
  363. PreferredDeviceType preferred_type = PreferredDeviceType::discrete;
  364. bool allow_any_type = true;
  365. bool require_present = true;
  366. bool require_dedicated_transfer_queue = false;
  367. bool require_dedicated_compute_queue = false;
  368. bool require_separate_transfer_queue = false;
  369. bool require_separate_compute_queue = false;
  370. VkDeviceSize required_mem_size = 0;
  371. VkDeviceSize desired_mem_size = 0;
  372. std::vector<const char*> required_extensions;
  373. std::vector<const char*> desired_extensions;
  374. uint32_t required_version = VK_MAKE_VERSION (1, 0, 0);
  375. uint32_t desired_version = VK_MAKE_VERSION (1, 0, 0);
  376. VkPhysicalDeviceFeatures required_features{};
  377. bool defer_surface_initialization = false;
  378. bool use_first_gpu_unconditionally = false;
  379. } criteria;
  380. enum class Suitable { yes, partial, no };
  381. Suitable is_device_suitable (PhysicalDeviceDesc phys_device) const;
  382. };
  383. // ---- Queue ---- //
  384. enum class QueueType { present, graphics, compute, transfer };
  385. // ---- Device ---- //
  386. struct Device {
  387. VkDevice device = VK_NULL_HANDLE;
  388. PhysicalDevice physical_device;
  389. VkSurfaceKHR surface = VK_NULL_HANDLE;
  390. std::vector<VkQueueFamilyProperties> queue_families;
  391. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  392. detail::Result<uint32_t> get_queue_index (QueueType type) const;
  393. // Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue index
  394. detail::Result<uint32_t> get_dedicated_queue_index (QueueType type) const;
  395. detail::Result<VkQueue> get_queue (QueueType type) const;
  396. // Only a compute or transfer queue type is valid. All other queue types do not support a 'dedicated' queue
  397. detail::Result<VkQueue> get_dedicated_queue (QueueType type) const;
  398. };
  399. // For advanced device queue setup
  400. struct CustomQueueDescription {
  401. explicit CustomQueueDescription (uint32_t index, uint32_t count, std::vector<float> priorities);
  402. uint32_t index = 0;
  403. uint32_t count = 0;
  404. std::vector<float> priorities;
  405. };
  406. void destroy_device (Device device);
  407. class DeviceBuilder {
  408. public:
  409. // Any features and extensions that are requested/required in PhysicalDeviceSelector are automatically enabled.
  410. explicit DeviceBuilder (PhysicalDevice physical_device);
  411. detail::Result<Device> build () const;
  412. // For Advanced Users: specify the exact list of VkDeviceQueueCreateInfo's needed for the application.
  413. // If a custom queue setup is provided, getting the queues and queue indexes is up to the application.
  414. DeviceBuilder& custom_queue_setup (std::vector<CustomQueueDescription> queue_descriptions);
  415. // Add a structure to the pNext chain of VkDeviceCreateInfo.
  416. // The structure must be valid when DeviceBuilder::build() is called.
  417. template <typename T> DeviceBuilder& add_pNext (T* structure) {
  418. info.pNext_chain.push_back (reinterpret_cast<VkBaseOutStructure*> (structure));
  419. return *this;
  420. }
  421. // Provide custom allocation callbacks.
  422. DeviceBuilder& set_allocation_callbacks (VkAllocationCallbacks* callbacks);
  423. private:
  424. struct DeviceInfo {
  425. VkDeviceCreateFlags flags = 0;
  426. std::vector<VkBaseOutStructure*> pNext_chain;
  427. PhysicalDevice physical_device;
  428. VkSurfaceKHR surface = VK_NULL_HANDLE;
  429. bool defer_surface_initialization = false;
  430. std::vector<VkQueueFamilyProperties> queue_families;
  431. VkPhysicalDeviceFeatures features{};
  432. std::vector<const char*> extensions_to_enable;
  433. std::vector<CustomQueueDescription> queue_descriptions;
  434. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  435. } info;
  436. };
  437. // ---- Swapchain ---- //
  438. struct Swapchain {
  439. VkDevice device = VK_NULL_HANDLE;
  440. VkSwapchainKHR swapchain = VK_NULL_HANDLE;
  441. uint32_t image_count = 0;
  442. VkFormat image_format = VK_FORMAT_UNDEFINED;
  443. VkExtent2D extent = { 0, 0 };
  444. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  445. // Returns a vector of VkImage handles to the swapchain.
  446. detail::Result<std::vector<VkImage>> get_images ();
  447. // Returns a vector of VkImageView's to the VkImage's of the swapchain.
  448. // VkImageViews must be destroyed.
  449. detail::Result<std::vector<VkImageView>> get_image_views ();
  450. void destroy_image_views (std::vector<VkImageView> const& image_views);
  451. };
  452. void destroy_swapchain (Swapchain const& swapchain);
  453. class SwapchainBuilder {
  454. public:
  455. explicit SwapchainBuilder (Device const& device);
  456. explicit SwapchainBuilder (Device const& device, VkSurfaceKHR const surface);
  457. explicit SwapchainBuilder (VkPhysicalDevice const physical_device, VkDevice const device, VkSurfaceKHR const surface, int32_t graphics_queue_index = -1, int32_t present_queue_index = -1);
  458. detail::Result<Swapchain> build () const;
  459. // Set the oldSwapchain member of VkSwapchainCreateInfoKHR.
  460. // For use in rebuilding a swapchain.
  461. SwapchainBuilder& set_old_swapchain (VkSwapchainKHR old_swapchain);
  462. SwapchainBuilder& set_old_swapchain (Swapchain const& swapchain);
  463. // Desired size of the swapchain. By default, the swapchain will use the size
  464. // of the window being drawn to.
  465. SwapchainBuilder& set_desired_extent (uint32_t width, uint32_t height);
  466. // When determining the surface format, make this the first to be used if supported.
  467. SwapchainBuilder& set_desired_format (VkSurfaceFormatKHR format);
  468. // Add this swapchain format to the end of the list of formats selected from.
  469. SwapchainBuilder& add_fallback_format (VkSurfaceFormatKHR format);
  470. // Use the default swapchain formats. This is done if no formats are provided.
  471. SwapchainBuilder& use_default_format_selection ();
  472. // When determining the present mode, make this the first to be used if supported.
  473. SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode);
  474. // Add this present mode to the end of the list of present modes selected from.
  475. SwapchainBuilder& add_fallback_present_mode (VkPresentModeKHR present_mode);
  476. // Use the default presentation mode. This is done if no present modes are provided.
  477. SwapchainBuilder& use_default_present_mode_selection ();
  478. // Set the bitmask of the image usage for acquired swapchain images.
  479. SwapchainBuilder& set_image_usage_flags (VkImageUsageFlags usage_flags);
  480. // Add a image usage to the bitmask for acquired swapchain images.
  481. SwapchainBuilder& add_image_usage_flags (VkImageUsageFlags usage_flags);
  482. // Use the default image usage bitmask values. This is the default if no image usages
  483. // are provided. The default is VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
  484. SwapchainBuilder& use_default_image_usage_flags ();
  485. // Set the number of views in for multiview/stereo surface
  486. SwapchainBuilder& set_image_array_layer_count (uint32_t array_layer_count);
  487. // Set whether the Vulkan implementation is allowed to discard rendering operations that
  488. // affect regions of the surface that are not visible. Default is true.
  489. // Note: Applications should use the default of true if they do not expect to read back the content
  490. // of presentable images before presenting them or after reacquiring them, and if their fragment
  491. // shaders do not have any side effects that require them to run for all pixels in the presentable image.
  492. SwapchainBuilder& set_clipped (bool clipped = true);
  493. // Set the VkSwapchainCreateFlagBitsKHR.
  494. SwapchainBuilder& set_create_flags (VkSwapchainCreateFlagBitsKHR create_flags);
  495. // Set the transform to be applied, like a 90 degree rotation. Default is the current transform.
  496. SwapchainBuilder& set_pre_transform_flags (VkSurfaceTransformFlagBitsKHR pre_transform_flags);
  497. // Set the alpha channel to be used with other windows in on the system. Default is VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR.
  498. SwapchainBuilder& set_composite_alpha_flags (VkCompositeAlphaFlagBitsKHR composite_alpha_flags);
  499. // Add a structure to the pNext chain of VkSwapchainCreateInfoKHR.
  500. // The structure must be valid when SwapchainBuilder::build() is called.
  501. template <typename T> SwapchainBuilder& add_pNext (T* structure) {
  502. info.pNext_chain.push_back (reinterpret_cast<VkBaseOutStructure*> (structure));
  503. return *this;
  504. }
  505. // Provide custom allocation callbacks.
  506. SwapchainBuilder& set_allocation_callbacks (VkAllocationCallbacks* callbacks);
  507. private:
  508. void add_desired_formats (std::vector<VkSurfaceFormatKHR>& formats) const;
  509. void add_desired_present_modes (std::vector<VkPresentModeKHR>& modes) const;
  510. struct SwapchainInfo {
  511. VkPhysicalDevice physical_device = VK_NULL_HANDLE;
  512. VkDevice device = VK_NULL_HANDLE;
  513. std::vector<VkBaseOutStructure*> pNext_chain;
  514. VkSwapchainCreateFlagBitsKHR create_flags = static_cast<VkSwapchainCreateFlagBitsKHR> (0);
  515. VkSurfaceKHR surface = VK_NULL_HANDLE;
  516. std::vector<VkSurfaceFormatKHR> desired_formats;
  517. uint32_t desired_width = 256;
  518. uint32_t desired_height = 256;
  519. uint32_t array_layer_count = 1;
  520. VkImageUsageFlags image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  521. uint32_t graphics_queue_index = 0;
  522. uint32_t present_queue_index = 0;
  523. VkSurfaceTransformFlagBitsKHR pre_transform = static_cast<VkSurfaceTransformFlagBitsKHR> (0);
  524. VkCompositeAlphaFlagBitsKHR composite_alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  525. std::vector<VkPresentModeKHR> desired_present_modes;
  526. bool clipped = true;
  527. VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
  528. VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
  529. } info;
  530. };
  531. } // namespace vkb
  532. namespace std {
  533. template <> struct is_error_code_enum<vkb::InstanceError> : true_type {};
  534. template <> struct is_error_code_enum<vkb::PhysicalDeviceError> : true_type {};
  535. template <> struct is_error_code_enum<vkb::QueueError> : true_type {};
  536. template <> struct is_error_code_enum<vkb::DeviceError> : true_type {};
  537. template <> struct is_error_code_enum<vkb::SwapchainError> : true_type {};
  538. } // namespace std