wrapper.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <exception>
  6. #include <iterator>
  7. #include <limits>
  8. #include <memory>
  9. #include <optional>
  10. #include <type_traits>
  11. #include <utility>
  12. #include <vector>
  13. #define VK_NO_PROTOTYPES
  14. #include <vulkan/vulkan.h>
  15. #include "common/common_types.h"
  16. namespace Vulkan::vk {
  17. /**
  18. * Span for Vulkan arrays.
  19. * Based on std::span but optimized for array access instead of iterators.
  20. * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions.
  21. */
  22. template <typename T>
  23. class Span {
  24. public:
  25. using value_type = T;
  26. using size_type = u32;
  27. using difference_type = std::ptrdiff_t;
  28. using reference = const T&;
  29. using const_reference = const T&;
  30. using pointer = const T*;
  31. using const_pointer = const T*;
  32. using iterator = const T*;
  33. using const_iterator = const T*;
  34. /// Construct an empty span.
  35. constexpr Span() noexcept = default;
  36. /// Construct a span from a single element.
  37. constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {}
  38. /// Construct a span from a range.
  39. template <typename Range>
  40. // requires std::data(const Range&)
  41. // requires std::size(const Range&)
  42. constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {}
  43. /// Construct a span from a pointer and a size.
  44. /// This is inteded for subranges.
  45. constexpr Span(const T* ptr, std::size_t num) noexcept : ptr{ptr}, num{num} {}
  46. /// Returns the data pointer by the span.
  47. constexpr const T* data() const noexcept {
  48. return ptr;
  49. }
  50. /// Returns the number of elements in the span.
  51. /// @note Returns a 32 bits integer because most Vulkan functions expect this type.
  52. constexpr u32 size() const noexcept {
  53. return static_cast<u32>(num);
  54. }
  55. /// Returns true when the span is empty.
  56. constexpr bool empty() const noexcept {
  57. return num == 0;
  58. }
  59. /// Returns a reference to the element in the passed index.
  60. /// @pre: index < size()
  61. constexpr const T& operator[](std::size_t index) const noexcept {
  62. return ptr[index];
  63. }
  64. /// Returns an iterator to the beginning of the span.
  65. constexpr const T* begin() const noexcept {
  66. return ptr;
  67. }
  68. /// Returns an iterator to the end of the span.
  69. constexpr const T* end() const noexcept {
  70. return ptr + num;
  71. }
  72. /// Returns an iterator to the beginning of the span.
  73. constexpr const T* cbegin() const noexcept {
  74. return ptr;
  75. }
  76. /// Returns an iterator to the end of the span.
  77. constexpr const T* cend() const noexcept {
  78. return ptr + num;
  79. }
  80. private:
  81. const T* ptr = nullptr;
  82. std::size_t num = 0;
  83. };
  84. /// Vulkan exception generated from a VkResult.
  85. class Exception final : public std::exception {
  86. public:
  87. /// Construct the exception with a result.
  88. /// @pre result != VK_SUCCESS
  89. explicit Exception(VkResult result_) : result{result_} {}
  90. virtual ~Exception() = default;
  91. const char* what() const noexcept override;
  92. private:
  93. VkResult result;
  94. };
  95. /// Converts a VkResult enum into a rodata string
  96. const char* ToString(VkResult) noexcept;
  97. /// Throws a Vulkan exception if result is not success.
  98. inline void Check(VkResult result) {
  99. if (result != VK_SUCCESS) {
  100. throw Exception(result);
  101. }
  102. }
  103. /// Throws a Vulkan exception if result is an error.
  104. /// @return result
  105. inline VkResult Filter(VkResult result) {
  106. if (result < 0) {
  107. throw Exception(result);
  108. }
  109. return result;
  110. }
  111. /// Table holding Vulkan instance function pointers.
  112. struct InstanceDispatch {
  113. PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
  114. PFN_vkCreateInstance vkCreateInstance;
  115. PFN_vkDestroyInstance vkDestroyInstance;
  116. PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
  117. PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
  118. PFN_vkCreateDevice vkCreateDevice;
  119. PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
  120. PFN_vkDestroyDevice vkDestroyDevice;
  121. PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
  122. PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
  123. PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
  124. PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
  125. PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
  126. PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
  127. PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
  128. PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
  129. PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
  130. PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
  131. PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
  132. PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
  133. PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
  134. PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
  135. PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
  136. PFN_vkQueuePresentKHR vkQueuePresentKHR;
  137. };
  138. /// Table holding Vulkan device function pointers.
  139. struct DeviceDispatch : public InstanceDispatch {
  140. PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
  141. PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
  142. PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
  143. PFN_vkAllocateMemory vkAllocateMemory;
  144. PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
  145. PFN_vkBindBufferMemory vkBindBufferMemory;
  146. PFN_vkBindImageMemory vkBindImageMemory;
  147. PFN_vkCmdBeginQuery vkCmdBeginQuery;
  148. PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
  149. PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT;
  150. PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
  151. PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
  152. PFN_vkCmdBindPipeline vkCmdBindPipeline;
  153. PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT;
  154. PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
  155. PFN_vkCmdBlitImage vkCmdBlitImage;
  156. PFN_vkCmdClearAttachments vkCmdClearAttachments;
  157. PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
  158. PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
  159. PFN_vkCmdCopyImage vkCmdCopyImage;
  160. PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
  161. PFN_vkCmdDispatch vkCmdDispatch;
  162. PFN_vkCmdDraw vkCmdDraw;
  163. PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
  164. PFN_vkCmdEndQuery vkCmdEndQuery;
  165. PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
  166. PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT;
  167. PFN_vkCmdFillBuffer vkCmdFillBuffer;
  168. PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
  169. PFN_vkCmdPushConstants vkCmdPushConstants;
  170. PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
  171. PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV;
  172. PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
  173. PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
  174. PFN_vkCmdSetScissor vkCmdSetScissor;
  175. PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
  176. PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
  177. PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
  178. PFN_vkCmdSetViewport vkCmdSetViewport;
  179. PFN_vkCreateBuffer vkCreateBuffer;
  180. PFN_vkCreateBufferView vkCreateBufferView;
  181. PFN_vkCreateCommandPool vkCreateCommandPool;
  182. PFN_vkCreateComputePipelines vkCreateComputePipelines;
  183. PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
  184. PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
  185. PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR;
  186. PFN_vkCreateFence vkCreateFence;
  187. PFN_vkCreateFramebuffer vkCreateFramebuffer;
  188. PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
  189. PFN_vkCreateImage vkCreateImage;
  190. PFN_vkCreateImageView vkCreateImageView;
  191. PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
  192. PFN_vkCreateQueryPool vkCreateQueryPool;
  193. PFN_vkCreateRenderPass vkCreateRenderPass;
  194. PFN_vkCreateSampler vkCreateSampler;
  195. PFN_vkCreateSemaphore vkCreateSemaphore;
  196. PFN_vkCreateShaderModule vkCreateShaderModule;
  197. PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
  198. PFN_vkDestroyBuffer vkDestroyBuffer;
  199. PFN_vkDestroyBufferView vkDestroyBufferView;
  200. PFN_vkDestroyCommandPool vkDestroyCommandPool;
  201. PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
  202. PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
  203. PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR;
  204. PFN_vkDestroyFence vkDestroyFence;
  205. PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
  206. PFN_vkDestroyImage vkDestroyImage;
  207. PFN_vkDestroyImageView vkDestroyImageView;
  208. PFN_vkDestroyPipeline vkDestroyPipeline;
  209. PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
  210. PFN_vkDestroyQueryPool vkDestroyQueryPool;
  211. PFN_vkDestroyRenderPass vkDestroyRenderPass;
  212. PFN_vkDestroySampler vkDestroySampler;
  213. PFN_vkDestroySemaphore vkDestroySemaphore;
  214. PFN_vkDestroyShaderModule vkDestroyShaderModule;
  215. PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
  216. PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
  217. PFN_vkEndCommandBuffer vkEndCommandBuffer;
  218. PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
  219. PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
  220. PFN_vkFreeMemory vkFreeMemory;
  221. PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
  222. PFN_vkGetDeviceQueue vkGetDeviceQueue;
  223. PFN_vkGetFenceStatus vkGetFenceStatus;
  224. PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
  225. PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
  226. PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV;
  227. PFN_vkMapMemory vkMapMemory;
  228. PFN_vkQueueSubmit vkQueueSubmit;
  229. PFN_vkResetFences vkResetFences;
  230. PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT;
  231. PFN_vkUnmapMemory vkUnmapMemory;
  232. PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR;
  233. PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
  234. PFN_vkWaitForFences vkWaitForFences;
  235. };
  236. /// Loads instance agnostic function pointers.
  237. /// @return True on success, false on error.
  238. bool Load(InstanceDispatch&) noexcept;
  239. /// Loads instance function pointers.
  240. /// @return True on success, false on error.
  241. bool Load(VkInstance, InstanceDispatch&) noexcept;
  242. void Destroy(VkInstance, const InstanceDispatch&) noexcept;
  243. void Destroy(VkDevice, const InstanceDispatch&) noexcept;
  244. void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept;
  245. void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept;
  246. void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;
  247. void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;
  248. void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept;
  249. void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept;
  250. void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept;
  251. void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept;
  252. void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept;
  253. void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept;
  254. void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept;
  255. void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept;
  256. void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept;
  257. void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept;
  258. void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept;
  259. void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept;
  260. void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
  261. void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
  262. void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
  263. void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
  264. void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
  265. VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
  266. VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept;
  267. template <typename Type, typename OwnerType, typename Dispatch>
  268. class Handle;
  269. /// Handle with an owning type.
  270. /// Analogue to std::unique_ptr.
  271. template <typename Type, typename OwnerType, typename Dispatch>
  272. class Handle {
  273. public:
  274. /// Construct a handle and hold it's ownership.
  275. explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept
  276. : handle{handle_}, owner{owner_}, dld{&dld_} {}
  277. /// Construct an empty handle.
  278. Handle() = default;
  279. /// Copying Vulkan objects is not supported and will never be.
  280. Handle(const Handle&) = delete;
  281. Handle& operator=(const Handle&) = delete;
  282. /// Construct a handle transfering the ownership from another handle.
  283. Handle(Handle&& rhs) noexcept
  284. : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {}
  285. /// Assign the current handle transfering the ownership from another handle.
  286. /// Destroys any previously held object.
  287. Handle& operator=(Handle&& rhs) noexcept {
  288. Release();
  289. handle = std::exchange(rhs.handle, nullptr);
  290. owner = rhs.owner;
  291. dld = rhs.dld;
  292. return *this;
  293. }
  294. /// Destroys the current handle if it existed.
  295. ~Handle() noexcept {
  296. Release();
  297. }
  298. /// Destroys any held object.
  299. void reset() noexcept {
  300. Release();
  301. handle = nullptr;
  302. }
  303. /// Returns the address of the held object.
  304. /// Intended for Vulkan structures that expect a pointer to an array.
  305. const Type* address() const noexcept {
  306. return std::addressof(handle);
  307. }
  308. /// Returns the held Vulkan handle.
  309. Type operator*() const noexcept {
  310. return handle;
  311. }
  312. /// Returns true when there's a held object.
  313. explicit operator bool() const noexcept {
  314. return handle != nullptr;
  315. }
  316. protected:
  317. Type handle = nullptr;
  318. OwnerType owner = nullptr;
  319. const Dispatch* dld = nullptr;
  320. private:
  321. /// Destroys the held object if it exists.
  322. void Release() noexcept {
  323. if (handle) {
  324. Destroy(owner, handle, *dld);
  325. }
  326. }
  327. };
  328. /// Dummy type used to specify a handle has no owner.
  329. struct NoOwner {};
  330. /// Handle without an owning type.
  331. /// Analogue to std::unique_ptr
  332. template <typename Type, typename Dispatch>
  333. class Handle<Type, NoOwner, Dispatch> {
  334. public:
  335. /// Construct a handle and hold it's ownership.
  336. explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {}
  337. /// Construct an empty handle.
  338. Handle() noexcept = default;
  339. /// Copying Vulkan objects is not supported and will never be.
  340. Handle(const Handle&) = delete;
  341. Handle& operator=(const Handle&) = delete;
  342. /// Construct a handle transfering ownership from another handle.
  343. Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {}
  344. /// Assign the current handle transfering the ownership from another handle.
  345. /// Destroys any previously held object.
  346. Handle& operator=(Handle&& rhs) noexcept {
  347. Release();
  348. handle = std::exchange(rhs.handle, nullptr);
  349. dld = rhs.dld;
  350. return *this;
  351. }
  352. /// Destroys the current handle if it existed.
  353. ~Handle() noexcept {
  354. Release();
  355. }
  356. /// Destroys any held object.
  357. void reset() noexcept {
  358. Release();
  359. handle = nullptr;
  360. }
  361. /// Returns the address of the held object.
  362. /// Intended for Vulkan structures that expect a pointer to an array.
  363. const Type* address() const noexcept {
  364. return std::addressof(handle);
  365. }
  366. /// Returns the held Vulkan handle.
  367. Type operator*() const noexcept {
  368. return handle;
  369. }
  370. /// Returns true when there's a held object.
  371. operator bool() const noexcept {
  372. return handle != nullptr;
  373. }
  374. protected:
  375. Type handle = nullptr;
  376. const Dispatch* dld = nullptr;
  377. private:
  378. /// Destroys the held object if it exists.
  379. void Release() noexcept {
  380. if (handle) {
  381. Destroy(handle, *dld);
  382. }
  383. }
  384. };
  385. /// Array of a pool allocation.
  386. /// Analogue to std::vector
  387. template <typename AllocationType, typename PoolType>
  388. class PoolAllocations {
  389. public:
  390. /// Construct an empty allocation.
  391. PoolAllocations() = default;
  392. /// Construct an allocation. Errors are reported through IsOutOfPoolMemory().
  393. explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations, std::size_t num,
  394. VkDevice device, PoolType pool, const DeviceDispatch& dld) noexcept
  395. : allocations{std::move(allocations)}, num{num}, device{device}, pool{pool}, dld{&dld} {}
  396. /// Copying Vulkan allocations is not supported and will never be.
  397. PoolAllocations(const PoolAllocations&) = delete;
  398. PoolAllocations& operator=(const PoolAllocations&) = delete;
  399. /// Construct an allocation transfering ownership from another allocation.
  400. PoolAllocations(PoolAllocations&& rhs) noexcept
  401. : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool},
  402. dld{rhs.dld} {}
  403. /// Assign an allocation transfering ownership from another allocation.
  404. /// Releases any previously held allocation.
  405. PoolAllocations& operator=(PoolAllocations&& rhs) noexcept {
  406. Release();
  407. allocations = std::move(rhs.allocations);
  408. num = rhs.num;
  409. device = rhs.device;
  410. pool = rhs.pool;
  411. dld = rhs.dld;
  412. return *this;
  413. }
  414. /// Destroys any held allocation.
  415. ~PoolAllocations() {
  416. Release();
  417. }
  418. /// Returns the number of allocations.
  419. std::size_t size() const noexcept {
  420. return num;
  421. }
  422. /// Returns a pointer to the array of allocations.
  423. AllocationType const* data() const noexcept {
  424. return allocations.get();
  425. }
  426. /// Returns the allocation in the specified index.
  427. /// @pre index < size()
  428. AllocationType operator[](std::size_t index) const noexcept {
  429. return allocations[index];
  430. }
  431. /// True when a pool fails to construct.
  432. bool IsOutOfPoolMemory() const noexcept {
  433. return !device;
  434. }
  435. private:
  436. /// Destroys the held allocations if they exist.
  437. void Release() noexcept {
  438. if (!allocations) {
  439. return;
  440. }
  441. const Span<AllocationType> span(allocations.get(), num);
  442. const VkResult result = Free(device, pool, span, *dld);
  443. // There's no way to report errors from a destructor.
  444. if (result != VK_SUCCESS) {
  445. std::terminate();
  446. }
  447. }
  448. std::unique_ptr<AllocationType[]> allocations;
  449. std::size_t num = 0;
  450. VkDevice device = nullptr;
  451. PoolType pool = nullptr;
  452. const DeviceDispatch* dld = nullptr;
  453. };
  454. using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>;
  455. using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
  456. using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
  457. using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
  458. using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>;
  459. using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>;
  460. using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
  461. using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;
  462. using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>;
  463. using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>;
  464. using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>;
  465. using Semaphore = Handle<VkSemaphore, VkDevice, DeviceDispatch>;
  466. using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>;
  467. using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
  468. using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>;
  469. using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>;
  470. /// Vulkan instance owning handle.
  471. class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
  472. using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
  473. public:
  474. /// Creates a Vulkan instance. Use "operator bool" for error handling.
  475. static Instance Create(Span<const char*> layers, Span<const char*> extensions,
  476. InstanceDispatch& dld) noexcept;
  477. /// Enumerates physical devices.
  478. /// @return Physical devices and an empty handle on failure.
  479. std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices();
  480. /// Tries to create a debug callback messenger. Returns an empty handle on failure.
  481. DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept;
  482. };
  483. class Queue {
  484. public:
  485. /// Construct an empty queue handle.
  486. constexpr Queue() noexcept = default;
  487. /// Construct a queue handle.
  488. constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {}
  489. /// Returns the checkpoint data.
  490. /// @note Returns an empty vector when the function pointer is not present.
  491. std::vector<VkCheckpointDataNV> GetCheckpointDataNV(const DeviceDispatch& dld) const;
  492. void Submit(Span<VkSubmitInfo> submit_infos, VkFence fence) const {
  493. Check(dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence));
  494. }
  495. VkResult Present(const VkPresentInfoKHR& present_info) const noexcept {
  496. return dld->vkQueuePresentKHR(queue, &present_info);
  497. }
  498. private:
  499. VkQueue queue = nullptr;
  500. const DeviceDispatch* dld = nullptr;
  501. };
  502. class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
  503. using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
  504. public:
  505. /// Attaches a memory allocation.
  506. void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
  507. };
  508. class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
  509. using Handle<VkImage, VkDevice, DeviceDispatch>::Handle;
  510. public:
  511. /// Attaches a memory allocation.
  512. void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
  513. };
  514. class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> {
  515. using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle;
  516. public:
  517. u8* Map(VkDeviceSize offset, VkDeviceSize size) const {
  518. void* data;
  519. Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data));
  520. return static_cast<u8*>(data);
  521. }
  522. void Unmap() const noexcept {
  523. dld->vkUnmapMemory(owner, handle);
  524. }
  525. };
  526. class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> {
  527. using Handle<VkFence, VkDevice, DeviceDispatch>::Handle;
  528. public:
  529. VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept {
  530. return dld->vkWaitForFences(owner, 1, &handle, true, timeout);
  531. }
  532. VkResult GetStatus() const noexcept {
  533. return dld->vkGetFenceStatus(owner, handle);
  534. }
  535. void Reset() const {
  536. Check(dld->vkResetFences(owner, 1, &handle));
  537. }
  538. };
  539. class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> {
  540. using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle;
  541. public:
  542. DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const;
  543. };
  544. class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> {
  545. using Handle<VkCommandPool, VkDevice, DeviceDispatch>::Handle;
  546. public:
  547. CommandBuffers Allocate(std::size_t num_buffers,
  548. VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const;
  549. };
  550. class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> {
  551. using Handle<VkSwapchainKHR, VkDevice, DeviceDispatch>::Handle;
  552. public:
  553. std::vector<VkImage> GetImages() const;
  554. };
  555. class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
  556. using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle;
  557. public:
  558. static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
  559. Span<const char*> enabled_extensions,
  560. const VkPhysicalDeviceFeatures2& enabled_features,
  561. DeviceDispatch& dld) noexcept;
  562. Queue GetQueue(u32 family_index) const noexcept;
  563. Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
  564. BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
  565. Image CreateImage(const VkImageCreateInfo& ci) const;
  566. ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
  567. Semaphore CreateSemaphore() const;
  568. Fence CreateFence(const VkFenceCreateInfo& ci) const;
  569. DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const;
  570. RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const;
  571. DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const;
  572. PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const;
  573. Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const;
  574. Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const;
  575. Sampler CreateSampler(const VkSamplerCreateInfo& ci) const;
  576. Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const;
  577. CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const;
  578. DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR(
  579. const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const;
  580. QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const;
  581. ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
  582. SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
  583. DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept;
  584. DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const;
  585. VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept;
  586. VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept;
  587. void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
  588. Span<VkCopyDescriptorSet> copies) const noexcept;
  589. void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template,
  590. const void* data) const noexcept {
  591. dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data);
  592. }
  593. VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore,
  594. VkFence fence, u32* image_index) const noexcept {
  595. return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence,
  596. image_index);
  597. }
  598. VkResult WaitIdle() const noexcept {
  599. return dld->vkDeviceWaitIdle(handle);
  600. }
  601. void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept {
  602. dld->vkResetQueryPoolEXT(handle, query_pool, first, count);
  603. }
  604. void GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
  605. void* data, VkDeviceSize stride, VkQueryResultFlags flags) const {
  606. Check(dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride,
  607. flags));
  608. }
  609. template <typename T>
  610. T GetQueryResult(VkQueryPool query_pool, u32 first, VkQueryResultFlags flags) const {
  611. static_assert(std::is_trivially_copyable_v<T>);
  612. T value;
  613. GetQueryResults(query_pool, first, 1, sizeof(T), &value, sizeof(T), flags);
  614. return value;
  615. }
  616. };
  617. } // namespace Vulkan::vk