vulkan_wrapper.h 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221
  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 <span>
  11. #include <type_traits>
  12. #include <utility>
  13. #include <vector>
  14. #define VK_NO_PROTOTYPES
  15. #include <vulkan/vulkan.h>
  16. #include "common/common_types.h"
  17. #ifdef _MSC_VER
  18. #pragma warning(disable : 26812) // Disable prefer enum class over enum
  19. #endif
  20. namespace Vulkan::vk {
  21. /**
  22. * Span for Vulkan arrays.
  23. * Based on std::span but optimized for array access instead of iterators.
  24. * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions.
  25. */
  26. template <typename T>
  27. class Span {
  28. public:
  29. using value_type = T;
  30. using size_type = u32;
  31. using difference_type = std::ptrdiff_t;
  32. using reference = const T&;
  33. using const_reference = const T&;
  34. using pointer = const T*;
  35. using const_pointer = const T*;
  36. using iterator = const T*;
  37. using const_iterator = const T*;
  38. /// Construct an empty span.
  39. constexpr Span() noexcept = default;
  40. /// Construct an empty span
  41. constexpr Span(std::nullptr_t) noexcept {}
  42. /// Construct a span from a single element.
  43. constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {}
  44. /// Construct a span from a range.
  45. template <typename Range>
  46. // requires std::data(const Range&)
  47. // requires std::size(const Range&)
  48. constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {}
  49. /// Construct a span from a pointer and a size.
  50. /// This is inteded for subranges.
  51. constexpr Span(const T* ptr_, std::size_t num_) noexcept : ptr{ptr_}, num{num_} {}
  52. /// Returns the data pointer by the span.
  53. constexpr const T* data() const noexcept {
  54. return ptr;
  55. }
  56. /// Returns the number of elements in the span.
  57. /// @note Returns a 32 bits integer because most Vulkan functions expect this type.
  58. constexpr u32 size() const noexcept {
  59. return static_cast<u32>(num);
  60. }
  61. /// Returns true when the span is empty.
  62. constexpr bool empty() const noexcept {
  63. return num == 0;
  64. }
  65. /// Returns a reference to the element in the passed index.
  66. /// @pre: index < size()
  67. constexpr const T& operator[](std::size_t index) const noexcept {
  68. return ptr[index];
  69. }
  70. /// Returns an iterator to the beginning of the span.
  71. constexpr const T* begin() const noexcept {
  72. return ptr;
  73. }
  74. /// Returns an iterator to the end of the span.
  75. constexpr const T* end() const noexcept {
  76. return ptr + num;
  77. }
  78. /// Returns an iterator to the beginning of the span.
  79. constexpr const T* cbegin() const noexcept {
  80. return ptr;
  81. }
  82. /// Returns an iterator to the end of the span.
  83. constexpr const T* cend() const noexcept {
  84. return ptr + num;
  85. }
  86. private:
  87. const T* ptr = nullptr;
  88. std::size_t num = 0;
  89. };
  90. /// Vulkan exception generated from a VkResult.
  91. class Exception final : public std::exception {
  92. public:
  93. /// Construct the exception with a result.
  94. /// @pre result != VK_SUCCESS
  95. explicit Exception(VkResult result_) : result{result_} {}
  96. virtual ~Exception() = default;
  97. const char* what() const noexcept override;
  98. private:
  99. VkResult result;
  100. };
  101. /// Converts a VkResult enum into a rodata string
  102. const char* ToString(VkResult) noexcept;
  103. /// Throws a Vulkan exception if result is not success.
  104. inline void Check(VkResult result) {
  105. if (result != VK_SUCCESS) {
  106. throw Exception(result);
  107. }
  108. }
  109. /// Throws a Vulkan exception if result is an error.
  110. /// @return result
  111. inline VkResult Filter(VkResult result) {
  112. if (result < 0) {
  113. throw Exception(result);
  114. }
  115. return result;
  116. }
  117. /// Table holding Vulkan instance function pointers.
  118. struct InstanceDispatch {
  119. PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
  120. PFN_vkCreateInstance vkCreateInstance;
  121. PFN_vkDestroyInstance vkDestroyInstance;
  122. PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
  123. PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
  124. PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
  125. PFN_vkCreateDevice vkCreateDevice;
  126. PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
  127. PFN_vkDestroyDevice vkDestroyDevice;
  128. PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
  129. PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
  130. PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
  131. PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
  132. PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
  133. PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
  134. PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
  135. PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
  136. PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
  137. PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
  138. PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
  139. PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
  140. PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
  141. PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
  142. PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
  143. PFN_vkQueuePresentKHR vkQueuePresentKHR;
  144. };
  145. /// Table holding Vulkan device function pointers.
  146. struct DeviceDispatch : public InstanceDispatch {
  147. PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
  148. PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
  149. PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
  150. PFN_vkAllocateMemory vkAllocateMemory;
  151. PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
  152. PFN_vkBindBufferMemory vkBindBufferMemory;
  153. PFN_vkBindImageMemory vkBindImageMemory;
  154. PFN_vkCmdBeginQuery vkCmdBeginQuery;
  155. PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
  156. PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT;
  157. PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT;
  158. PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
  159. PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
  160. PFN_vkCmdBindPipeline vkCmdBindPipeline;
  161. PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT;
  162. PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
  163. PFN_vkCmdBlitImage vkCmdBlitImage;
  164. PFN_vkCmdClearAttachments vkCmdClearAttachments;
  165. PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
  166. PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
  167. PFN_vkCmdCopyImage vkCmdCopyImage;
  168. PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
  169. PFN_vkCmdDispatch vkCmdDispatch;
  170. PFN_vkCmdDraw vkCmdDraw;
  171. PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
  172. PFN_vkCmdEndQuery vkCmdEndQuery;
  173. PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
  174. PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT;
  175. PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT;
  176. PFN_vkCmdFillBuffer vkCmdFillBuffer;
  177. PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
  178. PFN_vkCmdPushConstants vkCmdPushConstants;
  179. PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
  180. PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
  181. PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
  182. PFN_vkCmdSetEvent vkCmdSetEvent;
  183. PFN_vkCmdSetScissor vkCmdSetScissor;
  184. PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
  185. PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
  186. PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
  187. PFN_vkCmdSetViewport vkCmdSetViewport;
  188. PFN_vkCmdWaitEvents vkCmdWaitEvents;
  189. PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT;
  190. PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT;
  191. PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT;
  192. PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT;
  193. PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT;
  194. PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT;
  195. PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT;
  196. PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT;
  197. PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT;
  198. PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT;
  199. PFN_vkCmdResolveImage vkCmdResolveImage;
  200. PFN_vkCreateBuffer vkCreateBuffer;
  201. PFN_vkCreateBufferView vkCreateBufferView;
  202. PFN_vkCreateCommandPool vkCreateCommandPool;
  203. PFN_vkCreateComputePipelines vkCreateComputePipelines;
  204. PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
  205. PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
  206. PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR;
  207. PFN_vkCreateEvent vkCreateEvent;
  208. PFN_vkCreateFence vkCreateFence;
  209. PFN_vkCreateFramebuffer vkCreateFramebuffer;
  210. PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
  211. PFN_vkCreateImage vkCreateImage;
  212. PFN_vkCreateImageView vkCreateImageView;
  213. PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
  214. PFN_vkCreateQueryPool vkCreateQueryPool;
  215. PFN_vkCreateRenderPass vkCreateRenderPass;
  216. PFN_vkCreateSampler vkCreateSampler;
  217. PFN_vkCreateSemaphore vkCreateSemaphore;
  218. PFN_vkCreateShaderModule vkCreateShaderModule;
  219. PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
  220. PFN_vkDestroyBuffer vkDestroyBuffer;
  221. PFN_vkDestroyBufferView vkDestroyBufferView;
  222. PFN_vkDestroyCommandPool vkDestroyCommandPool;
  223. PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
  224. PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
  225. PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR;
  226. PFN_vkDestroyEvent vkDestroyEvent;
  227. PFN_vkDestroyFence vkDestroyFence;
  228. PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
  229. PFN_vkDestroyImage vkDestroyImage;
  230. PFN_vkDestroyImageView vkDestroyImageView;
  231. PFN_vkDestroyPipeline vkDestroyPipeline;
  232. PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
  233. PFN_vkDestroyQueryPool vkDestroyQueryPool;
  234. PFN_vkDestroyRenderPass vkDestroyRenderPass;
  235. PFN_vkDestroySampler vkDestroySampler;
  236. PFN_vkDestroySemaphore vkDestroySemaphore;
  237. PFN_vkDestroyShaderModule vkDestroyShaderModule;
  238. PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
  239. PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
  240. PFN_vkEndCommandBuffer vkEndCommandBuffer;
  241. PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
  242. PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
  243. PFN_vkFreeMemory vkFreeMemory;
  244. PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
  245. PFN_vkGetDeviceQueue vkGetDeviceQueue;
  246. PFN_vkGetEventStatus vkGetEventStatus;
  247. PFN_vkGetFenceStatus vkGetFenceStatus;
  248. PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
  249. PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
  250. PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR;
  251. PFN_vkMapMemory vkMapMemory;
  252. PFN_vkQueueSubmit vkQueueSubmit;
  253. PFN_vkResetFences vkResetFences;
  254. PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT;
  255. PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
  256. PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT;
  257. PFN_vkUnmapMemory vkUnmapMemory;
  258. PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR;
  259. PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
  260. PFN_vkWaitForFences vkWaitForFences;
  261. PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR;
  262. };
  263. /// Loads instance agnostic function pointers.
  264. /// @return True on success, false on error.
  265. bool Load(InstanceDispatch&) noexcept;
  266. /// Loads instance function pointers.
  267. /// @return True on success, false on error.
  268. bool Load(VkInstance, InstanceDispatch&) noexcept;
  269. void Destroy(VkInstance, const InstanceDispatch&) noexcept;
  270. void Destroy(VkDevice, const InstanceDispatch&) noexcept;
  271. void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept;
  272. void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept;
  273. void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;
  274. void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;
  275. void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept;
  276. void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept;
  277. void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept;
  278. void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept;
  279. void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept;
  280. void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept;
  281. void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept;
  282. void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept;
  283. void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept;
  284. void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept;
  285. void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept;
  286. void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept;
  287. void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept;
  288. void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
  289. void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
  290. void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
  291. void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
  292. void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
  293. VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
  294. VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept;
  295. template <typename Type, typename OwnerType, typename Dispatch>
  296. class Handle;
  297. /// Handle with an owning type.
  298. /// Analogue to std::unique_ptr.
  299. template <typename Type, typename OwnerType, typename Dispatch>
  300. class Handle {
  301. public:
  302. /// Construct a handle and hold it's ownership.
  303. explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept
  304. : handle{handle_}, owner{owner_}, dld{&dld_} {}
  305. /// Construct an empty handle.
  306. Handle() = default;
  307. /// Copying Vulkan objects is not supported and will never be.
  308. Handle(const Handle&) = delete;
  309. Handle& operator=(const Handle&) = delete;
  310. /// Construct a handle transfering the ownership from another handle.
  311. Handle(Handle&& rhs) noexcept
  312. : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {}
  313. /// Assign the current handle transfering the ownership from another handle.
  314. /// Destroys any previously held object.
  315. Handle& operator=(Handle&& rhs) noexcept {
  316. Release();
  317. handle = std::exchange(rhs.handle, nullptr);
  318. owner = rhs.owner;
  319. dld = rhs.dld;
  320. return *this;
  321. }
  322. /// Destroys the current handle if it existed.
  323. ~Handle() noexcept {
  324. Release();
  325. }
  326. /// Destroys any held object.
  327. void reset() noexcept {
  328. Release();
  329. handle = nullptr;
  330. }
  331. /// Returns the address of the held object.
  332. /// Intended for Vulkan structures that expect a pointer to an array.
  333. const Type* address() const noexcept {
  334. return std::addressof(handle);
  335. }
  336. /// Returns the held Vulkan handle.
  337. Type operator*() const noexcept {
  338. return handle;
  339. }
  340. /// Returns true when there's a held object.
  341. explicit operator bool() const noexcept {
  342. return handle != nullptr;
  343. }
  344. protected:
  345. Type handle = nullptr;
  346. OwnerType owner = nullptr;
  347. const Dispatch* dld = nullptr;
  348. private:
  349. /// Destroys the held object if it exists.
  350. void Release() noexcept {
  351. if (handle) {
  352. Destroy(owner, handle, *dld);
  353. }
  354. }
  355. };
  356. /// Dummy type used to specify a handle has no owner.
  357. struct NoOwner {};
  358. /// Handle without an owning type.
  359. /// Analogue to std::unique_ptr
  360. template <typename Type, typename Dispatch>
  361. class Handle<Type, NoOwner, Dispatch> {
  362. public:
  363. /// Construct a handle and hold it's ownership.
  364. explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {}
  365. /// Construct an empty handle.
  366. Handle() noexcept = default;
  367. /// Copying Vulkan objects is not supported and will never be.
  368. Handle(const Handle&) = delete;
  369. Handle& operator=(const Handle&) = delete;
  370. /// Construct a handle transfering ownership from another handle.
  371. Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {}
  372. /// Assign the current handle transfering the ownership from another handle.
  373. /// Destroys any previously held object.
  374. Handle& operator=(Handle&& rhs) noexcept {
  375. Release();
  376. handle = std::exchange(rhs.handle, nullptr);
  377. dld = rhs.dld;
  378. return *this;
  379. }
  380. /// Destroys the current handle if it existed.
  381. ~Handle() noexcept {
  382. Release();
  383. }
  384. /// Destroys any held object.
  385. void reset() noexcept {
  386. Release();
  387. handle = nullptr;
  388. }
  389. /// Returns the address of the held object.
  390. /// Intended for Vulkan structures that expect a pointer to an array.
  391. const Type* address() const noexcept {
  392. return std::addressof(handle);
  393. }
  394. /// Returns the held Vulkan handle.
  395. Type operator*() const noexcept {
  396. return handle;
  397. }
  398. /// Returns true when there's a held object.
  399. operator bool() const noexcept {
  400. return handle != nullptr;
  401. }
  402. protected:
  403. Type handle = nullptr;
  404. const Dispatch* dld = nullptr;
  405. private:
  406. /// Destroys the held object if it exists.
  407. void Release() noexcept {
  408. if (handle) {
  409. Destroy(handle, *dld);
  410. }
  411. }
  412. };
  413. /// Array of a pool allocation.
  414. /// Analogue to std::vector
  415. template <typename AllocationType, typename PoolType>
  416. class PoolAllocations {
  417. public:
  418. /// Construct an empty allocation.
  419. PoolAllocations() = default;
  420. /// Construct an allocation. Errors are reported through IsOutOfPoolMemory().
  421. explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations_, std::size_t num_,
  422. VkDevice device_, PoolType pool_, const DeviceDispatch& dld_) noexcept
  423. : allocations{std::move(allocations_)}, num{num_}, device{device_}, pool{pool_},
  424. dld{&dld_} {}
  425. /// Copying Vulkan allocations is not supported and will never be.
  426. PoolAllocations(const PoolAllocations&) = delete;
  427. PoolAllocations& operator=(const PoolAllocations&) = delete;
  428. /// Construct an allocation transfering ownership from another allocation.
  429. PoolAllocations(PoolAllocations&& rhs) noexcept
  430. : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool},
  431. dld{rhs.dld} {}
  432. /// Assign an allocation transfering ownership from another allocation.
  433. /// Releases any previously held allocation.
  434. PoolAllocations& operator=(PoolAllocations&& rhs) noexcept {
  435. Release();
  436. allocations = std::move(rhs.allocations);
  437. num = rhs.num;
  438. device = rhs.device;
  439. pool = rhs.pool;
  440. dld = rhs.dld;
  441. return *this;
  442. }
  443. /// Destroys any held allocation.
  444. ~PoolAllocations() {
  445. Release();
  446. }
  447. /// Returns the number of allocations.
  448. std::size_t size() const noexcept {
  449. return num;
  450. }
  451. /// Returns a pointer to the array of allocations.
  452. AllocationType const* data() const noexcept {
  453. return allocations.get();
  454. }
  455. /// Returns the allocation in the specified index.
  456. /// @pre index < size()
  457. AllocationType operator[](std::size_t index) const noexcept {
  458. return allocations[index];
  459. }
  460. /// True when a pool fails to construct.
  461. bool IsOutOfPoolMemory() const noexcept {
  462. return !device;
  463. }
  464. private:
  465. /// Destroys the held allocations if they exist.
  466. void Release() noexcept {
  467. if (!allocations) {
  468. return;
  469. }
  470. const Span<AllocationType> span(allocations.get(), num);
  471. const VkResult result = Free(device, pool, span, *dld);
  472. // There's no way to report errors from a destructor.
  473. if (result != VK_SUCCESS) {
  474. std::terminate();
  475. }
  476. }
  477. std::unique_ptr<AllocationType[]> allocations;
  478. std::size_t num = 0;
  479. VkDevice device = nullptr;
  480. PoolType pool = nullptr;
  481. const DeviceDispatch* dld = nullptr;
  482. };
  483. using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
  484. using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
  485. using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
  486. using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
  487. using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;
  488. using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>;
  489. using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>;
  490. using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>;
  491. using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
  492. using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>;
  493. using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>;
  494. /// Vulkan instance owning handle.
  495. class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
  496. using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
  497. public:
  498. /// Creates a Vulkan instance.
  499. /// @throw Exception on initialization error.
  500. static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
  501. InstanceDispatch& dispatch);
  502. /// Enumerates physical devices.
  503. /// @return Physical devices and an empty handle on failure.
  504. std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices() const;
  505. /// Creates a debug callback messenger.
  506. /// @throw Exception on creation failure.
  507. DebugUtilsMessenger CreateDebugUtilsMessenger(
  508. const VkDebugUtilsMessengerCreateInfoEXT& create_info) const;
  509. /// Returns dispatch table.
  510. const InstanceDispatch& Dispatch() const noexcept {
  511. return *dld;
  512. }
  513. };
  514. class Queue {
  515. public:
  516. /// Construct an empty queue handle.
  517. constexpr Queue() noexcept = default;
  518. /// Construct a queue handle.
  519. constexpr Queue(VkQueue queue_, const DeviceDispatch& dld_) noexcept
  520. : queue{queue_}, dld{&dld_} {}
  521. VkResult Submit(Span<VkSubmitInfo> submit_infos,
  522. VkFence fence = VK_NULL_HANDLE) const noexcept {
  523. return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence);
  524. }
  525. VkResult Present(const VkPresentInfoKHR& present_info) const noexcept {
  526. return dld->vkQueuePresentKHR(queue, &present_info);
  527. }
  528. private:
  529. VkQueue queue = nullptr;
  530. const DeviceDispatch* dld = nullptr;
  531. };
  532. class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
  533. using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
  534. public:
  535. /// Attaches a memory allocation.
  536. void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
  537. /// Set object name.
  538. void SetObjectNameEXT(const char* name) const;
  539. };
  540. class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> {
  541. using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle;
  542. public:
  543. /// Set object name.
  544. void SetObjectNameEXT(const char* name) const;
  545. };
  546. class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
  547. using Handle<VkImage, VkDevice, DeviceDispatch>::Handle;
  548. public:
  549. /// Attaches a memory allocation.
  550. void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
  551. /// Set object name.
  552. void SetObjectNameEXT(const char* name) const;
  553. };
  554. class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> {
  555. using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle;
  556. public:
  557. /// Set object name.
  558. void SetObjectNameEXT(const char* name) const;
  559. };
  560. class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> {
  561. using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle;
  562. public:
  563. /// Set object name.
  564. void SetObjectNameEXT(const char* name) const;
  565. u8* Map(VkDeviceSize offset, VkDeviceSize size) const {
  566. void* data;
  567. Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data));
  568. return static_cast<u8*>(data);
  569. }
  570. void Unmap() const noexcept {
  571. dld->vkUnmapMemory(owner, handle);
  572. }
  573. };
  574. class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> {
  575. using Handle<VkFence, VkDevice, DeviceDispatch>::Handle;
  576. public:
  577. /// Set object name.
  578. void SetObjectNameEXT(const char* name) const;
  579. VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept {
  580. return dld->vkWaitForFences(owner, 1, &handle, true, timeout);
  581. }
  582. VkResult GetStatus() const noexcept {
  583. return dld->vkGetFenceStatus(owner, handle);
  584. }
  585. void Reset() const {
  586. Check(dld->vkResetFences(owner, 1, &handle));
  587. }
  588. };
  589. class Framebuffer : public Handle<VkFramebuffer, VkDevice, DeviceDispatch> {
  590. using Handle<VkFramebuffer, VkDevice, DeviceDispatch>::Handle;
  591. public:
  592. /// Set object name.
  593. void SetObjectNameEXT(const char* name) const;
  594. };
  595. class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> {
  596. using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle;
  597. public:
  598. DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const;
  599. /// Set object name.
  600. void SetObjectNameEXT(const char* name) const;
  601. };
  602. class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> {
  603. using Handle<VkCommandPool, VkDevice, DeviceDispatch>::Handle;
  604. public:
  605. CommandBuffers Allocate(std::size_t num_buffers,
  606. VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const;
  607. /// Set object name.
  608. void SetObjectNameEXT(const char* name) const;
  609. };
  610. class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> {
  611. using Handle<VkSwapchainKHR, VkDevice, DeviceDispatch>::Handle;
  612. public:
  613. std::vector<VkImage> GetImages() const;
  614. };
  615. class Event : public Handle<VkEvent, VkDevice, DeviceDispatch> {
  616. using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle;
  617. public:
  618. /// Set object name.
  619. void SetObjectNameEXT(const char* name) const;
  620. VkResult GetStatus() const noexcept {
  621. return dld->vkGetEventStatus(owner, handle);
  622. }
  623. };
  624. class ShaderModule : public Handle<VkShaderModule, VkDevice, DeviceDispatch> {
  625. using Handle<VkShaderModule, VkDevice, DeviceDispatch>::Handle;
  626. public:
  627. /// Set object name.
  628. void SetObjectNameEXT(const char* name) const;
  629. };
  630. class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> {
  631. using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle;
  632. public:
  633. /// Set object name.
  634. void SetObjectNameEXT(const char* name) const;
  635. [[nodiscard]] u64 GetCounter() const {
  636. u64 value;
  637. Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value));
  638. return value;
  639. }
  640. /**
  641. * Waits for a timeline semaphore on the host.
  642. *
  643. * @param value Value to wait
  644. * @param timeout Time in nanoseconds to timeout
  645. * @return True on successful wait, false on timeout
  646. */
  647. bool Wait(u64 value, u64 timeout = std::numeric_limits<u64>::max()) const {
  648. const VkSemaphoreWaitInfoKHR wait_info{
  649. .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR,
  650. .pNext = nullptr,
  651. .flags = 0,
  652. .semaphoreCount = 1,
  653. .pSemaphores = &handle,
  654. .pValues = &value,
  655. };
  656. const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout);
  657. switch (result) {
  658. case VK_SUCCESS:
  659. return true;
  660. case VK_TIMEOUT:
  661. return false;
  662. default:
  663. throw Exception(result);
  664. }
  665. }
  666. };
  667. class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
  668. using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle;
  669. public:
  670. static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
  671. Span<const char*> enabled_extensions, const void* next,
  672. DeviceDispatch& dispatch) noexcept;
  673. Queue GetQueue(u32 family_index) const noexcept;
  674. Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
  675. BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
  676. Image CreateImage(const VkImageCreateInfo& ci) const;
  677. ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
  678. Semaphore CreateSemaphore() const;
  679. Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const;
  680. Fence CreateFence(const VkFenceCreateInfo& ci) const;
  681. DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const;
  682. RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const;
  683. DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const;
  684. PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const;
  685. Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const;
  686. Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const;
  687. Sampler CreateSampler(const VkSamplerCreateInfo& ci) const;
  688. Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const;
  689. CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const;
  690. DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR(
  691. const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const;
  692. QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const;
  693. ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
  694. Event CreateEvent() const;
  695. SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
  696. DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept;
  697. DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const;
  698. VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept;
  699. VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept;
  700. void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
  701. Span<VkCopyDescriptorSet> copies) const noexcept;
  702. void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template,
  703. const void* data) const noexcept {
  704. dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data);
  705. }
  706. VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore,
  707. VkFence fence, u32* image_index) const noexcept {
  708. return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence,
  709. image_index);
  710. }
  711. VkResult WaitIdle() const noexcept {
  712. return dld->vkDeviceWaitIdle(handle);
  713. }
  714. void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept {
  715. dld->vkResetQueryPoolEXT(handle, query_pool, first, count);
  716. }
  717. VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
  718. void* data, VkDeviceSize stride,
  719. VkQueryResultFlags flags) const noexcept {
  720. return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride,
  721. flags);
  722. }
  723. };
  724. class PhysicalDevice {
  725. public:
  726. constexpr PhysicalDevice() noexcept = default;
  727. constexpr PhysicalDevice(VkPhysicalDevice physical_device_,
  728. const InstanceDispatch& dld_) noexcept
  729. : physical_device{physical_device_}, dld{&dld_} {}
  730. constexpr operator VkPhysicalDevice() const noexcept {
  731. return physical_device;
  732. }
  733. VkPhysicalDeviceProperties GetProperties() const noexcept;
  734. void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept;
  735. VkPhysicalDeviceFeatures GetFeatures() const noexcept;
  736. void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept;
  737. VkFormatProperties GetFormatProperties(VkFormat) const noexcept;
  738. std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties() const;
  739. std::vector<VkQueueFamilyProperties> GetQueueFamilyProperties() const;
  740. bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const;
  741. VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const;
  742. std::vector<VkSurfaceFormatKHR> GetSurfaceFormatsKHR(VkSurfaceKHR) const;
  743. std::vector<VkPresentModeKHR> GetSurfacePresentModesKHR(VkSurfaceKHR) const;
  744. VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept;
  745. private:
  746. VkPhysicalDevice physical_device = nullptr;
  747. const InstanceDispatch* dld = nullptr;
  748. };
  749. class CommandBuffer {
  750. public:
  751. CommandBuffer() noexcept = default;
  752. explicit CommandBuffer(VkCommandBuffer handle_, const DeviceDispatch& dld_) noexcept
  753. : handle{handle_}, dld{&dld_} {}
  754. const VkCommandBuffer* address() const noexcept {
  755. return &handle;
  756. }
  757. void Begin(const VkCommandBufferBeginInfo& begin_info) const {
  758. Check(dld->vkBeginCommandBuffer(handle, &begin_info));
  759. }
  760. void End() const {
  761. Check(dld->vkEndCommandBuffer(handle));
  762. }
  763. void BeginRenderPass(const VkRenderPassBeginInfo& renderpass_bi,
  764. VkSubpassContents contents) const noexcept {
  765. dld->vkCmdBeginRenderPass(handle, &renderpass_bi, contents);
  766. }
  767. void EndRenderPass() const noexcept {
  768. dld->vkCmdEndRenderPass(handle);
  769. }
  770. void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept {
  771. dld->vkCmdBeginQuery(handle, query_pool, query, flags);
  772. }
  773. void EndQuery(VkQueryPool query_pool, u32 query) const noexcept {
  774. dld->vkCmdEndQuery(handle, query_pool, query);
  775. }
  776. void BindDescriptorSets(VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 first,
  777. Span<VkDescriptorSet> sets, Span<u32> dynamic_offsets) const noexcept {
  778. dld->vkCmdBindDescriptorSets(handle, bind_point, layout, first, sets.size(), sets.data(),
  779. dynamic_offsets.size(), dynamic_offsets.data());
  780. }
  781. void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept {
  782. dld->vkCmdBindPipeline(handle, bind_point, pipeline);
  783. }
  784. void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset,
  785. VkIndexType index_type) const noexcept {
  786. dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type);
  787. }
  788. void BindVertexBuffers(u32 first, u32 count, const VkBuffer* buffers,
  789. const VkDeviceSize* offsets) const noexcept {
  790. dld->vkCmdBindVertexBuffers(handle, first, count, buffers, offsets);
  791. }
  792. void BindVertexBuffer(u32 binding, VkBuffer buffer, VkDeviceSize offset) const noexcept {
  793. BindVertexBuffers(binding, 1, &buffer, &offset);
  794. }
  795. void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex,
  796. u32 first_instance) const noexcept {
  797. dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance);
  798. }
  799. void DrawIndexed(u32 index_count, u32 instance_count, u32 first_index, u32 vertex_offset,
  800. u32 first_instance) const noexcept {
  801. dld->vkCmdDrawIndexed(handle, index_count, instance_count, first_index, vertex_offset,
  802. first_instance);
  803. }
  804. void ClearAttachments(Span<VkClearAttachment> attachments,
  805. Span<VkClearRect> rects) const noexcept {
  806. dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
  807. rects.data());
  808. }
  809. void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
  810. VkImageLayout dst_layout, Span<VkImageBlit> regions,
  811. VkFilter filter) const noexcept {
  812. dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
  813. regions.data(), filter);
  814. }
  815. void ResolveImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
  816. VkImageLayout dst_layout, Span<VkImageResolve> regions) {
  817. dld->vkCmdResolveImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
  818. regions.data());
  819. }
  820. void Dispatch(u32 x, u32 y, u32 z) const noexcept {
  821. dld->vkCmdDispatch(handle, x, y, z);
  822. }
  823. void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
  824. VkDependencyFlags dependency_flags, Span<VkMemoryBarrier> memory_barriers,
  825. Span<VkBufferMemoryBarrier> buffer_barriers,
  826. Span<VkImageMemoryBarrier> image_barriers) const noexcept {
  827. dld->vkCmdPipelineBarrier(handle, src_stage_mask, dst_stage_mask, dependency_flags,
  828. memory_barriers.size(), memory_barriers.data(),
  829. buffer_barriers.size(), buffer_barriers.data(),
  830. image_barriers.size(), image_barriers.data());
  831. }
  832. void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
  833. VkDependencyFlags dependency_flags = 0) const noexcept {
  834. PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, {});
  835. }
  836. void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
  837. VkDependencyFlags dependency_flags,
  838. const VkBufferMemoryBarrier& buffer_barrier) const noexcept {
  839. PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, buffer_barrier, {});
  840. }
  841. void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
  842. VkDependencyFlags dependency_flags,
  843. const VkImageMemoryBarrier& image_barrier) const noexcept {
  844. PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, image_barrier);
  845. }
  846. void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout,
  847. Span<VkBufferImageCopy> regions) const noexcept {
  848. dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(),
  849. regions.data());
  850. }
  851. void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer,
  852. Span<VkBufferCopy> regions) const noexcept {
  853. dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data());
  854. }
  855. void CopyImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
  856. VkImageLayout dst_layout, Span<VkImageCopy> regions) const noexcept {
  857. dld->vkCmdCopyImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
  858. regions.data());
  859. }
  860. void CopyImageToBuffer(VkImage src_image, VkImageLayout src_layout, VkBuffer dst_buffer,
  861. Span<VkBufferImageCopy> regions) const noexcept {
  862. dld->vkCmdCopyImageToBuffer(handle, src_image, src_layout, dst_buffer, regions.size(),
  863. regions.data());
  864. }
  865. void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size,
  866. u32 data) const noexcept {
  867. dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data);
  868. }
  869. void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, u32 offset, u32 size,
  870. const void* values) const noexcept {
  871. dld->vkCmdPushConstants(handle, layout, flags, offset, size, values);
  872. }
  873. template <typename T>
  874. void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags,
  875. const T& data) const noexcept {
  876. static_assert(std::is_trivially_copyable_v<T>, "<data> is not trivially copyable");
  877. dld->vkCmdPushConstants(handle, layout, flags, 0, static_cast<u32>(sizeof(T)), &data);
  878. }
  879. void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept {
  880. dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data());
  881. }
  882. void SetScissor(u32 first, Span<VkRect2D> scissors) const noexcept {
  883. dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data());
  884. }
  885. void SetBlendConstants(const float blend_constants[4]) const noexcept {
  886. dld->vkCmdSetBlendConstants(handle, blend_constants);
  887. }
  888. void SetStencilCompareMask(VkStencilFaceFlags face_mask, u32 compare_mask) const noexcept {
  889. dld->vkCmdSetStencilCompareMask(handle, face_mask, compare_mask);
  890. }
  891. void SetStencilReference(VkStencilFaceFlags face_mask, u32 reference) const noexcept {
  892. dld->vkCmdSetStencilReference(handle, face_mask, reference);
  893. }
  894. void SetStencilWriteMask(VkStencilFaceFlags face_mask, u32 write_mask) const noexcept {
  895. dld->vkCmdSetStencilWriteMask(handle, face_mask, write_mask);
  896. }
  897. void SetDepthBias(float constant_factor, float clamp, float slope_factor) const noexcept {
  898. dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor);
  899. }
  900. void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept {
  901. dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds);
  902. }
  903. void SetEvent(VkEvent event, VkPipelineStageFlags stage_flags) const noexcept {
  904. dld->vkCmdSetEvent(handle, event, stage_flags);
  905. }
  906. void WaitEvents(Span<VkEvent> events, VkPipelineStageFlags src_stage_mask,
  907. VkPipelineStageFlags dst_stage_mask, Span<VkMemoryBarrier> memory_barriers,
  908. Span<VkBufferMemoryBarrier> buffer_barriers,
  909. Span<VkImageMemoryBarrier> image_barriers) const noexcept {
  910. dld->vkCmdWaitEvents(handle, events.size(), events.data(), src_stage_mask, dst_stage_mask,
  911. memory_barriers.size(), memory_barriers.data(), buffer_barriers.size(),
  912. buffer_barriers.data(), image_barriers.size(), image_barriers.data());
  913. }
  914. void BindVertexBuffers2EXT(u32 first_binding, u32 binding_count, const VkBuffer* buffers,
  915. const VkDeviceSize* offsets, const VkDeviceSize* sizes,
  916. const VkDeviceSize* strides) const noexcept {
  917. dld->vkCmdBindVertexBuffers2EXT(handle, first_binding, binding_count, buffers, offsets,
  918. sizes, strides);
  919. }
  920. void SetCullModeEXT(VkCullModeFlags cull_mode) const noexcept {
  921. dld->vkCmdSetCullModeEXT(handle, cull_mode);
  922. }
  923. void SetDepthBoundsTestEnableEXT(bool enable) const noexcept {
  924. dld->vkCmdSetDepthBoundsTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
  925. }
  926. void SetDepthCompareOpEXT(VkCompareOp compare_op) const noexcept {
  927. dld->vkCmdSetDepthCompareOpEXT(handle, compare_op);
  928. }
  929. void SetDepthTestEnableEXT(bool enable) const noexcept {
  930. dld->vkCmdSetDepthTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
  931. }
  932. void SetDepthWriteEnableEXT(bool enable) const noexcept {
  933. dld->vkCmdSetDepthWriteEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
  934. }
  935. void SetFrontFaceEXT(VkFrontFace front_face) const noexcept {
  936. dld->vkCmdSetFrontFaceEXT(handle, front_face);
  937. }
  938. void SetPrimitiveTopologyEXT(VkPrimitiveTopology primitive_topology) const noexcept {
  939. dld->vkCmdSetPrimitiveTopologyEXT(handle, primitive_topology);
  940. }
  941. void SetStencilOpEXT(VkStencilFaceFlags face_mask, VkStencilOp fail_op, VkStencilOp pass_op,
  942. VkStencilOp depth_fail_op, VkCompareOp compare_op) const noexcept {
  943. dld->vkCmdSetStencilOpEXT(handle, face_mask, fail_op, pass_op, depth_fail_op, compare_op);
  944. }
  945. void SetStencilTestEnableEXT(bool enable) const noexcept {
  946. dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
  947. }
  948. void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers,
  949. const VkDeviceSize* offsets,
  950. const VkDeviceSize* sizes) const noexcept {
  951. dld->vkCmdBindTransformFeedbackBuffersEXT(handle, first, count, buffers, offsets, sizes);
  952. }
  953. void BeginTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
  954. const VkBuffer* counter_buffers,
  955. const VkDeviceSize* counter_buffer_offsets) const noexcept {
  956. dld->vkCmdBeginTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
  957. counter_buffers, counter_buffer_offsets);
  958. }
  959. void EndTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
  960. const VkBuffer* counter_buffers,
  961. const VkDeviceSize* counter_buffer_offsets) const noexcept {
  962. dld->vkCmdEndTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
  963. counter_buffers, counter_buffer_offsets);
  964. }
  965. void BeginDebugUtilsLabelEXT(const char* label, std::span<float, 4> color) const noexcept {
  966. const VkDebugUtilsLabelEXT label_info{
  967. .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
  968. .pNext = nullptr,
  969. .pLabelName = label,
  970. .color{color[0], color[1], color[2], color[3]},
  971. };
  972. dld->vkCmdBeginDebugUtilsLabelEXT(handle, &label_info);
  973. }
  974. void EndDebugUtilsLabelEXT() const noexcept {
  975. dld->vkCmdEndDebugUtilsLabelEXT(handle);
  976. }
  977. private:
  978. VkCommandBuffer handle;
  979. const DeviceDispatch* dld;
  980. };
  981. u32 AvailableVersion(const InstanceDispatch& dld) noexcept;
  982. std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
  983. const InstanceDispatch& dld);
  984. std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties(
  985. const InstanceDispatch& dld);
  986. } // namespace Vulkan::vk