Merge pull request #3566 from ReinUsesLisp/vk-wrapper-part1
renderer_vulkan/wrapper: Add a Vulkan wrapper (part 1 of 2)
This commit is contained in:
		| @@ -210,6 +210,8 @@ if (ENABLE_VULKAN) | |||||||
|         renderer_vulkan/vk_texture_cache.h |         renderer_vulkan/vk_texture_cache.h | ||||||
|         renderer_vulkan/vk_update_descriptor.cpp |         renderer_vulkan/vk_update_descriptor.cpp | ||||||
|         renderer_vulkan/vk_update_descriptor.h |         renderer_vulkan/vk_update_descriptor.h | ||||||
|  |         renderer_vulkan/wrapper.cpp | ||||||
|  |         renderer_vulkan/wrapper.h | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) |     target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) | ||||||
|   | |||||||
							
								
								
									
										342
									
								
								src/video_core/renderer_vulkan/wrapper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								src/video_core/renderer_vulkan/wrapper.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,342 @@ | |||||||
|  | // Copyright 2020 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <exception> | ||||||
|  | #include <memory> | ||||||
|  | #include <optional> | ||||||
|  | #include <utility> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #include "common/common_types.h" | ||||||
|  |  | ||||||
|  | #include "video_core/renderer_vulkan/wrapper.h" | ||||||
|  |  | ||||||
|  | namespace Vulkan::vk { | ||||||
|  |  | ||||||
|  | namespace { | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name, | ||||||
|  |           VkInstance instance = nullptr) noexcept { | ||||||
|  |     result = reinterpret_cast<T>(dld.vkGetInstanceProcAddr(instance, proc_name)); | ||||||
|  |     return result != nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept { | ||||||
|  |     result = reinterpret_cast<T>(dld.vkGetDeviceProcAddr(device, proc_name)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Load(VkDevice device, DeviceDispatch& dld) noexcept { | ||||||
|  | #define X(name) Proc(dld.name, dld, #name, device) | ||||||
|  |     X(vkAcquireNextImageKHR); | ||||||
|  |     X(vkAllocateCommandBuffers); | ||||||
|  |     X(vkAllocateDescriptorSets); | ||||||
|  |     X(vkAllocateMemory); | ||||||
|  |     X(vkBeginCommandBuffer); | ||||||
|  |     X(vkBindBufferMemory); | ||||||
|  |     X(vkBindImageMemory); | ||||||
|  |     X(vkCmdBeginQuery); | ||||||
|  |     X(vkCmdBeginRenderPass); | ||||||
|  |     X(vkCmdBeginTransformFeedbackEXT); | ||||||
|  |     X(vkCmdBindDescriptorSets); | ||||||
|  |     X(vkCmdBindIndexBuffer); | ||||||
|  |     X(vkCmdBindPipeline); | ||||||
|  |     X(vkCmdBindTransformFeedbackBuffersEXT); | ||||||
|  |     X(vkCmdBindVertexBuffers); | ||||||
|  |     X(vkCmdBlitImage); | ||||||
|  |     X(vkCmdClearAttachments); | ||||||
|  |     X(vkCmdCopyBuffer); | ||||||
|  |     X(vkCmdCopyBufferToImage); | ||||||
|  |     X(vkCmdCopyImage); | ||||||
|  |     X(vkCmdCopyImageToBuffer); | ||||||
|  |     X(vkCmdDispatch); | ||||||
|  |     X(vkCmdDraw); | ||||||
|  |     X(vkCmdDrawIndexed); | ||||||
|  |     X(vkCmdEndQuery); | ||||||
|  |     X(vkCmdEndRenderPass); | ||||||
|  |     X(vkCmdEndTransformFeedbackEXT); | ||||||
|  |     X(vkCmdFillBuffer); | ||||||
|  |     X(vkCmdPipelineBarrier); | ||||||
|  |     X(vkCmdPushConstants); | ||||||
|  |     X(vkCmdSetBlendConstants); | ||||||
|  |     X(vkCmdSetCheckpointNV); | ||||||
|  |     X(vkCmdSetDepthBias); | ||||||
|  |     X(vkCmdSetDepthBounds); | ||||||
|  |     X(vkCmdSetScissor); | ||||||
|  |     X(vkCmdSetStencilCompareMask); | ||||||
|  |     X(vkCmdSetStencilReference); | ||||||
|  |     X(vkCmdSetStencilWriteMask); | ||||||
|  |     X(vkCmdSetViewport); | ||||||
|  |     X(vkCreateBuffer); | ||||||
|  |     X(vkCreateBufferView); | ||||||
|  |     X(vkCreateCommandPool); | ||||||
|  |     X(vkCreateComputePipelines); | ||||||
|  |     X(vkCreateDescriptorPool); | ||||||
|  |     X(vkCreateDescriptorSetLayout); | ||||||
|  |     X(vkCreateDescriptorUpdateTemplateKHR); | ||||||
|  |     X(vkCreateFence); | ||||||
|  |     X(vkCreateFramebuffer); | ||||||
|  |     X(vkCreateGraphicsPipelines); | ||||||
|  |     X(vkCreateImage); | ||||||
|  |     X(vkCreateImageView); | ||||||
|  |     X(vkCreatePipelineLayout); | ||||||
|  |     X(vkCreateQueryPool); | ||||||
|  |     X(vkCreateRenderPass); | ||||||
|  |     X(vkCreateSampler); | ||||||
|  |     X(vkCreateSemaphore); | ||||||
|  |     X(vkCreateShaderModule); | ||||||
|  |     X(vkCreateSwapchainKHR); | ||||||
|  |     X(vkDestroyBuffer); | ||||||
|  |     X(vkDestroyBufferView); | ||||||
|  |     X(vkDestroyCommandPool); | ||||||
|  |     X(vkDestroyDescriptorPool); | ||||||
|  |     X(vkDestroyDescriptorSetLayout); | ||||||
|  |     X(vkDestroyDescriptorUpdateTemplateKHR); | ||||||
|  |     X(vkDestroyFence); | ||||||
|  |     X(vkDestroyFramebuffer); | ||||||
|  |     X(vkDestroyImage); | ||||||
|  |     X(vkDestroyImageView); | ||||||
|  |     X(vkDestroyPipeline); | ||||||
|  |     X(vkDestroyPipelineLayout); | ||||||
|  |     X(vkDestroyQueryPool); | ||||||
|  |     X(vkDestroyRenderPass); | ||||||
|  |     X(vkDestroySampler); | ||||||
|  |     X(vkDestroySemaphore); | ||||||
|  |     X(vkDestroyShaderModule); | ||||||
|  |     X(vkDestroySwapchainKHR); | ||||||
|  |     X(vkDeviceWaitIdle); | ||||||
|  |     X(vkEndCommandBuffer); | ||||||
|  |     X(vkFreeCommandBuffers); | ||||||
|  |     X(vkFreeDescriptorSets); | ||||||
|  |     X(vkFreeMemory); | ||||||
|  |     X(vkGetBufferMemoryRequirements); | ||||||
|  |     X(vkGetDeviceQueue); | ||||||
|  |     X(vkGetFenceStatus); | ||||||
|  |     X(vkGetImageMemoryRequirements); | ||||||
|  |     X(vkGetQueryPoolResults); | ||||||
|  |     X(vkGetQueueCheckpointDataNV); | ||||||
|  |     X(vkMapMemory); | ||||||
|  |     X(vkQueueSubmit); | ||||||
|  |     X(vkResetFences); | ||||||
|  |     X(vkResetQueryPoolEXT); | ||||||
|  |     X(vkUnmapMemory); | ||||||
|  |     X(vkUpdateDescriptorSetWithTemplateKHR); | ||||||
|  |     X(vkUpdateDescriptorSets); | ||||||
|  |     X(vkWaitForFences); | ||||||
|  | #undef X | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // Anonymous namespace | ||||||
|  |  | ||||||
|  | bool Load(InstanceDispatch& dld) noexcept { | ||||||
|  | #define X(name) Proc(dld.name, dld, #name) | ||||||
|  |     return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties); | ||||||
|  | #undef X | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Load(VkInstance instance, InstanceDispatch& dld) noexcept { | ||||||
|  | #define X(name) Proc(dld.name, dld, #name, instance) | ||||||
|  |     // These functions may fail to load depending on the enabled extensions. | ||||||
|  |     // Don't return a failure on these. | ||||||
|  |     X(vkCreateDebugUtilsMessengerEXT); | ||||||
|  |     X(vkDestroyDebugUtilsMessengerEXT); | ||||||
|  |     X(vkDestroySurfaceKHR); | ||||||
|  |     X(vkGetPhysicalDeviceFeatures2KHR); | ||||||
|  |     X(vkGetPhysicalDeviceProperties2KHR); | ||||||
|  |     X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); | ||||||
|  |     X(vkGetPhysicalDeviceSurfaceFormatsKHR); | ||||||
|  |     X(vkGetPhysicalDeviceSurfacePresentModesKHR); | ||||||
|  |     X(vkGetPhysicalDeviceSurfaceSupportKHR); | ||||||
|  |     X(vkGetSwapchainImagesKHR); | ||||||
|  |     X(vkQueuePresentKHR); | ||||||
|  |  | ||||||
|  |     return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) && | ||||||
|  |            X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) && | ||||||
|  |            X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) && | ||||||
|  |            X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) && | ||||||
|  |            X(vkGetPhysicalDeviceQueueFamilyProperties); | ||||||
|  | #undef X | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char* Exception::what() const noexcept { | ||||||
|  |     return ToString(result); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char* ToString(VkResult result) noexcept { | ||||||
|  |     switch (result) { | ||||||
|  |     case VkResult::VK_SUCCESS: | ||||||
|  |         return "VK_SUCCESS"; | ||||||
|  |     case VkResult::VK_NOT_READY: | ||||||
|  |         return "VK_NOT_READY"; | ||||||
|  |     case VkResult::VK_TIMEOUT: | ||||||
|  |         return "VK_TIMEOUT"; | ||||||
|  |     case VkResult::VK_EVENT_SET: | ||||||
|  |         return "VK_EVENT_SET"; | ||||||
|  |     case VkResult::VK_EVENT_RESET: | ||||||
|  |         return "VK_EVENT_RESET"; | ||||||
|  |     case VkResult::VK_INCOMPLETE: | ||||||
|  |         return "VK_INCOMPLETE"; | ||||||
|  |     case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY: | ||||||
|  |         return "VK_ERROR_OUT_OF_HOST_MEMORY"; | ||||||
|  |     case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY: | ||||||
|  |         return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; | ||||||
|  |     case VkResult::VK_ERROR_INITIALIZATION_FAILED: | ||||||
|  |         return "VK_ERROR_INITIALIZATION_FAILED"; | ||||||
|  |     case VkResult::VK_ERROR_DEVICE_LOST: | ||||||
|  |         return "VK_ERROR_DEVICE_LOST"; | ||||||
|  |     case VkResult::VK_ERROR_MEMORY_MAP_FAILED: | ||||||
|  |         return "VK_ERROR_MEMORY_MAP_FAILED"; | ||||||
|  |     case VkResult::VK_ERROR_LAYER_NOT_PRESENT: | ||||||
|  |         return "VK_ERROR_LAYER_NOT_PRESENT"; | ||||||
|  |     case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT: | ||||||
|  |         return "VK_ERROR_EXTENSION_NOT_PRESENT"; | ||||||
|  |     case VkResult::VK_ERROR_FEATURE_NOT_PRESENT: | ||||||
|  |         return "VK_ERROR_FEATURE_NOT_PRESENT"; | ||||||
|  |     case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER: | ||||||
|  |         return "VK_ERROR_INCOMPATIBLE_DRIVER"; | ||||||
|  |     case VkResult::VK_ERROR_TOO_MANY_OBJECTS: | ||||||
|  |         return "VK_ERROR_TOO_MANY_OBJECTS"; | ||||||
|  |     case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED: | ||||||
|  |         return "VK_ERROR_FORMAT_NOT_SUPPORTED"; | ||||||
|  |     case VkResult::VK_ERROR_FRAGMENTED_POOL: | ||||||
|  |         return "VK_ERROR_FRAGMENTED_POOL"; | ||||||
|  |     case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY: | ||||||
|  |         return "VK_ERROR_OUT_OF_POOL_MEMORY"; | ||||||
|  |     case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE: | ||||||
|  |         return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; | ||||||
|  |     case VkResult::VK_ERROR_SURFACE_LOST_KHR: | ||||||
|  |         return "VK_ERROR_SURFACE_LOST_KHR"; | ||||||
|  |     case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: | ||||||
|  |         return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; | ||||||
|  |     case VkResult::VK_SUBOPTIMAL_KHR: | ||||||
|  |         return "VK_SUBOPTIMAL_KHR"; | ||||||
|  |     case VkResult::VK_ERROR_OUT_OF_DATE_KHR: | ||||||
|  |         return "VK_ERROR_OUT_OF_DATE_KHR"; | ||||||
|  |     case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: | ||||||
|  |         return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; | ||||||
|  |     case VkResult::VK_ERROR_VALIDATION_FAILED_EXT: | ||||||
|  |         return "VK_ERROR_VALIDATION_FAILED_EXT"; | ||||||
|  |     case VkResult::VK_ERROR_INVALID_SHADER_NV: | ||||||
|  |         return "VK_ERROR_INVALID_SHADER_NV"; | ||||||
|  |     case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: | ||||||
|  |         return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; | ||||||
|  |     case VkResult::VK_ERROR_FRAGMENTATION_EXT: | ||||||
|  |         return "VK_ERROR_FRAGMENTATION_EXT"; | ||||||
|  |     case VkResult::VK_ERROR_NOT_PERMITTED_EXT: | ||||||
|  |         return "VK_ERROR_NOT_PERMITTED_EXT"; | ||||||
|  |     case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT: | ||||||
|  |         return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT"; | ||||||
|  |     case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: | ||||||
|  |         return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; | ||||||
|  |     } | ||||||
|  |     return "Unknown"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyInstance(instance, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyDevice(device, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyBuffer(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyBufferView(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyCommandPool(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyDescriptorPool(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyDescriptorSetLayout(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle, | ||||||
|  |              const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkFreeMemory(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyFence(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyFramebuffer(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyImage(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyImageView(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyPipeline(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyPipelineLayout(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyQueryPool(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyRenderPass(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroySampler(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroySwapchainKHR(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroySemaphore(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyShaderModule(device, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle, | ||||||
|  |              const InstanceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { | ||||||
|  |     dld.vkDestroySurfaceKHR(instance, handle, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VkResult Free(VkDevice device, VkDescriptorPool handle, Span<VkDescriptorSet> sets, | ||||||
|  |               const DeviceDispatch& dld) noexcept { | ||||||
|  |     return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffers, | ||||||
|  |               const DeviceDispatch& dld) noexcept { | ||||||
|  |     dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data()); | ||||||
|  |     return VK_SUCCESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace Vulkan::vk | ||||||
							
								
								
									
										545
									
								
								src/video_core/renderer_vulkan/wrapper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										545
									
								
								src/video_core/renderer_vulkan/wrapper.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,545 @@ | |||||||
|  | // Copyright 2020 yuzu Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <exception> | ||||||
|  | #include <iterator> | ||||||
|  | #include <limits> | ||||||
|  | #include <memory> | ||||||
|  | #include <optional> | ||||||
|  | #include <type_traits> | ||||||
|  | #include <utility> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #define VK_NO_PROTOTYPES | ||||||
|  | #include <vulkan/vulkan.h> | ||||||
|  |  | ||||||
|  | #include "common/common_types.h" | ||||||
|  |  | ||||||
|  | namespace Vulkan::vk { | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Span for Vulkan arrays. | ||||||
|  |  * Based on std::span but optimized for array access instead of iterators. | ||||||
|  |  * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions. | ||||||
|  |  */ | ||||||
|  | template <typename T> | ||||||
|  | class Span { | ||||||
|  | public: | ||||||
|  |     using value_type = T; | ||||||
|  |     using size_type = u32; | ||||||
|  |     using difference_type = std::ptrdiff_t; | ||||||
|  |     using reference = const T&; | ||||||
|  |     using const_reference = const T&; | ||||||
|  |     using pointer = const T*; | ||||||
|  |     using const_pointer = const T*; | ||||||
|  |     using iterator = const T*; | ||||||
|  |     using const_iterator = const T*; | ||||||
|  |  | ||||||
|  |     /// Construct an empty span. | ||||||
|  |     constexpr Span() noexcept = default; | ||||||
|  |  | ||||||
|  |     /// Construct a span from a single element. | ||||||
|  |     constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} | ||||||
|  |  | ||||||
|  |     /// Construct a span from a range. | ||||||
|  |     template <typename Range> | ||||||
|  |     // requires std::data(const Range&) | ||||||
|  |     // requires std::size(const Range&) | ||||||
|  |     constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {} | ||||||
|  |  | ||||||
|  |     /// Construct a span from a pointer and a size. | ||||||
|  |     /// This is inteded for subranges. | ||||||
|  |     constexpr Span(const T* ptr, std::size_t num) noexcept : ptr{ptr}, num{num} {} | ||||||
|  |  | ||||||
|  |     /// Returns the data pointer by the span. | ||||||
|  |     constexpr const T* data() const noexcept { | ||||||
|  |         return ptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns the number of elements in the span. | ||||||
|  |     /// @note Returns a 32 bits integer because most Vulkan functions expect this type. | ||||||
|  |     constexpr u32 size() const noexcept { | ||||||
|  |         return static_cast<u32>(num); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns true when the span is empty. | ||||||
|  |     constexpr bool empty() const noexcept { | ||||||
|  |         return num == 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns a reference to the element in the passed index. | ||||||
|  |     /// @pre: index < size() | ||||||
|  |     constexpr const T& operator[](std::size_t index) const noexcept { | ||||||
|  |         return ptr[index]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns an iterator to the beginning of the span. | ||||||
|  |     constexpr const T* begin() const noexcept { | ||||||
|  |         return ptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns an iterator to the end of the span. | ||||||
|  |     constexpr const T* end() const noexcept { | ||||||
|  |         return ptr + num; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns an iterator to the beginning of the span. | ||||||
|  |     constexpr const T* cbegin() const noexcept { | ||||||
|  |         return ptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns an iterator to the end of the span. | ||||||
|  |     constexpr const T* cend() const noexcept { | ||||||
|  |         return ptr + num; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     const T* ptr = nullptr; | ||||||
|  |     std::size_t num = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Vulkan exception generated from a VkResult. | ||||||
|  | class Exception final : public std::exception { | ||||||
|  | public: | ||||||
|  |     /// Construct the exception with a result. | ||||||
|  |     /// @pre result != VK_SUCCESS | ||||||
|  |     explicit Exception(VkResult result_) : result{result_} {} | ||||||
|  |     virtual ~Exception() = default; | ||||||
|  |  | ||||||
|  |     const char* what() const noexcept override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     VkResult result; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Converts a VkResult enum into a rodata string | ||||||
|  | const char* ToString(VkResult) noexcept; | ||||||
|  |  | ||||||
|  | /// Throws a Vulkan exception if result is not success. | ||||||
|  | inline void Check(VkResult result) { | ||||||
|  |     if (result != VK_SUCCESS) { | ||||||
|  |         throw Exception(result); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Throws a Vulkan exception if result is an error. | ||||||
|  | /// @return result | ||||||
|  | inline VkResult Filter(VkResult result) { | ||||||
|  |     if (result < 0) { | ||||||
|  |         throw Exception(result); | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Table holding Vulkan instance function pointers. | ||||||
|  | struct InstanceDispatch { | ||||||
|  |     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; | ||||||
|  |  | ||||||
|  |     PFN_vkCreateInstance vkCreateInstance; | ||||||
|  |     PFN_vkDestroyInstance vkDestroyInstance; | ||||||
|  |     PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; | ||||||
|  |  | ||||||
|  |     PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; | ||||||
|  |     PFN_vkCreateDevice vkCreateDevice; | ||||||
|  |     PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; | ||||||
|  |     PFN_vkDestroyDevice vkDestroyDevice; | ||||||
|  |     PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; | ||||||
|  |     PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; | ||||||
|  |     PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; | ||||||
|  |     PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; | ||||||
|  |     PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; | ||||||
|  |     PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; | ||||||
|  |     PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; | ||||||
|  |     PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; | ||||||
|  |     PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; | ||||||
|  |     PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; | ||||||
|  |     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; | ||||||
|  |     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; | ||||||
|  |     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; | ||||||
|  |     PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; | ||||||
|  |     PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; | ||||||
|  |     PFN_vkQueuePresentKHR vkQueuePresentKHR; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Table holding Vulkan device function pointers. | ||||||
|  | struct DeviceDispatch : public InstanceDispatch { | ||||||
|  |     PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; | ||||||
|  |     PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; | ||||||
|  |     PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; | ||||||
|  |     PFN_vkAllocateMemory vkAllocateMemory; | ||||||
|  |     PFN_vkBeginCommandBuffer vkBeginCommandBuffer; | ||||||
|  |     PFN_vkBindBufferMemory vkBindBufferMemory; | ||||||
|  |     PFN_vkBindImageMemory vkBindImageMemory; | ||||||
|  |     PFN_vkCmdBeginQuery vkCmdBeginQuery; | ||||||
|  |     PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; | ||||||
|  |     PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; | ||||||
|  |     PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; | ||||||
|  |     PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; | ||||||
|  |     PFN_vkCmdBindPipeline vkCmdBindPipeline; | ||||||
|  |     PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; | ||||||
|  |     PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; | ||||||
|  |     PFN_vkCmdBlitImage vkCmdBlitImage; | ||||||
|  |     PFN_vkCmdClearAttachments vkCmdClearAttachments; | ||||||
|  |     PFN_vkCmdCopyBuffer vkCmdCopyBuffer; | ||||||
|  |     PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; | ||||||
|  |     PFN_vkCmdCopyImage vkCmdCopyImage; | ||||||
|  |     PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; | ||||||
|  |     PFN_vkCmdDispatch vkCmdDispatch; | ||||||
|  |     PFN_vkCmdDraw vkCmdDraw; | ||||||
|  |     PFN_vkCmdDrawIndexed vkCmdDrawIndexed; | ||||||
|  |     PFN_vkCmdEndQuery vkCmdEndQuery; | ||||||
|  |     PFN_vkCmdEndRenderPass vkCmdEndRenderPass; | ||||||
|  |     PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; | ||||||
|  |     PFN_vkCmdFillBuffer vkCmdFillBuffer; | ||||||
|  |     PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; | ||||||
|  |     PFN_vkCmdPushConstants vkCmdPushConstants; | ||||||
|  |     PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; | ||||||
|  |     PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; | ||||||
|  |     PFN_vkCmdSetDepthBias vkCmdSetDepthBias; | ||||||
|  |     PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; | ||||||
|  |     PFN_vkCmdSetScissor vkCmdSetScissor; | ||||||
|  |     PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; | ||||||
|  |     PFN_vkCmdSetStencilReference vkCmdSetStencilReference; | ||||||
|  |     PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; | ||||||
|  |     PFN_vkCmdSetViewport vkCmdSetViewport; | ||||||
|  |     PFN_vkCreateBuffer vkCreateBuffer; | ||||||
|  |     PFN_vkCreateBufferView vkCreateBufferView; | ||||||
|  |     PFN_vkCreateCommandPool vkCreateCommandPool; | ||||||
|  |     PFN_vkCreateComputePipelines vkCreateComputePipelines; | ||||||
|  |     PFN_vkCreateDescriptorPool vkCreateDescriptorPool; | ||||||
|  |     PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; | ||||||
|  |     PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; | ||||||
|  |     PFN_vkCreateFence vkCreateFence; | ||||||
|  |     PFN_vkCreateFramebuffer vkCreateFramebuffer; | ||||||
|  |     PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; | ||||||
|  |     PFN_vkCreateImage vkCreateImage; | ||||||
|  |     PFN_vkCreateImageView vkCreateImageView; | ||||||
|  |     PFN_vkCreatePipelineLayout vkCreatePipelineLayout; | ||||||
|  |     PFN_vkCreateQueryPool vkCreateQueryPool; | ||||||
|  |     PFN_vkCreateRenderPass vkCreateRenderPass; | ||||||
|  |     PFN_vkCreateSampler vkCreateSampler; | ||||||
|  |     PFN_vkCreateSemaphore vkCreateSemaphore; | ||||||
|  |     PFN_vkCreateShaderModule vkCreateShaderModule; | ||||||
|  |     PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; | ||||||
|  |     PFN_vkDestroyBuffer vkDestroyBuffer; | ||||||
|  |     PFN_vkDestroyBufferView vkDestroyBufferView; | ||||||
|  |     PFN_vkDestroyCommandPool vkDestroyCommandPool; | ||||||
|  |     PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; | ||||||
|  |     PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; | ||||||
|  |     PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; | ||||||
|  |     PFN_vkDestroyFence vkDestroyFence; | ||||||
|  |     PFN_vkDestroyFramebuffer vkDestroyFramebuffer; | ||||||
|  |     PFN_vkDestroyImage vkDestroyImage; | ||||||
|  |     PFN_vkDestroyImageView vkDestroyImageView; | ||||||
|  |     PFN_vkDestroyPipeline vkDestroyPipeline; | ||||||
|  |     PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; | ||||||
|  |     PFN_vkDestroyQueryPool vkDestroyQueryPool; | ||||||
|  |     PFN_vkDestroyRenderPass vkDestroyRenderPass; | ||||||
|  |     PFN_vkDestroySampler vkDestroySampler; | ||||||
|  |     PFN_vkDestroySemaphore vkDestroySemaphore; | ||||||
|  |     PFN_vkDestroyShaderModule vkDestroyShaderModule; | ||||||
|  |     PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; | ||||||
|  |     PFN_vkDeviceWaitIdle vkDeviceWaitIdle; | ||||||
|  |     PFN_vkEndCommandBuffer vkEndCommandBuffer; | ||||||
|  |     PFN_vkFreeCommandBuffers vkFreeCommandBuffers; | ||||||
|  |     PFN_vkFreeDescriptorSets vkFreeDescriptorSets; | ||||||
|  |     PFN_vkFreeMemory vkFreeMemory; | ||||||
|  |     PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; | ||||||
|  |     PFN_vkGetDeviceQueue vkGetDeviceQueue; | ||||||
|  |     PFN_vkGetFenceStatus vkGetFenceStatus; | ||||||
|  |     PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; | ||||||
|  |     PFN_vkGetQueryPoolResults vkGetQueryPoolResults; | ||||||
|  |     PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; | ||||||
|  |     PFN_vkMapMemory vkMapMemory; | ||||||
|  |     PFN_vkQueueSubmit vkQueueSubmit; | ||||||
|  |     PFN_vkResetFences vkResetFences; | ||||||
|  |     PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; | ||||||
|  |     PFN_vkUnmapMemory vkUnmapMemory; | ||||||
|  |     PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; | ||||||
|  |     PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; | ||||||
|  |     PFN_vkWaitForFences vkWaitForFences; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Loads instance agnostic function pointers. | ||||||
|  | /// @return True on success, false on error. | ||||||
|  | bool Load(InstanceDispatch&) noexcept; | ||||||
|  |  | ||||||
|  | /// Loads instance function pointers. | ||||||
|  | /// @return True on success, false on error. | ||||||
|  | bool Load(VkInstance, InstanceDispatch&) noexcept; | ||||||
|  |  | ||||||
|  | void Destroy(VkInstance, const InstanceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, const InstanceDispatch&) noexcept; | ||||||
|  |  | ||||||
|  | void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; | ||||||
|  | void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; | ||||||
|  | void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; | ||||||
|  |  | ||||||
|  | VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; | ||||||
|  | VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept; | ||||||
|  |  | ||||||
|  | template <typename Type, typename OwnerType, typename Dispatch> | ||||||
|  | class Handle; | ||||||
|  |  | ||||||
|  | /// Handle with an owning type. | ||||||
|  | /// Analogue to std::unique_ptr. | ||||||
|  | template <typename Type, typename OwnerType, typename Dispatch> | ||||||
|  | class Handle { | ||||||
|  | public: | ||||||
|  |     /// Construct a handle and hold it's ownership. | ||||||
|  |     explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept | ||||||
|  |         : handle{handle_}, owner{owner_}, dld{&dld_} {} | ||||||
|  |  | ||||||
|  |     /// Construct an empty handle. | ||||||
|  |     Handle() = default; | ||||||
|  |  | ||||||
|  |     /// Copying Vulkan objects is not supported and will never be. | ||||||
|  |     Handle(const Handle&) = delete; | ||||||
|  |     Handle& operator=(const Handle&) = delete; | ||||||
|  |  | ||||||
|  |     /// Construct a handle transfering the ownership from another handle. | ||||||
|  |     Handle(Handle&& rhs) noexcept | ||||||
|  |         : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {} | ||||||
|  |  | ||||||
|  |     /// Assign the current handle transfering the ownership from another handle. | ||||||
|  |     /// Destroys any previously held object. | ||||||
|  |     Handle& operator=(Handle&& rhs) noexcept { | ||||||
|  |         Release(); | ||||||
|  |         handle = std::exchange(rhs.handle, nullptr); | ||||||
|  |         owner = rhs.owner; | ||||||
|  |         dld = rhs.dld; | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Destroys the current handle if it existed. | ||||||
|  |     ~Handle() noexcept { | ||||||
|  |         Release(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Destroys any held object. | ||||||
|  |     void reset() noexcept { | ||||||
|  |         Release(); | ||||||
|  |         handle = nullptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns the address of the held object. | ||||||
|  |     /// Intended for Vulkan structures that expect a pointer to an array. | ||||||
|  |     const Type* address() const noexcept { | ||||||
|  |         return std::addressof(handle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns the held Vulkan handle. | ||||||
|  |     Type operator*() const noexcept { | ||||||
|  |         return handle; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns true when there's a held object. | ||||||
|  |     explicit operator bool() const noexcept { | ||||||
|  |         return handle != nullptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     Type handle = nullptr; | ||||||
|  |     OwnerType owner = nullptr; | ||||||
|  |     const Dispatch* dld = nullptr; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     /// Destroys the held object if it exists. | ||||||
|  |     void Release() noexcept { | ||||||
|  |         if (handle) { | ||||||
|  |             Destroy(owner, handle, *dld); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Dummy type used to specify a handle has no owner. | ||||||
|  | struct NoOwner {}; | ||||||
|  |  | ||||||
|  | /// Handle without an owning type. | ||||||
|  | /// Analogue to std::unique_ptr | ||||||
|  | template <typename Type, typename Dispatch> | ||||||
|  | class Handle<Type, NoOwner, Dispatch> { | ||||||
|  | public: | ||||||
|  |     /// Construct a handle and hold it's ownership. | ||||||
|  |     explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {} | ||||||
|  |  | ||||||
|  |     /// Construct an empty handle. | ||||||
|  |     Handle() noexcept = default; | ||||||
|  |  | ||||||
|  |     /// Copying Vulkan objects is not supported and will never be. | ||||||
|  |     Handle(const Handle&) = delete; | ||||||
|  |     Handle& operator=(const Handle&) = delete; | ||||||
|  |  | ||||||
|  |     /// Construct a handle transfering ownership from another handle. | ||||||
|  |     Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {} | ||||||
|  |  | ||||||
|  |     /// Assign the current handle transfering the ownership from another handle. | ||||||
|  |     /// Destroys any previously held object. | ||||||
|  |     Handle& operator=(Handle&& rhs) noexcept { | ||||||
|  |         Release(); | ||||||
|  |         handle = std::exchange(rhs.handle, nullptr); | ||||||
|  |         dld = rhs.dld; | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Destroys the current handle if it existed. | ||||||
|  |     ~Handle() noexcept { | ||||||
|  |         Release(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Destroys any held object. | ||||||
|  |     void reset() noexcept { | ||||||
|  |         Release(); | ||||||
|  |         handle = nullptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns the address of the held object. | ||||||
|  |     /// Intended for Vulkan structures that expect a pointer to an array. | ||||||
|  |     const Type* address() const noexcept { | ||||||
|  |         return std::addressof(handle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns the held Vulkan handle. | ||||||
|  |     Type operator*() const noexcept { | ||||||
|  |         return handle; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns true when there's a held object. | ||||||
|  |     operator bool() const noexcept { | ||||||
|  |         return handle != nullptr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     Type handle = nullptr; | ||||||
|  |     const Dispatch* dld = nullptr; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     /// Destroys the held object if it exists. | ||||||
|  |     void Release() noexcept { | ||||||
|  |         if (handle) { | ||||||
|  |             Destroy(handle, *dld); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Array of a pool allocation. | ||||||
|  | /// Analogue to std::vector | ||||||
|  | template <typename AllocationType, typename PoolType> | ||||||
|  | class PoolAllocations { | ||||||
|  | public: | ||||||
|  |     /// Construct an empty allocation. | ||||||
|  |     PoolAllocations() = default; | ||||||
|  |  | ||||||
|  |     /// Construct an allocation. Errors are reported through IsOutOfPoolMemory(). | ||||||
|  |     explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations, std::size_t num, | ||||||
|  |                              VkDevice device, PoolType pool, const DeviceDispatch& dld) noexcept | ||||||
|  |         : allocations{std::move(allocations)}, num{num}, device{device}, pool{pool}, dld{&dld} {} | ||||||
|  |  | ||||||
|  |     /// Copying Vulkan allocations is not supported and will never be. | ||||||
|  |     PoolAllocations(const PoolAllocations&) = delete; | ||||||
|  |     PoolAllocations& operator=(const PoolAllocations&) = delete; | ||||||
|  |  | ||||||
|  |     /// Construct an allocation transfering ownership from another allocation. | ||||||
|  |     PoolAllocations(PoolAllocations&& rhs) noexcept | ||||||
|  |         : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool}, | ||||||
|  |           dld{rhs.dld} {} | ||||||
|  |  | ||||||
|  |     /// Assign an allocation transfering ownership from another allocation. | ||||||
|  |     /// Releases any previously held allocation. | ||||||
|  |     PoolAllocations& operator=(PoolAllocations&& rhs) noexcept { | ||||||
|  |         Release(); | ||||||
|  |         allocations = std::move(rhs.allocations); | ||||||
|  |         num = rhs.num; | ||||||
|  |         device = rhs.device; | ||||||
|  |         pool = rhs.pool; | ||||||
|  |         dld = rhs.dld; | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Destroys any held allocation. | ||||||
|  |     ~PoolAllocations() { | ||||||
|  |         Release(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns the number of allocations. | ||||||
|  |     std::size_t size() const noexcept { | ||||||
|  |         return num; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns a pointer to the array of allocations. | ||||||
|  |     AllocationType const* data() const noexcept { | ||||||
|  |         return allocations.get(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns the allocation in the specified index. | ||||||
|  |     /// @pre index < size() | ||||||
|  |     AllocationType operator[](std::size_t index) const noexcept { | ||||||
|  |         return allocations[index]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// True when a pool fails to construct. | ||||||
|  |     bool IsOutOfPoolMemory() const noexcept { | ||||||
|  |         return !device; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     /// Destroys the held allocations if they exist. | ||||||
|  |     void Release() noexcept { | ||||||
|  |         if (!allocations) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         const Span<AllocationType> span(allocations.get(), num); | ||||||
|  |         const VkResult result = Free(device, pool, span, *dld); | ||||||
|  |         // There's no way to report errors from a destructor. | ||||||
|  |         if (result != VK_SUCCESS) { | ||||||
|  |             std::terminate(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::unique_ptr<AllocationType[]> allocations; | ||||||
|  |     std::size_t num = 0; | ||||||
|  |     VkDevice device = nullptr; | ||||||
|  |     PoolType pool = nullptr; | ||||||
|  |     const DeviceDispatch* dld = nullptr; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>; | ||||||
|  | using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; | ||||||
|  | using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; | ||||||
|  | using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; | ||||||
|  | using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>; | ||||||
|  | using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>; | ||||||
|  | using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; | ||||||
|  | using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>; | ||||||
|  | using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; | ||||||
|  | using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>; | ||||||
|  | using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>; | ||||||
|  | using Semaphore = Handle<VkSemaphore, VkDevice, DeviceDispatch>; | ||||||
|  | using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>; | ||||||
|  | using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>; | ||||||
|  |  | ||||||
|  | using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>; | ||||||
|  | using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>; | ||||||
|  |  | ||||||
|  | } // namespace Vulkan::vk | ||||||
		Reference in New Issue
	
	Block a user
	 Rodrigo Locatti
					Rodrigo Locatti