diff options
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/wrapper.cpp | 342 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/wrapper.h | 545 |
3 files changed, 889 insertions, 0 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 91df062d7..effe76a63 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -210,6 +210,8 @@ if (ENABLE_VULKAN) | |||
| 210 | renderer_vulkan/vk_texture_cache.h | 210 | renderer_vulkan/vk_texture_cache.h |
| 211 | renderer_vulkan/vk_update_descriptor.cpp | 211 | renderer_vulkan/vk_update_descriptor.cpp |
| 212 | renderer_vulkan/vk_update_descriptor.h | 212 | renderer_vulkan/vk_update_descriptor.h |
| 213 | renderer_vulkan/wrapper.cpp | ||
| 214 | renderer_vulkan/wrapper.h | ||
| 213 | ) | 215 | ) |
| 214 | 216 | ||
| 215 | target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) | 217 | target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) |
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp new file mode 100644 index 000000000..c412b7f20 --- /dev/null +++ b/src/video_core/renderer_vulkan/wrapper.cpp | |||
| @@ -0,0 +1,342 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <exception> | ||
| 6 | #include <memory> | ||
| 7 | #include <optional> | ||
| 8 | #include <utility> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 13 | #include "video_core/renderer_vulkan/wrapper.h" | ||
| 14 | |||
| 15 | namespace Vulkan::vk { | ||
| 16 | |||
| 17 | namespace { | ||
| 18 | |||
| 19 | template <typename T> | ||
| 20 | bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name, | ||
| 21 | VkInstance instance = nullptr) noexcept { | ||
| 22 | result = reinterpret_cast<T>(dld.vkGetInstanceProcAddr(instance, proc_name)); | ||
| 23 | return result != nullptr; | ||
| 24 | } | ||
| 25 | |||
| 26 | template <typename T> | ||
| 27 | void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept { | ||
| 28 | result = reinterpret_cast<T>(dld.vkGetDeviceProcAddr(device, proc_name)); | ||
| 29 | } | ||
| 30 | |||
| 31 | void Load(VkDevice device, DeviceDispatch& dld) noexcept { | ||
| 32 | #define X(name) Proc(dld.name, dld, #name, device) | ||
| 33 | X(vkAcquireNextImageKHR); | ||
| 34 | X(vkAllocateCommandBuffers); | ||
| 35 | X(vkAllocateDescriptorSets); | ||
| 36 | X(vkAllocateMemory); | ||
| 37 | X(vkBeginCommandBuffer); | ||
| 38 | X(vkBindBufferMemory); | ||
| 39 | X(vkBindImageMemory); | ||
| 40 | X(vkCmdBeginQuery); | ||
| 41 | X(vkCmdBeginRenderPass); | ||
| 42 | X(vkCmdBeginTransformFeedbackEXT); | ||
| 43 | X(vkCmdBindDescriptorSets); | ||
| 44 | X(vkCmdBindIndexBuffer); | ||
| 45 | X(vkCmdBindPipeline); | ||
| 46 | X(vkCmdBindTransformFeedbackBuffersEXT); | ||
| 47 | X(vkCmdBindVertexBuffers); | ||
| 48 | X(vkCmdBlitImage); | ||
| 49 | X(vkCmdClearAttachments); | ||
| 50 | X(vkCmdCopyBuffer); | ||
| 51 | X(vkCmdCopyBufferToImage); | ||
| 52 | X(vkCmdCopyImage); | ||
| 53 | X(vkCmdCopyImageToBuffer); | ||
| 54 | X(vkCmdDispatch); | ||
| 55 | X(vkCmdDraw); | ||
| 56 | X(vkCmdDrawIndexed); | ||
| 57 | X(vkCmdEndQuery); | ||
| 58 | X(vkCmdEndRenderPass); | ||
| 59 | X(vkCmdEndTransformFeedbackEXT); | ||
| 60 | X(vkCmdFillBuffer); | ||
| 61 | X(vkCmdPipelineBarrier); | ||
| 62 | X(vkCmdPushConstants); | ||
| 63 | X(vkCmdSetBlendConstants); | ||
| 64 | X(vkCmdSetCheckpointNV); | ||
| 65 | X(vkCmdSetDepthBias); | ||
| 66 | X(vkCmdSetDepthBounds); | ||
| 67 | X(vkCmdSetScissor); | ||
| 68 | X(vkCmdSetStencilCompareMask); | ||
| 69 | X(vkCmdSetStencilReference); | ||
| 70 | X(vkCmdSetStencilWriteMask); | ||
| 71 | X(vkCmdSetViewport); | ||
| 72 | X(vkCreateBuffer); | ||
| 73 | X(vkCreateBufferView); | ||
| 74 | X(vkCreateCommandPool); | ||
| 75 | X(vkCreateComputePipelines); | ||
| 76 | X(vkCreateDescriptorPool); | ||
| 77 | X(vkCreateDescriptorSetLayout); | ||
| 78 | X(vkCreateDescriptorUpdateTemplateKHR); | ||
| 79 | X(vkCreateFence); | ||
| 80 | X(vkCreateFramebuffer); | ||
| 81 | X(vkCreateGraphicsPipelines); | ||
| 82 | X(vkCreateImage); | ||
| 83 | X(vkCreateImageView); | ||
| 84 | X(vkCreatePipelineLayout); | ||
| 85 | X(vkCreateQueryPool); | ||
| 86 | X(vkCreateRenderPass); | ||
| 87 | X(vkCreateSampler); | ||
| 88 | X(vkCreateSemaphore); | ||
| 89 | X(vkCreateShaderModule); | ||
| 90 | X(vkCreateSwapchainKHR); | ||
| 91 | X(vkDestroyBuffer); | ||
| 92 | X(vkDestroyBufferView); | ||
| 93 | X(vkDestroyCommandPool); | ||
| 94 | X(vkDestroyDescriptorPool); | ||
| 95 | X(vkDestroyDescriptorSetLayout); | ||
| 96 | X(vkDestroyDescriptorUpdateTemplateKHR); | ||
| 97 | X(vkDestroyFence); | ||
| 98 | X(vkDestroyFramebuffer); | ||
| 99 | X(vkDestroyImage); | ||
| 100 | X(vkDestroyImageView); | ||
| 101 | X(vkDestroyPipeline); | ||
| 102 | X(vkDestroyPipelineLayout); | ||
| 103 | X(vkDestroyQueryPool); | ||
| 104 | X(vkDestroyRenderPass); | ||
| 105 | X(vkDestroySampler); | ||
| 106 | X(vkDestroySemaphore); | ||
| 107 | X(vkDestroyShaderModule); | ||
| 108 | X(vkDestroySwapchainKHR); | ||
| 109 | X(vkDeviceWaitIdle); | ||
| 110 | X(vkEndCommandBuffer); | ||
| 111 | X(vkFreeCommandBuffers); | ||
| 112 | X(vkFreeDescriptorSets); | ||
| 113 | X(vkFreeMemory); | ||
| 114 | X(vkGetBufferMemoryRequirements); | ||
| 115 | X(vkGetDeviceQueue); | ||
| 116 | X(vkGetFenceStatus); | ||
| 117 | X(vkGetImageMemoryRequirements); | ||
| 118 | X(vkGetQueryPoolResults); | ||
| 119 | X(vkGetQueueCheckpointDataNV); | ||
| 120 | X(vkMapMemory); | ||
| 121 | X(vkQueueSubmit); | ||
| 122 | X(vkResetFences); | ||
| 123 | X(vkResetQueryPoolEXT); | ||
| 124 | X(vkUnmapMemory); | ||
| 125 | X(vkUpdateDescriptorSetWithTemplateKHR); | ||
| 126 | X(vkUpdateDescriptorSets); | ||
| 127 | X(vkWaitForFences); | ||
| 128 | #undef X | ||
| 129 | } | ||
| 130 | |||
| 131 | } // Anonymous namespace | ||
| 132 | |||
| 133 | bool Load(InstanceDispatch& dld) noexcept { | ||
| 134 | #define X(name) Proc(dld.name, dld, #name) | ||
| 135 | return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties); | ||
| 136 | #undef X | ||
| 137 | } | ||
| 138 | |||
| 139 | bool Load(VkInstance instance, InstanceDispatch& dld) noexcept { | ||
| 140 | #define X(name) Proc(dld.name, dld, #name, instance) | ||
| 141 | // These functions may fail to load depending on the enabled extensions. | ||
| 142 | // Don't return a failure on these. | ||
| 143 | X(vkCreateDebugUtilsMessengerEXT); | ||
| 144 | X(vkDestroyDebugUtilsMessengerEXT); | ||
| 145 | X(vkDestroySurfaceKHR); | ||
| 146 | X(vkGetPhysicalDeviceFeatures2KHR); | ||
| 147 | X(vkGetPhysicalDeviceProperties2KHR); | ||
| 148 | X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); | ||
| 149 | X(vkGetPhysicalDeviceSurfaceFormatsKHR); | ||
| 150 | X(vkGetPhysicalDeviceSurfacePresentModesKHR); | ||
| 151 | X(vkGetPhysicalDeviceSurfaceSupportKHR); | ||
| 152 | X(vkGetSwapchainImagesKHR); | ||
| 153 | X(vkQueuePresentKHR); | ||
| 154 | |||
| 155 | return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) && | ||
| 156 | X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) && | ||
| 157 | X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) && | ||
| 158 | X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) && | ||
| 159 | X(vkGetPhysicalDeviceQueueFamilyProperties); | ||
| 160 | #undef X | ||
| 161 | } | ||
| 162 | |||
| 163 | const char* Exception::what() const noexcept { | ||
| 164 | return ToString(result); | ||
| 165 | } | ||
| 166 | |||
| 167 | const char* ToString(VkResult result) noexcept { | ||
| 168 | switch (result) { | ||
| 169 | case VkResult::VK_SUCCESS: | ||
| 170 | return "VK_SUCCESS"; | ||
| 171 | case VkResult::VK_NOT_READY: | ||
| 172 | return "VK_NOT_READY"; | ||
| 173 | case VkResult::VK_TIMEOUT: | ||
| 174 | return "VK_TIMEOUT"; | ||
| 175 | case VkResult::VK_EVENT_SET: | ||
| 176 | return "VK_EVENT_SET"; | ||
| 177 | case VkResult::VK_EVENT_RESET: | ||
| 178 | return "VK_EVENT_RESET"; | ||
| 179 | case VkResult::VK_INCOMPLETE: | ||
| 180 | return "VK_INCOMPLETE"; | ||
| 181 | case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY: | ||
| 182 | return "VK_ERROR_OUT_OF_HOST_MEMORY"; | ||
| 183 | case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY: | ||
| 184 | return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; | ||
| 185 | case VkResult::VK_ERROR_INITIALIZATION_FAILED: | ||
| 186 | return "VK_ERROR_INITIALIZATION_FAILED"; | ||
| 187 | case VkResult::VK_ERROR_DEVICE_LOST: | ||
| 188 | return "VK_ERROR_DEVICE_LOST"; | ||
| 189 | case VkResult::VK_ERROR_MEMORY_MAP_FAILED: | ||
| 190 | return "VK_ERROR_MEMORY_MAP_FAILED"; | ||
| 191 | case VkResult::VK_ERROR_LAYER_NOT_PRESENT: | ||
| 192 | return "VK_ERROR_LAYER_NOT_PRESENT"; | ||
| 193 | case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT: | ||
| 194 | return "VK_ERROR_EXTENSION_NOT_PRESENT"; | ||
| 195 | case VkResult::VK_ERROR_FEATURE_NOT_PRESENT: | ||
| 196 | return "VK_ERROR_FEATURE_NOT_PRESENT"; | ||
| 197 | case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER: | ||
| 198 | return "VK_ERROR_INCOMPATIBLE_DRIVER"; | ||
| 199 | case VkResult::VK_ERROR_TOO_MANY_OBJECTS: | ||
| 200 | return "VK_ERROR_TOO_MANY_OBJECTS"; | ||
| 201 | case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED: | ||
| 202 | return "VK_ERROR_FORMAT_NOT_SUPPORTED"; | ||
| 203 | case VkResult::VK_ERROR_FRAGMENTED_POOL: | ||
| 204 | return "VK_ERROR_FRAGMENTED_POOL"; | ||
| 205 | case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY: | ||
| 206 | return "VK_ERROR_OUT_OF_POOL_MEMORY"; | ||
| 207 | case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE: | ||
| 208 | return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; | ||
| 209 | case VkResult::VK_ERROR_SURFACE_LOST_KHR: | ||
| 210 | return "VK_ERROR_SURFACE_LOST_KHR"; | ||
| 211 | case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: | ||
| 212 | return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; | ||
| 213 | case VkResult::VK_SUBOPTIMAL_KHR: | ||
| 214 | return "VK_SUBOPTIMAL_KHR"; | ||
| 215 | case VkResult::VK_ERROR_OUT_OF_DATE_KHR: | ||
| 216 | return "VK_ERROR_OUT_OF_DATE_KHR"; | ||
| 217 | case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: | ||
| 218 | return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; | ||
| 219 | case VkResult::VK_ERROR_VALIDATION_FAILED_EXT: | ||
| 220 | return "VK_ERROR_VALIDATION_FAILED_EXT"; | ||
| 221 | case VkResult::VK_ERROR_INVALID_SHADER_NV: | ||
| 222 | return "VK_ERROR_INVALID_SHADER_NV"; | ||
| 223 | case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: | ||
| 224 | return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; | ||
| 225 | case VkResult::VK_ERROR_FRAGMENTATION_EXT: | ||
| 226 | return "VK_ERROR_FRAGMENTATION_EXT"; | ||
| 227 | case VkResult::VK_ERROR_NOT_PERMITTED_EXT: | ||
| 228 | return "VK_ERROR_NOT_PERMITTED_EXT"; | ||
| 229 | case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT: | ||
| 230 | return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT"; | ||
| 231 | case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: | ||
| 232 | return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; | ||
| 233 | } | ||
| 234 | return "Unknown"; | ||
| 235 | } | ||
| 236 | |||
| 237 | void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { | ||
| 238 | dld.vkDestroyInstance(instance, nullptr); | ||
| 239 | } | ||
| 240 | |||
| 241 | void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept { | ||
| 242 | dld.vkDestroyDevice(device, nullptr); | ||
| 243 | } | ||
| 244 | |||
| 245 | void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept { | ||
| 246 | dld.vkDestroyBuffer(device, handle, nullptr); | ||
| 247 | } | ||
| 248 | |||
| 249 | void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept { | ||
| 250 | dld.vkDestroyBufferView(device, handle, nullptr); | ||
| 251 | } | ||
| 252 | |||
| 253 | void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept { | ||
| 254 | dld.vkDestroyCommandPool(device, handle, nullptr); | ||
| 255 | } | ||
| 256 | |||
| 257 | void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept { | ||
| 258 | dld.vkDestroyDescriptorPool(device, handle, nullptr); | ||
| 259 | } | ||
| 260 | |||
| 261 | void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept { | ||
| 262 | dld.vkDestroyDescriptorSetLayout(device, handle, nullptr); | ||
| 263 | } | ||
| 264 | |||
| 265 | void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle, | ||
| 266 | const DeviceDispatch& dld) noexcept { | ||
| 267 | dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr); | ||
| 268 | } | ||
| 269 | |||
| 270 | void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept { | ||
| 271 | dld.vkFreeMemory(device, handle, nullptr); | ||
| 272 | } | ||
| 273 | |||
| 274 | void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept { | ||
| 275 | dld.vkDestroyFence(device, handle, nullptr); | ||
| 276 | } | ||
| 277 | |||
| 278 | void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept { | ||
| 279 | dld.vkDestroyFramebuffer(device, handle, nullptr); | ||
| 280 | } | ||
| 281 | |||
| 282 | void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept { | ||
| 283 | dld.vkDestroyImage(device, handle, nullptr); | ||
| 284 | } | ||
| 285 | |||
| 286 | void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept { | ||
| 287 | dld.vkDestroyImageView(device, handle, nullptr); | ||
| 288 | } | ||
| 289 | |||
| 290 | void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept { | ||
| 291 | dld.vkDestroyPipeline(device, handle, nullptr); | ||
| 292 | } | ||
| 293 | |||
| 294 | void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept { | ||
| 295 | dld.vkDestroyPipelineLayout(device, handle, nullptr); | ||
| 296 | } | ||
| 297 | |||
| 298 | void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept { | ||
| 299 | dld.vkDestroyQueryPool(device, handle, nullptr); | ||
| 300 | } | ||
| 301 | |||
| 302 | void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept { | ||
| 303 | dld.vkDestroyRenderPass(device, handle, nullptr); | ||
| 304 | } | ||
| 305 | |||
| 306 | void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept { | ||
| 307 | dld.vkDestroySampler(device, handle, nullptr); | ||
| 308 | } | ||
| 309 | |||
| 310 | void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept { | ||
| 311 | dld.vkDestroySwapchainKHR(device, handle, nullptr); | ||
| 312 | } | ||
| 313 | |||
| 314 | void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept { | ||
| 315 | dld.vkDestroySemaphore(device, handle, nullptr); | ||
| 316 | } | ||
| 317 | |||
| 318 | void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept { | ||
| 319 | dld.vkDestroyShaderModule(device, handle, nullptr); | ||
| 320 | } | ||
| 321 | |||
| 322 | void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle, | ||
| 323 | const InstanceDispatch& dld) noexcept { | ||
| 324 | dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); | ||
| 325 | } | ||
| 326 | |||
| 327 | void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { | ||
| 328 | dld.vkDestroySurfaceKHR(instance, handle, nullptr); | ||
| 329 | } | ||
| 330 | |||
| 331 | VkResult Free(VkDevice device, VkDescriptorPool handle, Span<VkDescriptorSet> sets, | ||
| 332 | const DeviceDispatch& dld) noexcept { | ||
| 333 | return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data()); | ||
| 334 | } | ||
| 335 | |||
| 336 | VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffers, | ||
| 337 | const DeviceDispatch& dld) noexcept { | ||
| 338 | dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data()); | ||
| 339 | return VK_SUCCESS; | ||
| 340 | } | ||
| 341 | |||
| 342 | } // namespace Vulkan::vk | ||
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h new file mode 100644 index 000000000..686c2b9a1 --- /dev/null +++ b/src/video_core/renderer_vulkan/wrapper.h | |||
| @@ -0,0 +1,545 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <exception> | ||
| 8 | #include <iterator> | ||
| 9 | #include <limits> | ||
| 10 | #include <memory> | ||
| 11 | #include <optional> | ||
| 12 | #include <type_traits> | ||
| 13 | #include <utility> | ||
| 14 | #include <vector> | ||
| 15 | |||
| 16 | #define VK_NO_PROTOTYPES | ||
| 17 | #include <vulkan/vulkan.h> | ||
| 18 | |||
| 19 | #include "common/common_types.h" | ||
| 20 | |||
| 21 | namespace Vulkan::vk { | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Span for Vulkan arrays. | ||
| 25 | * Based on std::span but optimized for array access instead of iterators. | ||
| 26 | * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions. | ||
| 27 | */ | ||
| 28 | template <typename T> | ||
| 29 | class Span { | ||
| 30 | public: | ||
| 31 | using value_type = T; | ||
| 32 | using size_type = u32; | ||
| 33 | using difference_type = std::ptrdiff_t; | ||
| 34 | using reference = const T&; | ||
| 35 | using const_reference = const T&; | ||
| 36 | using pointer = const T*; | ||
| 37 | using const_pointer = const T*; | ||
| 38 | using iterator = const T*; | ||
| 39 | using const_iterator = const T*; | ||
| 40 | |||
| 41 | /// Construct an empty span. | ||
| 42 | constexpr Span() noexcept = default; | ||
| 43 | |||
| 44 | /// Construct a span from a single element. | ||
| 45 | constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} | ||
| 46 | |||
| 47 | /// Construct a span from a range. | ||
| 48 | template <typename Range> | ||
| 49 | // requires std::data(const Range&) | ||
| 50 | // requires std::size(const Range&) | ||
| 51 | constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {} | ||
| 52 | |||
| 53 | /// Construct a span from a pointer and a size. | ||
| 54 | /// This is inteded for subranges. | ||
| 55 | constexpr Span(const T* ptr, std::size_t num) noexcept : ptr{ptr}, num{num} {} | ||
| 56 | |||
| 57 | /// Returns the data pointer by the span. | ||
| 58 | constexpr const T* data() const noexcept { | ||
| 59 | return ptr; | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Returns the number of elements in the span. | ||
| 63 | /// @note Returns a 32 bits integer because most Vulkan functions expect this type. | ||
| 64 | constexpr u32 size() const noexcept { | ||
| 65 | return static_cast<u32>(num); | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Returns true when the span is empty. | ||
| 69 | constexpr bool empty() const noexcept { | ||
| 70 | return num == 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | /// Returns a reference to the element in the passed index. | ||
| 74 | /// @pre: index < size() | ||
| 75 | constexpr const T& operator[](std::size_t index) const noexcept { | ||
| 76 | return ptr[index]; | ||
| 77 | } | ||
| 78 | |||
| 79 | /// Returns an iterator to the beginning of the span. | ||
| 80 | constexpr const T* begin() const noexcept { | ||
| 81 | return ptr; | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Returns an iterator to the end of the span. | ||
| 85 | constexpr const T* end() const noexcept { | ||
| 86 | return ptr + num; | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Returns an iterator to the beginning of the span. | ||
| 90 | constexpr const T* cbegin() const noexcept { | ||
| 91 | return ptr; | ||
| 92 | } | ||
| 93 | |||
| 94 | /// Returns an iterator to the end of the span. | ||
| 95 | constexpr const T* cend() const noexcept { | ||
| 96 | return ptr + num; | ||
| 97 | } | ||
| 98 | |||
| 99 | private: | ||
| 100 | const T* ptr = nullptr; | ||
| 101 | std::size_t num = 0; | ||
| 102 | }; | ||
| 103 | |||
| 104 | /// Vulkan exception generated from a VkResult. | ||
| 105 | class Exception final : public std::exception { | ||
| 106 | public: | ||
| 107 | /// Construct the exception with a result. | ||
| 108 | /// @pre result != VK_SUCCESS | ||
| 109 | explicit Exception(VkResult result_) : result{result_} {} | ||
| 110 | virtual ~Exception() = default; | ||
| 111 | |||
| 112 | const char* what() const noexcept override; | ||
| 113 | |||
| 114 | private: | ||
| 115 | VkResult result; | ||
| 116 | }; | ||
| 117 | |||
| 118 | /// Converts a VkResult enum into a rodata string | ||
| 119 | const char* ToString(VkResult) noexcept; | ||
| 120 | |||
| 121 | /// Throws a Vulkan exception if result is not success. | ||
| 122 | inline void Check(VkResult result) { | ||
| 123 | if (result != VK_SUCCESS) { | ||
| 124 | throw Exception(result); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Throws a Vulkan exception if result is an error. | ||
| 129 | /// @return result | ||
| 130 | inline VkResult Filter(VkResult result) { | ||
| 131 | if (result < 0) { | ||
| 132 | throw Exception(result); | ||
| 133 | } | ||
| 134 | return result; | ||
| 135 | } | ||
| 136 | |||
| 137 | /// Table holding Vulkan instance function pointers. | ||
| 138 | struct InstanceDispatch { | ||
| 139 | PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; | ||
| 140 | |||
| 141 | PFN_vkCreateInstance vkCreateInstance; | ||
| 142 | PFN_vkDestroyInstance vkDestroyInstance; | ||
| 143 | PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; | ||
| 144 | |||
| 145 | PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; | ||
| 146 | PFN_vkCreateDevice vkCreateDevice; | ||
| 147 | PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; | ||
| 148 | PFN_vkDestroyDevice vkDestroyDevice; | ||
| 149 | PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; | ||
| 150 | PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; | ||
| 151 | PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; | ||
| 152 | PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; | ||
| 153 | PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; | ||
| 154 | PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; | ||
| 155 | PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; | ||
| 156 | PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; | ||
| 157 | PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; | ||
| 158 | PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; | ||
| 159 | PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; | ||
| 160 | PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; | ||
| 161 | PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; | ||
| 162 | PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; | ||
| 163 | PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; | ||
| 164 | PFN_vkQueuePresentKHR vkQueuePresentKHR; | ||
| 165 | }; | ||
| 166 | |||
| 167 | /// Table holding Vulkan device function pointers. | ||
| 168 | struct DeviceDispatch : public InstanceDispatch { | ||
| 169 | PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; | ||
| 170 | PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; | ||
| 171 | PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; | ||
| 172 | PFN_vkAllocateMemory vkAllocateMemory; | ||
| 173 | PFN_vkBeginCommandBuffer vkBeginCommandBuffer; | ||
| 174 | PFN_vkBindBufferMemory vkBindBufferMemory; | ||
| 175 | PFN_vkBindImageMemory vkBindImageMemory; | ||
| 176 | PFN_vkCmdBeginQuery vkCmdBeginQuery; | ||
| 177 | PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; | ||
| 178 | PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; | ||
| 179 | PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; | ||
| 180 | PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; | ||
| 181 | PFN_vkCmdBindPipeline vkCmdBindPipeline; | ||
| 182 | PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; | ||
| 183 | PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; | ||
| 184 | PFN_vkCmdBlitImage vkCmdBlitImage; | ||
| 185 | PFN_vkCmdClearAttachments vkCmdClearAttachments; | ||
| 186 | PFN_vkCmdCopyBuffer vkCmdCopyBuffer; | ||
| 187 | PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; | ||
| 188 | PFN_vkCmdCopyImage vkCmdCopyImage; | ||
| 189 | PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; | ||
| 190 | PFN_vkCmdDispatch vkCmdDispatch; | ||
| 191 | PFN_vkCmdDraw vkCmdDraw; | ||
| 192 | PFN_vkCmdDrawIndexed vkCmdDrawIndexed; | ||
| 193 | PFN_vkCmdEndQuery vkCmdEndQuery; | ||
| 194 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass; | ||
| 195 | PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; | ||
| 196 | PFN_vkCmdFillBuffer vkCmdFillBuffer; | ||
| 197 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; | ||
| 198 | PFN_vkCmdPushConstants vkCmdPushConstants; | ||
| 199 | PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; | ||
| 200 | PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; | ||
| 201 | PFN_vkCmdSetDepthBias vkCmdSetDepthBias; | ||
| 202 | PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; | ||
| 203 | PFN_vkCmdSetScissor vkCmdSetScissor; | ||
| 204 | PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; | ||
| 205 | PFN_vkCmdSetStencilReference vkCmdSetStencilReference; | ||
| 206 | PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; | ||
| 207 | PFN_vkCmdSetViewport vkCmdSetViewport; | ||
| 208 | PFN_vkCreateBuffer vkCreateBuffer; | ||
| 209 | PFN_vkCreateBufferView vkCreateBufferView; | ||
| 210 | PFN_vkCreateCommandPool vkCreateCommandPool; | ||
| 211 | PFN_vkCreateComputePipelines vkCreateComputePipelines; | ||
| 212 | PFN_vkCreateDescriptorPool vkCreateDescriptorPool; | ||
| 213 | PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; | ||
| 214 | PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; | ||
| 215 | PFN_vkCreateFence vkCreateFence; | ||
| 216 | PFN_vkCreateFramebuffer vkCreateFramebuffer; | ||
| 217 | PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; | ||
| 218 | PFN_vkCreateImage vkCreateImage; | ||
| 219 | PFN_vkCreateImageView vkCreateImageView; | ||
| 220 | PFN_vkCreatePipelineLayout vkCreatePipelineLayout; | ||
| 221 | PFN_vkCreateQueryPool vkCreateQueryPool; | ||
| 222 | PFN_vkCreateRenderPass vkCreateRenderPass; | ||
| 223 | PFN_vkCreateSampler vkCreateSampler; | ||
| 224 | PFN_vkCreateSemaphore vkCreateSemaphore; | ||
| 225 | PFN_vkCreateShaderModule vkCreateShaderModule; | ||
| 226 | PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; | ||
| 227 | PFN_vkDestroyBuffer vkDestroyBuffer; | ||
| 228 | PFN_vkDestroyBufferView vkDestroyBufferView; | ||
| 229 | PFN_vkDestroyCommandPool vkDestroyCommandPool; | ||
| 230 | PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; | ||
| 231 | PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; | ||
| 232 | PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; | ||
| 233 | PFN_vkDestroyFence vkDestroyFence; | ||
| 234 | PFN_vkDestroyFramebuffer vkDestroyFramebuffer; | ||
| 235 | PFN_vkDestroyImage vkDestroyImage; | ||
| 236 | PFN_vkDestroyImageView vkDestroyImageView; | ||
| 237 | PFN_vkDestroyPipeline vkDestroyPipeline; | ||
| 238 | PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; | ||
| 239 | PFN_vkDestroyQueryPool vkDestroyQueryPool; | ||
| 240 | PFN_vkDestroyRenderPass vkDestroyRenderPass; | ||
| 241 | PFN_vkDestroySampler vkDestroySampler; | ||
| 242 | PFN_vkDestroySemaphore vkDestroySemaphore; | ||
| 243 | PFN_vkDestroyShaderModule vkDestroyShaderModule; | ||
| 244 | PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; | ||
| 245 | PFN_vkDeviceWaitIdle vkDeviceWaitIdle; | ||
| 246 | PFN_vkEndCommandBuffer vkEndCommandBuffer; | ||
| 247 | PFN_vkFreeCommandBuffers vkFreeCommandBuffers; | ||
| 248 | PFN_vkFreeDescriptorSets vkFreeDescriptorSets; | ||
| 249 | PFN_vkFreeMemory vkFreeMemory; | ||
| 250 | PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; | ||
| 251 | PFN_vkGetDeviceQueue vkGetDeviceQueue; | ||
| 252 | PFN_vkGetFenceStatus vkGetFenceStatus; | ||
| 253 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; | ||
| 254 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults; | ||
| 255 | PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; | ||
| 256 | PFN_vkMapMemory vkMapMemory; | ||
| 257 | PFN_vkQueueSubmit vkQueueSubmit; | ||
| 258 | PFN_vkResetFences vkResetFences; | ||
| 259 | PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; | ||
| 260 | PFN_vkUnmapMemory vkUnmapMemory; | ||
| 261 | PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; | ||
| 262 | PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; | ||
| 263 | PFN_vkWaitForFences vkWaitForFences; | ||
| 264 | }; | ||
| 265 | |||
| 266 | /// Loads instance agnostic function pointers. | ||
| 267 | /// @return True on success, false on error. | ||
| 268 | bool Load(InstanceDispatch&) noexcept; | ||
| 269 | |||
| 270 | /// Loads instance function pointers. | ||
| 271 | /// @return True on success, false on error. | ||
| 272 | bool Load(VkInstance, InstanceDispatch&) noexcept; | ||
| 273 | |||
| 274 | void Destroy(VkInstance, const InstanceDispatch&) noexcept; | ||
| 275 | void Destroy(VkDevice, const InstanceDispatch&) noexcept; | ||
| 276 | |||
| 277 | void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept; | ||
| 278 | void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept; | ||
| 279 | void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept; | ||
| 280 | void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept; | ||
| 281 | void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept; | ||
| 282 | void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept; | ||
| 283 | void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept; | ||
| 284 | void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept; | ||
| 285 | void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept; | ||
| 286 | void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept; | ||
| 287 | void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept; | ||
| 288 | void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept; | ||
| 289 | void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept; | ||
| 290 | void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept; | ||
| 291 | void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept; | ||
| 292 | void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept; | ||
| 293 | void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept; | ||
| 294 | void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; | ||
| 295 | void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; | ||
| 296 | void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; | ||
| 297 | void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; | ||
| 298 | |||
| 299 | VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; | ||
| 300 | VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept; | ||
| 301 | |||
| 302 | template <typename Type, typename OwnerType, typename Dispatch> | ||
| 303 | class Handle; | ||
| 304 | |||
| 305 | /// Handle with an owning type. | ||
| 306 | /// Analogue to std::unique_ptr. | ||
| 307 | template <typename Type, typename OwnerType, typename Dispatch> | ||
| 308 | class Handle { | ||
| 309 | public: | ||
| 310 | /// Construct a handle and hold it's ownership. | ||
| 311 | explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept | ||
| 312 | : handle{handle_}, owner{owner_}, dld{&dld_} {} | ||
| 313 | |||
| 314 | /// Construct an empty handle. | ||
| 315 | Handle() = default; | ||
| 316 | |||
| 317 | /// Copying Vulkan objects is not supported and will never be. | ||
| 318 | Handle(const Handle&) = delete; | ||
| 319 | Handle& operator=(const Handle&) = delete; | ||
| 320 | |||
| 321 | /// Construct a handle transfering the ownership from another handle. | ||
| 322 | Handle(Handle&& rhs) noexcept | ||
| 323 | : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {} | ||
| 324 | |||
| 325 | /// Assign the current handle transfering the ownership from another handle. | ||
| 326 | /// Destroys any previously held object. | ||
| 327 | Handle& operator=(Handle&& rhs) noexcept { | ||
| 328 | Release(); | ||
| 329 | handle = std::exchange(rhs.handle, nullptr); | ||
| 330 | owner = rhs.owner; | ||
| 331 | dld = rhs.dld; | ||
| 332 | return *this; | ||
| 333 | } | ||
| 334 | |||
| 335 | /// Destroys the current handle if it existed. | ||
| 336 | ~Handle() noexcept { | ||
| 337 | Release(); | ||
| 338 | } | ||
| 339 | |||
| 340 | /// Destroys any held object. | ||
| 341 | void reset() noexcept { | ||
| 342 | Release(); | ||
| 343 | handle = nullptr; | ||
| 344 | } | ||
| 345 | |||
| 346 | /// Returns the address of the held object. | ||
| 347 | /// Intended for Vulkan structures that expect a pointer to an array. | ||
| 348 | const Type* address() const noexcept { | ||
| 349 | return std::addressof(handle); | ||
| 350 | } | ||
| 351 | |||
| 352 | /// Returns the held Vulkan handle. | ||
| 353 | Type operator*() const noexcept { | ||
| 354 | return handle; | ||
| 355 | } | ||
| 356 | |||
| 357 | /// Returns true when there's a held object. | ||
| 358 | explicit operator bool() const noexcept { | ||
| 359 | return handle != nullptr; | ||
| 360 | } | ||
| 361 | |||
| 362 | protected: | ||
| 363 | Type handle = nullptr; | ||
| 364 | OwnerType owner = nullptr; | ||
| 365 | const Dispatch* dld = nullptr; | ||
| 366 | |||
| 367 | private: | ||
| 368 | /// Destroys the held object if it exists. | ||
| 369 | void Release() noexcept { | ||
| 370 | if (handle) { | ||
| 371 | Destroy(owner, handle, *dld); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | }; | ||
| 375 | |||
| 376 | /// Dummy type used to specify a handle has no owner. | ||
| 377 | struct NoOwner {}; | ||
| 378 | |||
| 379 | /// Handle without an owning type. | ||
| 380 | /// Analogue to std::unique_ptr | ||
| 381 | template <typename Type, typename Dispatch> | ||
| 382 | class Handle<Type, NoOwner, Dispatch> { | ||
| 383 | public: | ||
| 384 | /// Construct a handle and hold it's ownership. | ||
| 385 | explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {} | ||
| 386 | |||
| 387 | /// Construct an empty handle. | ||
| 388 | Handle() noexcept = default; | ||
| 389 | |||
| 390 | /// Copying Vulkan objects is not supported and will never be. | ||
| 391 | Handle(const Handle&) = delete; | ||
| 392 | Handle& operator=(const Handle&) = delete; | ||
| 393 | |||
| 394 | /// Construct a handle transfering ownership from another handle. | ||
| 395 | Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {} | ||
| 396 | |||
| 397 | /// Assign the current handle transfering the ownership from another handle. | ||
| 398 | /// Destroys any previously held object. | ||
| 399 | Handle& operator=(Handle&& rhs) noexcept { | ||
| 400 | Release(); | ||
| 401 | handle = std::exchange(rhs.handle, nullptr); | ||
| 402 | dld = rhs.dld; | ||
| 403 | return *this; | ||
| 404 | } | ||
| 405 | |||
| 406 | /// Destroys the current handle if it existed. | ||
| 407 | ~Handle() noexcept { | ||
| 408 | Release(); | ||
| 409 | } | ||
| 410 | |||
| 411 | /// Destroys any held object. | ||
| 412 | void reset() noexcept { | ||
| 413 | Release(); | ||
| 414 | handle = nullptr; | ||
| 415 | } | ||
| 416 | |||
| 417 | /// Returns the address of the held object. | ||
| 418 | /// Intended for Vulkan structures that expect a pointer to an array. | ||
| 419 | const Type* address() const noexcept { | ||
| 420 | return std::addressof(handle); | ||
| 421 | } | ||
| 422 | |||
| 423 | /// Returns the held Vulkan handle. | ||
| 424 | Type operator*() const noexcept { | ||
| 425 | return handle; | ||
| 426 | } | ||
| 427 | |||
| 428 | /// Returns true when there's a held object. | ||
| 429 | operator bool() const noexcept { | ||
| 430 | return handle != nullptr; | ||
| 431 | } | ||
| 432 | |||
| 433 | protected: | ||
| 434 | Type handle = nullptr; | ||
| 435 | const Dispatch* dld = nullptr; | ||
| 436 | |||
| 437 | private: | ||
| 438 | /// Destroys the held object if it exists. | ||
| 439 | void Release() noexcept { | ||
| 440 | if (handle) { | ||
| 441 | Destroy(handle, *dld); | ||
| 442 | } | ||
| 443 | } | ||
| 444 | }; | ||
| 445 | |||
| 446 | /// Array of a pool allocation. | ||
| 447 | /// Analogue to std::vector | ||
| 448 | template <typename AllocationType, typename PoolType> | ||
| 449 | class PoolAllocations { | ||
| 450 | public: | ||
| 451 | /// Construct an empty allocation. | ||
| 452 | PoolAllocations() = default; | ||
| 453 | |||
| 454 | /// Construct an allocation. Errors are reported through IsOutOfPoolMemory(). | ||
| 455 | explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations, std::size_t num, | ||
| 456 | VkDevice device, PoolType pool, const DeviceDispatch& dld) noexcept | ||
| 457 | : allocations{std::move(allocations)}, num{num}, device{device}, pool{pool}, dld{&dld} {} | ||
| 458 | |||
| 459 | /// Copying Vulkan allocations is not supported and will never be. | ||
| 460 | PoolAllocations(const PoolAllocations&) = delete; | ||
| 461 | PoolAllocations& operator=(const PoolAllocations&) = delete; | ||
| 462 | |||
| 463 | /// Construct an allocation transfering ownership from another allocation. | ||
| 464 | PoolAllocations(PoolAllocations&& rhs) noexcept | ||
| 465 | : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool}, | ||
| 466 | dld{rhs.dld} {} | ||
| 467 | |||
| 468 | /// Assign an allocation transfering ownership from another allocation. | ||
| 469 | /// Releases any previously held allocation. | ||
| 470 | PoolAllocations& operator=(PoolAllocations&& rhs) noexcept { | ||
| 471 | Release(); | ||
| 472 | allocations = std::move(rhs.allocations); | ||
| 473 | num = rhs.num; | ||
| 474 | device = rhs.device; | ||
| 475 | pool = rhs.pool; | ||
| 476 | dld = rhs.dld; | ||
| 477 | return *this; | ||
| 478 | } | ||
| 479 | |||
| 480 | /// Destroys any held allocation. | ||
| 481 | ~PoolAllocations() { | ||
| 482 | Release(); | ||
| 483 | } | ||
| 484 | |||
| 485 | /// Returns the number of allocations. | ||
| 486 | std::size_t size() const noexcept { | ||
| 487 | return num; | ||
| 488 | } | ||
| 489 | |||
| 490 | /// Returns a pointer to the array of allocations. | ||
| 491 | AllocationType const* data() const noexcept { | ||
| 492 | return allocations.get(); | ||
| 493 | } | ||
| 494 | |||
| 495 | /// Returns the allocation in the specified index. | ||
| 496 | /// @pre index < size() | ||
| 497 | AllocationType operator[](std::size_t index) const noexcept { | ||
| 498 | return allocations[index]; | ||
| 499 | } | ||
| 500 | |||
| 501 | /// True when a pool fails to construct. | ||
| 502 | bool IsOutOfPoolMemory() const noexcept { | ||
| 503 | return !device; | ||
| 504 | } | ||
| 505 | |||
| 506 | private: | ||
| 507 | /// Destroys the held allocations if they exist. | ||
| 508 | void Release() noexcept { | ||
| 509 | if (!allocations) { | ||
| 510 | return; | ||
| 511 | } | ||
| 512 | const Span<AllocationType> span(allocations.get(), num); | ||
| 513 | const VkResult result = Free(device, pool, span, *dld); | ||
| 514 | // There's no way to report errors from a destructor. | ||
| 515 | if (result != VK_SUCCESS) { | ||
| 516 | std::terminate(); | ||
| 517 | } | ||
| 518 | } | ||
| 519 | |||
| 520 | std::unique_ptr<AllocationType[]> allocations; | ||
| 521 | std::size_t num = 0; | ||
| 522 | VkDevice device = nullptr; | ||
| 523 | PoolType pool = nullptr; | ||
| 524 | const DeviceDispatch* dld = nullptr; | ||
| 525 | }; | ||
| 526 | |||
| 527 | using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>; | ||
| 528 | using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; | ||
| 529 | using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; | ||
| 530 | using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; | ||
| 531 | using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>; | ||
| 532 | using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>; | ||
| 533 | using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; | ||
| 534 | using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>; | ||
| 535 | using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; | ||
| 536 | using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; | ||
| 537 | using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; | ||
| 538 | using Semaphore = Handle<VkSemaphore, VkDevice, DeviceDispatch>; | ||
| 539 | using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>; | ||
| 540 | using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; | ||
| 541 | |||
| 542 | using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>; | ||
| 543 | using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>; | ||
| 544 | |||
| 545 | } // namespace Vulkan::vk | ||