Skip to content

Instantly share code, notes, and snippets.

@qis
Last active October 16, 2019 15:40
Show Gist options
  • Save qis/2372c1085d468f57fa535f6a8e008f76 to your computer and use it in GitHub Desktop.
Save qis/2372c1085d468f57fa535f6a8e008f76 to your computer and use it in GitHub Desktop.
#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