Last active
October 16, 2019 15:40
-
-
Save qis/2372c1085d468f57fa535f6a8e008f76 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <result.hpp> | |
#include <vulkan/vulkan.h> | |
#include <windows.h> | |
#include <memory> | |
#include <string_view> | |
#include <vector> | |
#include <cassert> | |
struct VkCommandPipelineBarrierInfo { | |
VkCommandBuffer commandBuffer; | |
VkPipelineStageFlags srcStageMask; | |
VkPipelineStageFlags dstStageMask; | |
VkDependencyFlags dependencyFlags; | |
uint32_t memoryBarrierCount; | |
const VkMemoryBarrier* pMemoryBarriers; | |
uint32_t bufferMemoryBarrierCount; | |
const VkBufferMemoryBarrier* pBufferMemoryBarriers; | |
uint32_t imageMemoryBarrierCount; | |
const VkImageMemoryBarrier* pImageMemoryBarriers; | |
}; | |
namespace vk { | |
#define VULKAN_DECLARE(name) inline PFN_##name name = nullptr | |
#define VULKAN_CONTEXT(name) PFN_vk##name name = nullptr | |
#define VULKAN_IMPORT(name) \ | |
name = reinterpret_cast<decltype(name)>(GetProcAddress(module, #name)); \ | |
if (!name) { \ | |
assert(false); \ | |
return error::vulkan_missing_import; \ | |
} | |
#define VULKAN_CALL(call) \ | |
if (const auto result = call; result != VK_SUCCESS) { \ | |
return static_cast<error>(result); \ | |
} | |
using std::vector; | |
VULKAN_DECLARE(vkEnumerateInstanceLayerProperties); | |
VULKAN_DECLARE(vkEnumerateInstanceExtensionProperties); | |
VULKAN_DECLARE(vkCreateInstance); | |
VULKAN_DECLARE(vkDestroyInstance); | |
VULKAN_DECLARE(vkGetInstanceProcAddr); | |
VULKAN_DECLARE(vkCreateWin32SurfaceKHR); | |
VULKAN_DECLARE(vkDestroySurfaceKHR); | |
VULKAN_DECLARE(vkEnumeratePhysicalDevices); | |
VULKAN_DECLARE(vkGetPhysicalDeviceProperties); | |
VULKAN_DECLARE(vkGetPhysicalDeviceQueueFamilyProperties); | |
VULKAN_DECLARE(vkGetPhysicalDeviceSurfaceSupportKHR); | |
VULKAN_DECLARE(vkGetPhysicalDeviceSurfaceFormatsKHR); | |
VULKAN_DECLARE(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); | |
VULKAN_DECLARE(vkGetPhysicalDeviceSurfacePresentModesKHR); | |
VULKAN_DECLARE(vkCreateDevice); | |
VULKAN_DECLARE(vkDestroyDevice); | |
VULKAN_DECLARE(vkGetDeviceQueue); | |
VULKAN_DECLARE(vkCreateSwapchainKHR); | |
VULKAN_DECLARE(vkDestroySwapchainKHR); | |
VULKAN_DECLARE(vkGetSwapchainImagesKHR); | |
VULKAN_DECLARE(vkCreateCommandPool); | |
VULKAN_DECLARE(vkDestroyCommandPool); | |
VULKAN_DECLARE(vkAllocateCommandBuffers); | |
VULKAN_DECLARE(vkFreeCommandBuffers); | |
VULKAN_DECLARE(vkResetCommandBuffer); | |
VULKAN_DECLARE(vkBeginCommandBuffer); | |
VULKAN_DECLARE(vkEndCommandBuffer); | |
VULKAN_DECLARE(vkQueueSubmit); | |
VULKAN_DECLARE(vkCreateFence); | |
VULKAN_DECLARE(vkDestroyFence); | |
VULKAN_DECLARE(vkWaitForFences); | |
VULKAN_DECLARE(vkResetFences); | |
VULKAN_DECLARE(vkCreateSemaphore); | |
VULKAN_DECLARE(vkDestroySemaphore); | |
VULKAN_DECLARE(vkCmdPipelineBarrier); | |
VULKAN_DECLARE(vkCreateImageView); | |
VULKAN_DECLARE(vkDestroyImageView); | |
VULKAN_DECLARE(vkAcquireNextImageKHR); | |
VULKAN_DECLARE(vkQueuePresentKHR); | |
VULKAN_DECLARE(vkCreateDebugReportCallbackEXT); | |
VULKAN_DECLARE(vkDestroyDebugReportCallbackEXT); | |
VULKAN_DECLARE(vkDebugReportMessageEXT); | |
// ==================================================================================================================== | |
inline result<void> Load() noexcept | |
{ | |
const auto module = LoadLibrary(L"vulkan-1.dll"); | |
if (!module) { | |
return error::vulkan_lib_not_found; | |
} | |
VULKAN_IMPORT(vkEnumerateInstanceLayerProperties); | |
VULKAN_IMPORT(vkEnumerateInstanceExtensionProperties); | |
VULKAN_IMPORT(vkCreateInstance); | |
VULKAN_IMPORT(vkDestroyInstance); | |
VULKAN_IMPORT(vkGetInstanceProcAddr); | |
VULKAN_IMPORT(vkCreateWin32SurfaceKHR); | |
VULKAN_IMPORT(vkDestroySurfaceKHR); | |
VULKAN_IMPORT(vkEnumeratePhysicalDevices); | |
VULKAN_IMPORT(vkGetPhysicalDeviceProperties); | |
VULKAN_IMPORT(vkGetPhysicalDeviceQueueFamilyProperties); | |
VULKAN_IMPORT(vkGetPhysicalDeviceSurfaceSupportKHR); | |
VULKAN_IMPORT(vkGetPhysicalDeviceSurfaceFormatsKHR); | |
VULKAN_IMPORT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); | |
VULKAN_IMPORT(vkGetPhysicalDeviceSurfacePresentModesKHR); | |
VULKAN_IMPORT(vkCreateDevice); | |
VULKAN_IMPORT(vkDestroyDevice); | |
VULKAN_IMPORT(vkGetDeviceQueue); | |
VULKAN_IMPORT(vkCreateSwapchainKHR); | |
VULKAN_IMPORT(vkDestroySwapchainKHR); | |
VULKAN_IMPORT(vkGetSwapchainImagesKHR); | |
VULKAN_IMPORT(vkCreateCommandPool); | |
VULKAN_IMPORT(vkDestroyCommandPool); | |
VULKAN_IMPORT(vkAllocateCommandBuffers); | |
VULKAN_IMPORT(vkFreeCommandBuffers); | |
VULKAN_IMPORT(vkResetCommandBuffer); | |
VULKAN_IMPORT(vkBeginCommandBuffer); | |
VULKAN_IMPORT(vkEndCommandBuffer); | |
VULKAN_IMPORT(vkQueueSubmit); | |
VULKAN_IMPORT(vkCreateFence); | |
VULKAN_IMPORT(vkDestroyFence); | |
VULKAN_IMPORT(vkWaitForFences); | |
VULKAN_IMPORT(vkResetFences); | |
VULKAN_IMPORT(vkCreateSemaphore); | |
VULKAN_IMPORT(vkDestroySemaphore); | |
VULKAN_IMPORT(vkCmdPipelineBarrier); | |
VULKAN_IMPORT(vkCreateImageView); | |
VULKAN_IMPORT(vkDestroyImageView); | |
VULKAN_IMPORT(vkAcquireNextImageKHR); | |
VULKAN_IMPORT(vkQueuePresentKHR); | |
return error::success; | |
} | |
// ==================================================================================================================== | |
inline result<vector<VkLayerProperties>> EnumerateInstanceLayerProperties() noexcept | |
{ | |
uint32_t count = 0; | |
vector<VkLayerProperties> properties; | |
VULKAN_CALL(vkEnumerateInstanceLayerProperties(&count, nullptr)); | |
properties.resize(count); | |
VULKAN_CALL(vkEnumerateInstanceLayerProperties(&count, properties.data())); | |
assert(properties.size() == count); | |
properties.resize(count); | |
return properties; | |
} | |
inline result<vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(const char* layer = nullptr) noexcept | |
{ | |
uint32_t count = 0; | |
vector<VkExtensionProperties> properties; | |
VULKAN_CALL(vkEnumerateInstanceExtensionProperties(layer, &count, nullptr)); | |
properties.resize(count); | |
VULKAN_CALL(vkEnumerateInstanceExtensionProperties(layer, &count, properties.data())); | |
assert(properties.size() == count); | |
properties.resize(count); | |
return properties; | |
} | |
// ==================================================================================================================== | |
class Instance { | |
public: | |
Instance() noexcept = default; | |
Instance(const Instance& other) = delete; | |
Instance& operator=(const Instance& other) = delete; | |
Instance(Instance&& other) noexcept : handle_(other.handle_) | |
{ | |
other.handle_ = nullptr; | |
} | |
Instance& operator=(Instance&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (get()) { | |
vkDestroyInstance(get(), nullptr); | |
} | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~Instance() | |
{ | |
if (get()) { | |
vkDestroyInstance(get(), nullptr); | |
} | |
} | |
constexpr operator VkInstance() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkInstance& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkInstance& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkInstance handle_ = nullptr; | |
}; | |
// ==================================================================================================================== | |
template <typename T> | |
inline result<T> GetInstanceProcAddr(VkInstance instance, const char* name) noexcept | |
{ | |
if (const auto proc = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name)); proc) { | |
return proc; | |
} | |
return error::vulkan_missing_instance_import; | |
} | |
template <typename T> | |
inline result<void> GetInstanceProcAddr(VkInstance instance, const char* name, T& proc) noexcept | |
{ | |
if (proc = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name)); proc) { | |
return error::success; | |
} | |
return error::vulkan_missing_instance_import; | |
} | |
// ==================================================================================================================== | |
inline result<Instance> CreateInstance(const VkInstanceCreateInfo* info) noexcept | |
{ | |
Instance instance; | |
VULKAN_CALL(vkCreateInstance(info, nullptr, &instance.get())); | |
bool load_debug_report = false; | |
for (uint32_t i = 0; i < info->enabledExtensionCount; i++) { | |
if (std::string_view(info->ppEnabledExtensionNames[i]) == "VK_EXT_debug_report") { | |
load_debug_report = true; | |
break; | |
} | |
} | |
if (load_debug_report) { | |
if (!GetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT", vkCreateDebugReportCallbackEXT)) { | |
return error::vulkan_missing_instance_debug_import; | |
} | |
if (!GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT", vkDestroyDebugReportCallbackEXT)) { | |
return error::vulkan_missing_instance_debug_import; | |
} | |
if (!GetInstanceProcAddr(instance, "vkDebugReportMessageEXT", vkDebugReportMessageEXT)) { | |
return error::vulkan_missing_instance_debug_import; | |
} | |
} | |
return instance; | |
} | |
// ==================================================================================================================== | |
class Surface { | |
public: | |
Surface() noexcept = default; | |
Surface(const Surface& other) = delete; | |
Surface& operator=(const Surface& other) = delete; | |
Surface(Surface&& other) noexcept : instance_(other.instance_), handle_(other.handle_) | |
{ | |
other.instance_ = nullptr; | |
other.handle_ = nullptr; | |
} | |
Surface& operator=(Surface&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (get()) { | |
vkDestroySurfaceKHR(instance(), get(), nullptr); | |
} | |
instance_ = other.instance_; | |
other.instance_ = nullptr; | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~Surface() | |
{ | |
if (get()) { | |
vkDestroySurfaceKHR(instance(), get(), nullptr); | |
} | |
} | |
constexpr const VkInstance& instance() const noexcept | |
{ | |
return instance_; | |
} | |
constexpr VkInstance& instance() noexcept | |
{ | |
return instance_; | |
} | |
constexpr operator VkSurfaceKHR() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkSurfaceKHR& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkSurfaceKHR& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkInstance instance_ = nullptr; | |
VkSurfaceKHR handle_ = nullptr; | |
}; | |
inline result<Surface> CreateWin32Surface(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* info) noexcept | |
{ | |
Surface surface; | |
surface.instance() = instance; | |
VULKAN_CALL(vkCreateWin32SurfaceKHR(instance, info, nullptr, &surface.get())); | |
return surface; | |
} | |
// ==================================================================================================================== | |
inline result<vector<VkPhysicalDevice>> EnumeratePhysicalDevices(VkInstance instance) noexcept | |
{ | |
uint32_t count = 0; | |
vector<VkPhysicalDevice> properties; | |
VULKAN_CALL(vkEnumeratePhysicalDevices(instance, &count, nullptr)); | |
properties.resize(count); | |
VULKAN_CALL(vkEnumeratePhysicalDevices(instance, &count, properties.data())); | |
assert(properties.size() == count); | |
properties.resize(count); | |
return properties; | |
} | |
inline VkPhysicalDeviceProperties GetPhysicalDeviceProperties(VkPhysicalDevice physical_device) noexcept | |
{ | |
VkPhysicalDeviceProperties properties = {}; | |
vkGetPhysicalDeviceProperties(physical_device, &properties); | |
return properties; | |
} | |
inline vector<VkQueueFamilyProperties> GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physical_device) noexcept | |
{ | |
uint32_t count = 0; | |
vector<VkQueueFamilyProperties> properties; | |
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, nullptr); | |
properties.resize(count); | |
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, properties.data()); | |
assert(properties.size() == count); | |
properties.resize(count); | |
return properties; | |
} | |
inline bool GetPhysicalDeviceSurfaceSupport(VkPhysicalDevice physical_device, uint32_t index, VkSurfaceKHR surface) noexcept | |
{ | |
VkBool32 supported = 0; | |
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, index, surface, &supported); | |
return supported ? true : false; | |
} | |
inline result<vector<VkSurfaceFormatKHR>> GetPhysicalDeviceSurfaceFormats(VkPhysicalDevice physical_device, VkSurfaceKHR surface) noexcept | |
{ | |
uint32_t count = 0; | |
vector<VkSurfaceFormatKHR> properties; | |
VULKAN_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &count, nullptr)); | |
properties.resize(count); | |
VULKAN_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &count, properties.data())); | |
assert(properties.size() == count); | |
properties.resize(count); | |
return properties; | |
} | |
inline result<VkSurfaceCapabilitiesKHR> GetPhysicalDeviceSurfaceCapabilities(VkPhysicalDevice physical_device, VkSurfaceKHR surface) noexcept | |
{ | |
VkSurfaceCapabilitiesKHR capabilities; | |
VULKAN_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities)); | |
return capabilities; | |
} | |
inline result<vector<VkPresentModeKHR>> GetPhysicalDeviceSurfacePresentModes(VkPhysicalDevice physical_device, VkSurfaceKHR surface) noexcept | |
{ | |
uint32_t count = 0; | |
vector<VkPresentModeKHR> modes; | |
VULKAN_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &count, nullptr)); | |
modes.resize(count); | |
VULKAN_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &count, modes.data())); | |
assert(modes.size() == count); | |
modes.resize(count); | |
return modes; | |
} | |
// ==================================================================================================================== | |
class Device { | |
public: | |
Device() noexcept = default; | |
Device(const Device& other) = delete; | |
Device& operator=(const Device& other) = delete; | |
Device(Device&& other) noexcept : handle_(other.handle_) | |
{ | |
other.handle_ = nullptr; | |
} | |
Device& operator=(Device&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (get()) { | |
vkDestroyDevice(get(), nullptr); | |
} | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~Device() | |
{ | |
if (get()) { | |
vkDestroyDevice(get(), nullptr); | |
} | |
} | |
constexpr operator VkDevice() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkDevice& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkDevice& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkDevice handle_ = nullptr; | |
}; | |
inline result<Device> CreateDevice(VkPhysicalDevice physical_device, const VkDeviceCreateInfo* info) noexcept | |
{ | |
Device device; | |
VULKAN_CALL(vkCreateDevice(physical_device, info, nullptr, &device.get())); | |
return device; | |
} | |
inline VkQueue GetDeviceQueue(VkDevice device, uint32_t family_index, uint32_t index) noexcept | |
{ | |
VkQueue queue = nullptr; | |
vkGetDeviceQueue(device, family_index, index, &queue); | |
return queue; | |
} | |
// ==================================================================================================================== | |
class CommandPool { | |
public: | |
CommandPool() noexcept = default; | |
CommandPool(const CommandPool& other) = delete; | |
CommandPool& operator=(const CommandPool& other) = delete; | |
CommandPool(CommandPool&& other) noexcept : device_(other.device_), handle_(other.handle_) | |
{ | |
other.device_ = nullptr; | |
other.handle_ = nullptr; | |
} | |
CommandPool& operator=(CommandPool&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (get()) { | |
vkDestroyCommandPool(device(), get(), nullptr); | |
} | |
device_ = other.device_; | |
other.device_ = nullptr; | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~CommandPool() | |
{ | |
if (get()) { | |
vkDestroyCommandPool(device(), get(), nullptr); | |
} | |
} | |
constexpr const VkDevice& device() const noexcept | |
{ | |
return device_; | |
} | |
constexpr VkDevice& device() noexcept | |
{ | |
return device_; | |
} | |
constexpr operator VkCommandPool() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkCommandPool& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkCommandPool& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkDevice device_ = nullptr; | |
VkCommandPool handle_ = nullptr; | |
}; | |
inline result<CommandPool> CreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo* info) noexcept | |
{ | |
CommandPool pool; | |
pool.device() = device; | |
VULKAN_CALL(vkCreateCommandPool(device, info, nullptr, &pool.get())); | |
return pool; | |
} | |
class CommandBuffers { | |
public: | |
CommandBuffers() noexcept = default; | |
explicit CommandBuffers(uint32_t size) noexcept | |
{ | |
handles_.resize(size); | |
} | |
CommandBuffers(const CommandBuffers& other) = delete; | |
CommandBuffers& operator=(const CommandBuffers& other) = delete; | |
CommandBuffers(CommandBuffers&& other) noexcept : | |
device_(other.device_), command_pool_(other.command_pool_), handles_(std::move(other.handles_)) | |
{ | |
other.device_ = nullptr; | |
other.command_pool_ = nullptr; | |
other.handles_.clear(); | |
} | |
CommandBuffers& operator=(CommandBuffers&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (size()) { | |
vkFreeCommandBuffers(device(), command_pool(), size(), get()); | |
} | |
device_ = other.device_; | |
other.device_ = nullptr; | |
command_pool_ = other.command_pool_; | |
other.command_pool_ = nullptr; | |
handles_ = std::move(other.handles_); | |
other.handles_.clear(); | |
} | |
return *this; | |
} | |
~CommandBuffers() | |
{ | |
if (size()) { | |
vkFreeCommandBuffers(device(), command_pool(), size(), get()); | |
} | |
} | |
constexpr const VkDevice& device() const noexcept | |
{ | |
return device_; | |
} | |
constexpr VkDevice& device() noexcept | |
{ | |
return device_; | |
} | |
constexpr const VkCommandPool& command_pool() const noexcept | |
{ | |
return command_pool_; | |
} | |
constexpr VkCommandPool& command_pool() noexcept | |
{ | |
return command_pool_; | |
} | |
const VkCommandBuffer& operator[](uint32_t index) const noexcept | |
{ | |
assert(index < handles_.size()); | |
return handles_[index]; | |
} | |
VkCommandBuffer& operator[](uint32_t index) noexcept | |
{ | |
assert(index < handles_.size()); | |
return handles_[index]; | |
} | |
operator const VkCommandBuffer*() const noexcept | |
{ | |
return handles_.data(); | |
} | |
operator VkCommandBuffer*() noexcept | |
{ | |
return handles_.data(); | |
} | |
const VkCommandBuffer* get() const noexcept | |
{ | |
return handles_.data(); | |
} | |
VkCommandBuffer* get() noexcept | |
{ | |
return handles_.data(); | |
} | |
uint32_t size() const noexcept | |
{ | |
return static_cast<uint32_t>(handles_.size()); | |
} | |
private: | |
VkDevice device_ = nullptr; | |
VkCommandPool command_pool_ = nullptr; | |
vector<VkCommandBuffer> handles_; | |
}; | |
inline result<CommandBuffers> AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* info) noexcept | |
{ | |
CommandBuffers buffers(info->commandBufferCount); | |
buffers.device() = device; | |
buffers.command_pool() = info->commandPool; | |
VULKAN_CALL(vkAllocateCommandBuffers(device, info, buffers.get())); | |
return buffers; | |
} | |
inline result<void> BeginCommandBuffer(VkCommandBuffer buffer, const VkCommandBufferBeginInfo* info) noexcept | |
{ | |
return static_cast<error>(vkBeginCommandBuffer(buffer, info)); | |
} | |
inline result<void> EndCommandBuffer(VkCommandBuffer buffer) noexcept | |
{ | |
return static_cast<error>(vkEndCommandBuffer(buffer)); | |
} | |
inline result<void> ResetCommandBuffer(VkCommandBuffer buffer, VkCommandBufferResetFlags flags = 0) noexcept | |
{ | |
return static_cast<error>(vkResetCommandBuffer(buffer, flags)); | |
} | |
inline result<void> QueueSubmit(VkQueue queue, uint32_t count, const VkSubmitInfo* info, VkFence fence) noexcept | |
{ | |
return static_cast<error>(vkQueueSubmit(queue, count, info, fence)); | |
} | |
// ==================================================================================================================== | |
class Swapchain { | |
public: | |
Swapchain() noexcept = default; | |
Swapchain(const Swapchain& other) = delete; | |
Swapchain& operator=(const Swapchain& other) = delete; | |
Swapchain(Swapchain&& other) noexcept : device_(other.device_), handle_(other.handle_) | |
{ | |
other.device_ = nullptr; | |
other.handle_ = nullptr; | |
} | |
Swapchain& operator=(Swapchain&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (get()) { | |
vkDestroySwapchainKHR(device(), get(), nullptr); | |
} | |
device_ = other.device_; | |
other.device_ = nullptr; | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~Swapchain() | |
{ | |
if (get()) { | |
vkDestroySwapchainKHR(device(), get(), nullptr); | |
} | |
} | |
constexpr const VkDevice& device() const noexcept | |
{ | |
return device_; | |
} | |
constexpr VkDevice& device() noexcept | |
{ | |
return device_; | |
} | |
constexpr operator VkSwapchainKHR() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkSwapchainKHR& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkSwapchainKHR& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkDevice device_ = nullptr; | |
VkSwapchainKHR handle_ = nullptr; | |
}; | |
inline result<Swapchain> CreateSwapchain(VkDevice device, const VkSwapchainCreateInfoKHR* info) noexcept | |
{ | |
Swapchain swapchain; | |
swapchain.device() = device; | |
VULKAN_CALL(vkCreateSwapchainKHR(device, info, nullptr, &swapchain.get())); | |
return swapchain; | |
} | |
inline result<vector<VkImage>> GetSwapchainImages(VkDevice device, VkSwapchainKHR swapchain) noexcept | |
{ | |
uint32_t count = 0; | |
vector<VkImage> images; | |
VULKAN_CALL(vkGetSwapchainImagesKHR(device, swapchain, &count, nullptr)); | |
images.resize(count); | |
VULKAN_CALL(vkGetSwapchainImagesKHR(device, swapchain, &count, images.data())); | |
assert(images.size() == count); | |
images.resize(count); | |
return images; | |
} | |
inline result<uint32_t> AcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence) noexcept | |
{ | |
uint32_t index = 0; | |
VULKAN_CALL(vkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, &index)); | |
return index; | |
} | |
inline result<void> QueuePresent(VkQueue queue, const VkPresentInfoKHR* info) noexcept | |
{ | |
return static_cast<error>(vkQueuePresentKHR(queue, info)); | |
} | |
// ==================================================================================================================== | |
class ImageView { | |
public: | |
ImageView() noexcept = default; | |
ImageView(const ImageView& other) = delete; | |
ImageView& operator=(const ImageView& other) = delete; | |
ImageView(ImageView&& other) noexcept : device_(other.device_), handle_(other.handle_) | |
{ | |
other.device_ = nullptr; | |
other.handle_ = nullptr; | |
} | |
ImageView& operator=(ImageView&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (get()) { | |
vkDestroyImageView(device(), get(), nullptr); | |
} | |
device_ = other.device_; | |
other.device_ = nullptr; | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~ImageView() | |
{ | |
if (get()) { | |
vkDestroyImageView(device(), get(), nullptr); | |
} | |
} | |
constexpr const VkDevice& device() const noexcept | |
{ | |
return device_; | |
} | |
constexpr VkDevice& device() noexcept | |
{ | |
return device_; | |
} | |
constexpr operator VkImageView() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkImageView& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkImageView& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkDevice device_ = nullptr; | |
VkImageView handle_ = nullptr; | |
}; | |
inline result<ImageView> CreateImageView(VkDevice device, const VkImageViewCreateInfo* info) noexcept | |
{ | |
ImageView image_view; | |
image_view.device() = device; | |
VULKAN_CALL(vkCreateImageView(device, info, nullptr, &image_view.get())); | |
return image_view; | |
} | |
// ==================================================================================================================== | |
class Fence { | |
public: | |
Fence() noexcept = default; | |
Fence(const Fence& other) = delete; | |
Fence& operator=(const Fence& other) = delete; | |
Fence(Fence&& other) noexcept : device_(other.device_), handle_(other.handle_) | |
{ | |
other.device_ = nullptr; | |
other.handle_ = nullptr; | |
} | |
Fence& operator=(Fence&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (handle_) { | |
vkDestroyFence(device(), get(), nullptr); | |
} | |
device_ = other.device_; | |
other.device_ = nullptr; | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~Fence() | |
{ | |
if (handle_) { | |
vkDestroyFence(device(), get(), nullptr); | |
} | |
} | |
constexpr const VkDevice& device() const noexcept | |
{ | |
return device_; | |
} | |
constexpr VkDevice& device() noexcept | |
{ | |
return device_; | |
} | |
constexpr operator VkFence() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkFence& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkFence& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkDevice device_ = nullptr; | |
VkFence handle_ = nullptr; | |
}; | |
inline result<Fence> CreateFence(VkDevice device, const VkFenceCreateInfo* info) noexcept | |
{ | |
Fence fence; | |
fence.device() = device; | |
VULKAN_CALL(vkCreateFence(device, info, nullptr, &fence.get())); | |
return fence; | |
} | |
inline result<void> WaitForFence(VkDevice device, const VkFence& fence, uint64_t timeout = UINT64_MAX) noexcept | |
{ | |
return static_cast<error>(vkWaitForFences(device, 1, &fence, VK_TRUE, timeout)); | |
} | |
inline result<void> ResetFence(VkDevice device, const VkFence& fence) noexcept | |
{ | |
return static_cast<error>(vkResetFences(device, 1, &fence)); | |
} | |
// ==================================================================================================================== | |
class Semaphore { | |
public: | |
Semaphore() noexcept = default; | |
Semaphore(const Semaphore& other) = delete; | |
Semaphore& operator=(const Semaphore& other) = delete; | |
Semaphore(Semaphore&& other) noexcept : device_(other.device_), handle_(other.handle_) | |
{ | |
other.device_ = nullptr; | |
other.handle_ = nullptr; | |
} | |
Semaphore& operator=(Semaphore&& other) noexcept | |
{ | |
if (this != std::addressof(other)) { | |
if (handle_) { | |
vkDestroySemaphore(device(), get(), nullptr); | |
} | |
device_ = other.device_; | |
other.device_ = nullptr; | |
handle_ = other.handle_; | |
other.handle_ = nullptr; | |
} | |
return *this; | |
} | |
~Semaphore() | |
{ | |
if (handle_) { | |
vkDestroySemaphore(device(), get(), nullptr); | |
} | |
} | |
constexpr const VkDevice& device() const noexcept | |
{ | |
return device_; | |
} | |
constexpr VkDevice& device() noexcept | |
{ | |
return device_; | |
} | |
constexpr operator VkSemaphore() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr const VkSemaphore& get() const noexcept | |
{ | |
return handle_; | |
} | |
constexpr VkSemaphore& get() noexcept | |
{ | |
return handle_; | |
} | |
private: | |
VkDevice device_ = nullptr; | |
VkSemaphore handle_ = nullptr; | |
}; | |
inline result<Semaphore> CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo* info) noexcept | |
{ | |
Semaphore semaphore; | |
semaphore.device() = device; | |
VULKAN_CALL(vkCreateSemaphore(device, info, nullptr, &semaphore.get())); | |
return semaphore; | |
} | |
// ==================================================================================================================== | |
inline void CommandPipelineBarrier(const VkCommandPipelineBarrierInfo* info) noexcept | |
{ | |
vkCmdPipelineBarrier( | |
info->commandBuffer, info->srcStageMask, info->dstStageMask, info->dependencyFlags, info->memoryBarrierCount, | |
info->pMemoryBarriers, info->bufferMemoryBarrierCount, info->pBufferMemoryBarriers, info->imageMemoryBarrierCount, | |
info->pImageMemoryBarriers); | |
} | |
// ==================================================================================================================== | |
using DebugReportCallback = std::shared_ptr<void>; | |
// clang-format off | |
template <typename T> | |
inline DebugReportCallback CreateDebugReportCallback(VkInstance instance, VkDebugReportFlagsEXT flags, T callback) noexcept | |
{ | |
if (!vkCreateDebugReportCallbackEXT || !vkDestroyDebugReportCallbackEXT) { | |
return {}; | |
} | |
struct Storage { | |
Storage(T callback, VkInstance instance) : callback(std::move(callback)), instance(instance) | |
{} | |
~Storage() { | |
vkDestroyDebugReportCallbackEXT(instance, handle, nullptr); | |
} | |
T callback; | |
VkInstance instance; | |
VkDebugReportCallbackEXT handle = nullptr; | |
}; | |
auto storage = std::make_shared<Storage>(std::move(callback), instance); | |
VkDebugReportCallbackCreateInfoEXT info = {}; | |
info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; | |
info.flags = flags; | |
info.pfnCallback = []( | |
VkDebugReportFlagsEXT flags, | |
VkDebugReportObjectTypeEXT object_type, | |
uint64_t object, | |
size_t location, | |
int32_t code, | |
const char* layer, | |
const char* message, | |
void* context) -> VkBool32 | |
{ | |
return reinterpret_cast<Storage*>(context)->callback(flags, layer, message); | |
}; | |
info.pUserData = storage.get(); | |
if (vkCreateDebugReportCallbackEXT(instance, &info, nullptr, &storage->handle) != VK_SUCCESS) { | |
return {}; | |
} | |
return storage; | |
} | |
// clang-format on | |
inline result<void> DebugReportMessage(VkInstance instance, VkDebugReportFlagsEXT flags, const char* layer, const char* message) noexcept | |
{ | |
if (!vkDebugReportMessageEXT) { | |
return error::vulkan_missing_instance_debug_import; | |
} | |
vkDebugReportMessageEXT(instance, flags, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, 0, 0, layer, message); | |
return error::success; | |
} | |
} // namespace vk |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment