浏览代码

Refactor Vulkan code

Kajetan Johannes Hammerle 3 月之前
父节点
当前提交
3460eeec5e
共有 11 个文件被更改,包括 652 次插入572 次删除
  1. 7 1
      CMakeLists.txt
  2. 108 0
      include/core/VulkanBase.hpp
  3. 27 0
      include/core/VulkanUtility.hpp
  4. 11 5
      src/Image.cpp
  5. 1 1
      src/Network.cpp
  6. 287 0
      src/VulkanBase.cpp
  7. 62 0
      src/VulkanUtility.cpp
  8. 41 398
      src/VulkanUtils.cpp
  9. 11 59
      src/VulkanUtils.hpp
  10. 96 107
      src/VulkanWrapper.cpp
  11. 1 1
      test/modules/WindowManagerTests.cpp

+ 7 - 1
CMakeLists.txt

@@ -8,7 +8,9 @@ set(CMAKE_CXX_STANDARD 23)
 set(SRC
     "src/Image.cpp"
     "src/Network.cpp"
+    "src/VulkanBase.cpp"
     "src/VulkanUtils.cpp"
+    "src/VulkanUtility.cpp"
     "src/VulkanWrapper.cpp"
     "src/WindowManager.cpp"
 )
@@ -51,7 +53,7 @@ target_compile_options(gamingcore PUBLIC
     -fdiagnostics-color=always
 )
 target_compile_definitions(gamingcore
-    PUBLIC LOG_LEVEL=${LOG_LEVEL}
+    PRIVATE LOG_LEVEL=${LOG_LEVEL}
     PUBLIC ${DEFINITIONS}
 )
 target_link_libraries(gamingcore
@@ -72,6 +74,7 @@ target_sources(gamingcore PUBLIC
     FILES
         ./include/core/Image.hpp
         ./include/core/Network.hpp
+        ./include/core/VulkanBase.hpp
         ./include/core/VulkanWrapper.hpp
         ./include/core/WindowManager.hpp
 )
@@ -84,3 +87,6 @@ add_shader(NAME fragment SOURCES shaders/fragment.frag.glsl)
 
 add_executable(test ${SRC_TESTS})
 target_link_libraries(test PRIVATE gamingcore)
+target_compile_definitions(test
+    PRIVATE LOG_LEVEL=4
+)

+ 108 - 0
include/core/VulkanBase.hpp

@@ -0,0 +1,108 @@
+#ifndef GAMINGCORE_VULKAN_BASE_HPP
+#define GAMINGCORE_VULKAN_BASE_HPP
+
+#include <core/Array.hpp>
+#include <core/List.hpp>
+#include <core/Types.hpp>
+#include <core/Utility.hpp>
+
+#define GLFW_INCLUDE_VULKAN
+#include <GLFW/glfw3.h>
+
+#include "core/VulkanUtility.hpp"
+
+namespace Core::Vulkan {
+    [[maybe_unused]] constexpr u32 INVALID_QUEUE_FAMILY = 0xFFFF'FFFF;
+
+    struct DeviceQueueData {
+        u32 queueFamilyIndex = 0;
+        float priority = 0.0f;
+    };
+
+    class Base {
+        VkInstance instance;
+#ifdef DEBUG_VULKAN
+        VkDebugUtilsMessengerEXT debugMessenger;
+        VkDebugReportCallbackEXT debugReportCallback;
+#endif
+        VkSurfaceKHR surface;
+        VkPhysicalDevice physicalDevice;
+        VkDevice device;
+
+    public:
+        Base();
+        ~Base();
+        Base(const Base&) = delete;
+        Base(Base&&) = delete;
+        Base& operator=(const Base&) = delete;
+        Base& operator=(Base&&) = delete;
+
+        bool init();
+        void destroy();
+
+        PFN_vkVoidFunction getFunction(const char* name);
+
+        template<typename T>
+        using PhysicalDeviceSelector = int (*)(Base&, T&);
+
+        template<typename T>
+        bool findPhysicalDevice(T& data, PhysicalDeviceSelector<T> s) {
+            Core::Array<VkPhysicalDevice, 32> devices;
+            u32 c = devices.getLength();
+            VK_CHECK_TRUE(
+                vkEnumeratePhysicalDevices(instance, &c, &devices[0]));
+            int bestPoints = 0;
+            VkPhysicalDevice best = VK_NULL_HANDLE;
+            for(u32 i = 0; i < c; i++) {
+                physicalDevice = devices[i];
+                T userData;
+                int points = s(*this, userData);
+                if(points > bestPoints) {
+                    bestPoints = points;
+                    best = physicalDevice;
+                    data = userData;
+                }
+            }
+            physicalDevice = best;
+            return bestPoints == 0;
+        }
+
+        void getPhysicalDeviceProperties(VkPhysicalDeviceProperties& p);
+        u32 findQueueFamily(VkQueueFlags flags);
+        u32 findSurfaceQueueFamily();
+        bool hasExtension(const char* extension);
+        bool getSurfaceCapabilities(VkSurfaceCapabilitiesKHR& c);
+
+        using SurfaceFormatSelector = int (*)(const VkSurfaceFormatKHR&);
+        bool findSurfaceFormat(
+            VkSurfaceFormatKHR& sf, SurfaceFormatSelector sfs);
+
+        using SurfacePresentModeSelector = int (*)(VkPresentModeKHR);
+        bool findSurfacePresentMode(
+            VkPresentModeKHR& m, SurfacePresentModeSelector spms);
+
+        bool initDevice(
+            const List<DeviceQueueData> data,
+            const List<const char*>& extensions);
+
+        operator VkDevice() {
+            return device;
+        }
+
+        operator VkSurfaceKHR() {
+            return surface;
+        }
+
+    private:
+        bool initInstance();
+#ifdef DEBUG_VULKAN
+        bool initDebugMessenger();
+        bool initDebugReportCallback();
+        void destroyDebugMessenger();
+        void destroyDebugReportCallback();
+#endif
+        bool initSurface();
+    };
+}
+
+#endif

+ 27 - 0
include/core/VulkanUtility.hpp

@@ -0,0 +1,27 @@
+#ifndef GAMINGCORE_VULKAN_UTILITY_HPP
+#define GAMINGCORE_VULKAN_UTILITY_HPP
+
+#include <core/Logger.hpp>
+
+#include <vulkan/vulkan.h>
+
+namespace Core::Vulkan {
+    const char* getResultString(VkResult r);
+}
+
+#define VK_REPORT(level, format, ...)                                          \
+    REPORT(                                                                    \
+        Core::LogLevel::level, "Vulkan | " format __VA_OPT__(, ) __VA_ARGS__);
+#define VK_REPORT_ERROR(...) VK_REPORT(ERROR, __VA_ARGS__)
+#define VK_REPORT_WARNING(...) VK_REPORT(WARNING, __VA_ARGS__)
+#define VK_CHECK(r, a)                                                     \
+    do {                                                                   \
+        VkResult vkResult = (a);                                           \
+        if(vkResult != VK_SUCCESS) {                                       \
+            VK_REPORT_ERROR("#", Core::Vulkan::getResultString(vkResult)); \
+            return r;                                                      \
+        }                                                                  \
+    } while(false)
+#define VK_CHECK_TRUE(a) VK_CHECK(true, a)
+
+#endif

+ 11 - 5
src/Image.cpp

@@ -1,16 +1,22 @@
 #include "core/Image.hpp"
 
-#define STB_IMAGE_IMPLEMENTATION
-#define STBI_ONLY_PNG
-// #define STBI_MALLOC(n) Core::allocateRaw(n)
-// #define STBI_REALLOC(p, n) Core::reallocateRaw(p, n)
-// #define STBI_FREE(p) Core::deallocateRaw(p)
 #include <cerrno>
 #include <core/Logger.hpp>
 #include <core/Utility.hpp>
 #include <cstring>
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wunknown-warning-option"
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#pragma GCC diagnostic ignored "-Walloc-zero"
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_ONLY_PNG
+#define STBI_MALLOC(n) Core::allocateRaw(n)
+#define STBI_REALLOC(p, n) Core::reallocateRaw(p, n)
+#define STBI_FREE(p) Core::deallocateRaw(p)
 #include <stb_image.h>
+#pragma GCC diagnostic pop
 
 static void reportError(const char* path) {
     REPORT(

+ 1 - 1
src/Network.cpp

@@ -148,7 +148,7 @@ void OutPacket::writeFloat(float f) {
 }
 
 void OutPacket::writeString(const char* s) {
-    size_t l = Core::min(strlen(s), 65'534);
+    size_t l = Core::min<size_t>(65'534, strlen(s));
     writeU16(static_cast<u16>(l + 1));
     write(s, l);
     writeU8(0);

+ 287 - 0
src/VulkanBase.cpp

@@ -0,0 +1,287 @@
+#include "core/VulkanBase.hpp"
+
+#include <core/List.hpp>
+#include <core/Logger.hpp>
+
+#include "GLFW.hpp"
+
+using Core::Vulkan::Base;
+
+#define GET_FUNCTION(name) (reinterpret_cast<PFN_##name>(getFunction(#name)))
+
+Base::Base() :
+    instance(VK_NULL_HANDLE),
+#ifdef DEBUG_VULKAN
+    debugMessenger(VK_NULL_HANDLE), debugReportCallback(VK_NULL_HANDLE),
+#endif
+    surface(VK_NULL_HANDLE), physicalDevice(VK_NULL_HANDLE),
+    device(VK_NULL_HANDLE) {
+}
+
+Base::~Base() {
+    destroy();
+}
+
+bool Base::initInstance() {
+    u32 baseCount = 0;
+    const char** baseExtensions = glfwGetRequiredInstanceExtensions(&baseCount);
+    if(baseExtensions == nullptr) {
+        VK_REPORT_ERROR("Could not get required extensions from GLFW");
+        return true;
+    }
+    Core::List<const char*> extensions;
+    for(u32 i = 0; i < baseCount; i++) {
+        extensions.add(baseExtensions[i]);
+    }
+    Core::List<const char*> layers;
+#ifdef DEBUG_VULKAN
+    extensions.add(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+    extensions.add(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
+    layers.add("VK_LAYER_KHRONOS_validation");
+#endif
+    VkApplicationInfo appInfo = {
+        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+        .pApplicationName = "Vulkan",
+        .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
+        .pEngineName = "Kajetan",
+        .engineVersion = VK_MAKE_VERSION(0, 0, 1),
+        .apiVersion = VK_API_VERSION_1_1};
+    VkInstanceCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+        .pApplicationInfo = &appInfo,
+        .enabledLayerCount = static_cast<u32>(layers.getLength()),
+        .ppEnabledLayerNames = &layers[0],
+        .enabledExtensionCount = static_cast<u32>(extensions.getLength()),
+        .ppEnabledExtensionNames = &extensions[0]};
+    VK_CHECK_TRUE(vkCreateInstance(&info, nullptr, &instance));
+    return false;
+}
+
+#ifdef DEBUG_VULKAN
+static VKAPI_ATTR VkBool32 onVulkanDebugMessenger VKAPI_CALL(
+    VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
+    const VkDebugUtilsMessengerCallbackDataEXT* data, void*) {
+    VK_REPORT_WARNING("Vulkan validation layer message: #", data->pMessage);
+    return false;
+}
+
+bool Base::initDebugMessenger() {
+    VkDebugUtilsMessengerCreateInfoEXT info = {
+        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
+        .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
+                           VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
+        .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
+                       VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
+                       VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
+        .pfnUserCallback = onVulkanDebugMessenger};
+    auto f = GET_FUNCTION(vkCreateDebugUtilsMessengerEXT);
+    if(f == nullptr) {
+        VK_REPORT_WARNING("Could not find debug util messenger function");
+        return false;
+    }
+    VK_CHECK_TRUE(f(instance, &info, nullptr, &debugMessenger));
+    return false;
+}
+
+static VKAPI_ATTR VkBool32 onVulkanDebugReport VKAPI_CALL(
+    VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t,
+    int32_t, const char* pLayerPrefix, const char* pMessage, void*) {
+    VK_REPORT_WARNING("Vulkan debug message '#': #", pLayerPrefix, pMessage);
+    return false;
+}
+
+bool Base::initDebugReportCallback() {
+    VkDebugReportCallbackCreateInfoEXT info = {
+        .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
+        .flags = VK_DEBUG_REPORT_WARNING_BIT_EXT |
+                 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
+                 VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        .pfnCallback = onVulkanDebugReport};
+    auto f = GET_FUNCTION(vkCreateDebugReportCallbackEXT);
+    if(f == nullptr) {
+        VK_REPORT_WARNING("Could not find debug report function");
+        return false;
+    }
+    VK_CHECK_TRUE(f(instance, &info, nullptr, &debugReportCallback));
+    return false;
+}
+
+void Base::destroyDebugMessenger() {
+    if(debugMessenger == VK_NULL_HANDLE) {
+        return;
+    }
+    auto f = GET_FUNCTION(vkDestroyDebugUtilsMessengerEXT);
+    if(f == nullptr) {
+        VK_REPORT_WARNING(
+            "Could not find debug util messenger destroy function");
+        return;
+    }
+    f(instance, debugMessenger, nullptr);
+    debugMessenger = VK_NULL_HANDLE;
+}
+
+void Base::destroyDebugReportCallback() {
+    if(debugReportCallback == VK_NULL_HANDLE) {
+        return;
+    }
+    auto f = GET_FUNCTION(vkDestroyDebugReportCallbackEXT);
+    if(f == nullptr) {
+        VK_REPORT_WARNING("Could not find debug report destroy function");
+        return;
+    }
+    f(instance, debugReportCallback, nullptr);
+    debugReportCallback = VK_NULL_HANDLE;
+}
+#endif
+
+bool Base::initSurface() {
+    GLFWwindow* w = Window::get();
+    if(w == nullptr) {
+        VK_REPORT_ERROR("Init a window before Vulkan");
+        return true;
+    }
+    VK_CHECK_TRUE(glfwCreateWindowSurface(instance, w, nullptr, &surface));
+    return false;
+}
+
+bool Base::init() {
+    if(initInstance()) {
+        return true;
+    }
+#ifdef DEBUG_VULKAN
+    if(initDebugMessenger() || initDebugReportCallback()) {
+        return true;
+    }
+#endif
+    return initSurface();
+}
+
+void Base::destroy() {
+#ifdef DEBUG_VULKAN
+    destroyDebugMessenger();
+    destroyDebugReportCallback();
+#endif
+    if(instance != VK_NULL_HANDLE) {
+        vkDestroySurfaceKHR(instance, surface, nullptr);
+        surface = VK_NULL_HANDLE;
+        vkDestroyDevice(device, nullptr);
+        device = VK_NULL_HANDLE;
+    }
+    vkDestroyInstance(instance, nullptr);
+    instance = VK_NULL_HANDLE;
+}
+
+PFN_vkVoidFunction Base::getFunction(const char* name) {
+    return vkGetInstanceProcAddr(instance, name);
+}
+
+void Base::getPhysicalDeviceProperties(VkPhysicalDeviceProperties& p) {
+    vkGetPhysicalDeviceProperties(physicalDevice, &p);
+}
+
+u32 Base::findQueueFamily(VkQueueFlags flags) {
+    Core::Array<VkQueueFamilyProperties, 32> p;
+    u32 c = p.getLength();
+    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &c, p.begin());
+    for(u32 i = 0; i < c; i++) {
+        if((p[i].queueFlags & flags) == flags) {
+            return i;
+        }
+    }
+    return INVALID_QUEUE_FAMILY;
+}
+
+static bool hasPresentationSupport(
+    VkPhysicalDevice pd, VkSurfaceKHR s, u32 index) {
+    VkBool32 b = false;
+    VK_CHECK(false, vkGetPhysicalDeviceSurfaceSupportKHR(pd, index, s, &b));
+    return b;
+}
+
+u32 Base::findSurfaceQueueFamily() {
+    u32 c = 0;
+    vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &c, nullptr);
+    for(u32 i = 0; i < c; i++) {
+        if(hasPresentationSupport(physicalDevice, surface, i)) {
+            return i;
+        }
+    }
+    return INVALID_QUEUE_FAMILY;
+}
+
+bool Base::hasExtension(const char* extension) {
+    Core::Array<VkExtensionProperties, 1024> e;
+    u32 c = e.getLength();
+    VK_CHECK(
+        false, vkEnumerateDeviceExtensionProperties(
+                   physicalDevice, nullptr, &c, &e[0]));
+    for(u32 i = 0; i < c; i++) {
+        if(strcmp(e[i].extensionName, extension) == 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool Base::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR& c) {
+    VK_CHECK_TRUE(
+        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &c));
+    return false;
+}
+
+bool Base::findSurfaceFormat(
+    VkSurfaceFormatKHR& sf, SurfaceFormatSelector sfs) {
+    Core::Array<VkSurfaceFormatKHR, 64> formats;
+    u32 c = formats.getLength();
+    VK_CHECK_TRUE(vkGetPhysicalDeviceSurfaceFormatsKHR(
+        physicalDevice, surface, &c, formats.begin()));
+    int bestPoints = 0;
+    for(u32 i = 0; i < c; i++) {
+        int points = sfs(formats[i]);
+        if(points > bestPoints) {
+            bestPoints = points;
+            sf = formats[i];
+        }
+    }
+    return bestPoints == 0;
+}
+
+bool Base::findSurfacePresentMode(
+    VkPresentModeKHR& m, SurfacePresentModeSelector spms) {
+    Core::Array<VkPresentModeKHR, 64> modes;
+    u32 c = modes.getLength();
+    VK_CHECK_TRUE(vkGetPhysicalDeviceSurfacePresentModesKHR(
+        physicalDevice, surface, &c, modes.begin()));
+    int bestPoints = 0;
+    for(u32 i = 0; i < c; i++) {
+        int points = spms(modes[i]);
+        if(points > bestPoints) {
+            bestPoints = points;
+            m = modes[i];
+        }
+    }
+    return bestPoints == 0;
+}
+
+bool Base::initDevice(
+    const List<DeviceQueueData> data, const List<const char*>& extensions) {
+    Core::List<VkDeviceQueueCreateInfo> qInfo;
+    for(const DeviceQueueData& d : data) {
+        VkDeviceQueueCreateInfo& i = qInfo.put();
+        i.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+        i.queueFamilyIndex = d.queueFamilyIndex;
+        i.queueCount = 1;
+        i.pQueuePriorities = &d.priority;
+    }
+    VkPhysicalDeviceFeatures deviceFeatures = {};
+    vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
+    VkDeviceCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+        .queueCreateInfoCount = static_cast<u32>(qInfo.getLength()),
+        .pQueueCreateInfos = &qInfo[0],
+        .enabledExtensionCount = static_cast<u32>(extensions.getLength()),
+        .ppEnabledExtensionNames = &extensions[0],
+        .pEnabledFeatures = &deviceFeatures};
+    VK_CHECK_TRUE(vkCreateDevice(physicalDevice, &info, nullptr, &device));
+    return false;
+}

+ 62 - 0
src/VulkanUtility.cpp

@@ -0,0 +1,62 @@
+#include "core/VulkanUtility.hpp"
+
+namespace Vulkan = Core::Vulkan;
+
+#define VK_ERROR_CASE(error)  \
+    case error: return #error
+
+const char* Vulkan::getResultString(VkResult r) {
+    switch(r) {
+        VK_ERROR_CASE(VK_SUCCESS);
+        VK_ERROR_CASE(VK_NOT_READY);
+        VK_ERROR_CASE(VK_TIMEOUT);
+        VK_ERROR_CASE(VK_EVENT_SET);
+        VK_ERROR_CASE(VK_EVENT_RESET);
+        VK_ERROR_CASE(VK_INCOMPLETE);
+        VK_ERROR_CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
+        VK_ERROR_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
+        VK_ERROR_CASE(VK_ERROR_INITIALIZATION_FAILED);
+        VK_ERROR_CASE(VK_ERROR_DEVICE_LOST);
+        VK_ERROR_CASE(VK_ERROR_MEMORY_MAP_FAILED);
+        VK_ERROR_CASE(VK_ERROR_LAYER_NOT_PRESENT);
+        VK_ERROR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
+        VK_ERROR_CASE(VK_ERROR_FEATURE_NOT_PRESENT);
+        VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
+        VK_ERROR_CASE(VK_ERROR_TOO_MANY_OBJECTS);
+        VK_ERROR_CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
+        VK_ERROR_CASE(VK_ERROR_FRAGMENTED_POOL);
+        VK_ERROR_CASE(VK_ERROR_UNKNOWN);
+        VK_ERROR_CASE(VK_ERROR_OUT_OF_POOL_MEMORY);
+        VK_ERROR_CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE);
+        VK_ERROR_CASE(VK_ERROR_FRAGMENTATION);
+        VK_ERROR_CASE(VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS);
+        VK_ERROR_CASE(VK_PIPELINE_COMPILE_REQUIRED);
+        VK_ERROR_CASE(VK_ERROR_SURFACE_LOST_KHR);
+        VK_ERROR_CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
+        VK_ERROR_CASE(VK_SUBOPTIMAL_KHR);
+        VK_ERROR_CASE(VK_ERROR_OUT_OF_DATE_KHR);
+        VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
+        VK_ERROR_CASE(VK_ERROR_VALIDATION_FAILED_EXT);
+        VK_ERROR_CASE(VK_ERROR_INVALID_SHADER_NV);
+        VK_ERROR_CASE(VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR);
+        VK_ERROR_CASE(VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR);
+        VK_ERROR_CASE(VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR);
+        VK_ERROR_CASE(VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR);
+        VK_ERROR_CASE(VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR);
+        VK_ERROR_CASE(VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR);
+        VK_ERROR_CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
+        VK_ERROR_CASE(VK_ERROR_NOT_PERMITTED_KHR);
+        VK_ERROR_CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
+        VK_ERROR_CASE(VK_THREAD_IDLE_KHR);
+        VK_ERROR_CASE(VK_THREAD_DONE_KHR);
+        VK_ERROR_CASE(VK_OPERATION_DEFERRED_KHR);
+        VK_ERROR_CASE(VK_OPERATION_NOT_DEFERRED_KHR);
+        VK_ERROR_CASE(VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR);
+        VK_ERROR_CASE(VK_ERROR_COMPRESSION_EXHAUSTED_EXT);
+        VK_ERROR_CASE(VK_INCOMPATIBLE_SHADER_BINARY_EXT);
+        VK_ERROR_CASE(VK_PIPELINE_BINARY_MISSING_KHR);
+        VK_ERROR_CASE(VK_ERROR_NOT_ENOUGH_SPACE_KHR);
+        default: break;
+    }
+    return "unknown";
+}

+ 41 - 398
src/VulkanUtils.cpp

@@ -4,359 +4,7 @@
 #include <core/File.hpp>
 #include <core/Logger.hpp>
 
-static VkInstance instance;
-#ifdef DEBUG_VULKAN
-static VkDebugUtilsMessengerEXT debugMessenger;
-static VkDebugReportCallbackEXT debugReportCallback;
-#endif
-
-#define VK_ERROR_CASE(error)  \
-    case error: return #error
-
-const char* getVulkanResultString(VkResult r) {
-    switch(r) {
-        VK_ERROR_CASE(VK_SUCCESS);
-        VK_ERROR_CASE(VK_NOT_READY);
-        VK_ERROR_CASE(VK_TIMEOUT);
-        VK_ERROR_CASE(VK_EVENT_SET);
-        VK_ERROR_CASE(VK_EVENT_RESET);
-        VK_ERROR_CASE(VK_INCOMPLETE);
-        VK_ERROR_CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
-        VK_ERROR_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
-        VK_ERROR_CASE(VK_ERROR_INITIALIZATION_FAILED);
-        VK_ERROR_CASE(VK_ERROR_DEVICE_LOST);
-        VK_ERROR_CASE(VK_ERROR_MEMORY_MAP_FAILED);
-        VK_ERROR_CASE(VK_ERROR_LAYER_NOT_PRESENT);
-        VK_ERROR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
-        VK_ERROR_CASE(VK_ERROR_FEATURE_NOT_PRESENT);
-        VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
-        VK_ERROR_CASE(VK_ERROR_TOO_MANY_OBJECTS);
-        VK_ERROR_CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
-        VK_ERROR_CASE(VK_ERROR_FRAGMENTED_POOL);
-        VK_ERROR_CASE(VK_ERROR_UNKNOWN);
-        VK_ERROR_CASE(VK_ERROR_OUT_OF_POOL_MEMORY);
-        VK_ERROR_CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE);
-        VK_ERROR_CASE(VK_ERROR_FRAGMENTATION);
-        VK_ERROR_CASE(VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS);
-        VK_ERROR_CASE(VK_PIPELINE_COMPILE_REQUIRED);
-        VK_ERROR_CASE(VK_ERROR_SURFACE_LOST_KHR);
-        VK_ERROR_CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
-        VK_ERROR_CASE(VK_SUBOPTIMAL_KHR);
-        VK_ERROR_CASE(VK_ERROR_OUT_OF_DATE_KHR);
-        VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
-        VK_ERROR_CASE(VK_ERROR_VALIDATION_FAILED_EXT);
-        VK_ERROR_CASE(VK_ERROR_INVALID_SHADER_NV);
-        VK_ERROR_CASE(VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR);
-        VK_ERROR_CASE(VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR);
-        VK_ERROR_CASE(VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR);
-        VK_ERROR_CASE(VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR);
-        VK_ERROR_CASE(VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR);
-        VK_ERROR_CASE(VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR);
-        VK_ERROR_CASE(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
-        VK_ERROR_CASE(VK_ERROR_NOT_PERMITTED_KHR);
-        VK_ERROR_CASE(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
-        VK_ERROR_CASE(VK_THREAD_IDLE_KHR);
-        VK_ERROR_CASE(VK_THREAD_DONE_KHR);
-        VK_ERROR_CASE(VK_OPERATION_DEFERRED_KHR);
-        VK_ERROR_CASE(VK_OPERATION_NOT_DEFERRED_KHR);
-        VK_ERROR_CASE(VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR);
-        VK_ERROR_CASE(VK_ERROR_COMPRESSION_EXHAUSTED_EXT);
-        VK_ERROR_CASE(VK_INCOMPATIBLE_SHADER_BINARY_EXT);
-        VK_ERROR_CASE(VK_PIPELINE_BINARY_MISSING_KHR);
-        VK_ERROR_CASE(VK_ERROR_NOT_ENOUGH_SPACE_KHR);
-        default: break;
-    }
-    return "unknown";
-}
-
-static PFN_vkVoidFunction getVulkanFunction(const char* name) {
-    return vkGetInstanceProcAddr(instance, name);
-}
-
-#define GET_VULKAN_FUNCTION(name)                            \
-    (reinterpret_cast<PFN_##name>(getVulkanFunction(#name)))
-
-bool initVulkanInstance() {
-    u32 baseCount = 0;
-    const char** baseExtensions = glfwGetRequiredInstanceExtensions(&baseCount);
-    if(baseExtensions == nullptr) {
-        LOG_ERROR("Could not get required extensions from GLFW");
-        return true;
-    }
-#ifdef DEBUG_VULKAN
-    u32 count = baseCount + 2;
-    Core::Array<const char*, 32> extensions;
-    if(count > extensions.getLength()) {
-        LOG_ERROR("Extension buffer is too small");
-        return true;
-    }
-    for(u32 i = 0; i < baseCount; i++) {
-        extensions[i] = baseExtensions[i];
-    }
-    extensions[baseCount] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
-    extensions[baseCount + 1] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
-    const char* layers[] = {"VK_LAYER_KHRONOS_validation"};
-#else
-    u32 count = baseCount;
-    const char** extensions = baseExtensions;
-#endif
-    VkApplicationInfo appInfo = {
-        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
-        .pApplicationName = "Vulkan",
-        .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
-        .pEngineName = "Kajetan",
-        .engineVersion = VK_MAKE_VERSION(0, 0, 1),
-        .apiVersion = VK_API_VERSION_1_1};
-    VkInstanceCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
-        .pApplicationInfo = &appInfo,
-#ifdef DEBUG_VULKAN
-        .enabledLayerCount = 1,
-        .ppEnabledLayerNames = layers,
-#endif
-        .enabledExtensionCount = count,
-        .ppEnabledExtensionNames = extensions.begin()};
-    VK_ASSERT(vkCreateInstance(&info, nullptr, &instance));
-    return false;
-}
-
-void destroyVulkanInstance() {
-    vkDestroyInstance(instance, nullptr);
-    instance = VK_NULL_HANDLE;
-}
-
-#ifdef DEBUG_VULKAN
-static VKAPI_ATTR VkBool32 onVulkanDebugMessenger VKAPI_CALL(
-    VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
-    const VkDebugUtilsMessengerCallbackDataEXT* data, void*) {
-    LOG_WARNING("Vulkan validation layer message: %s", data->pMessage);
-    return false;
-}
-
-static bool initDebugMessenger() {
-    VkDebugUtilsMessengerCreateInfoEXT info = {
-        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
-        .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
-                           VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
-        .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
-                       VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
-                       VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
-        .pfnUserCallback = onVulkanDebugMessenger};
-    auto f = GET_VULKAN_FUNCTION(vkCreateDebugUtilsMessengerEXT);
-    if(f == nullptr) {
-        LOG_WARNING("Could not find debug util messenger function");
-        return false;
-    }
-    VK_ASSERT(f(instance, &info, nullptr, &debugMessenger));
-    return false;
-}
-
-static VKAPI_ATTR VkBool32 onVulkanDebugReport VKAPI_CALL(
-    VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t,
-    int32_t, const char* pLayerPrefix, const char* pMessage, void*) {
-    LOG_WARNING("Vulkan debug message '%s': %s", pLayerPrefix, pMessage);
-    return false;
-}
-
-static bool initDebugReportCallback() {
-    VkDebugReportCallbackCreateInfoEXT info = {
-        .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
-        .flags = VK_DEBUG_REPORT_WARNING_BIT_EXT |
-                 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
-                 VK_DEBUG_REPORT_ERROR_BIT_EXT,
-        .pfnCallback = onVulkanDebugReport};
-    auto f = GET_VULKAN_FUNCTION(vkCreateDebugReportCallbackEXT);
-    if(f == nullptr) {
-        LOG_WARNING("Could not find debug report function");
-        return false;
-    }
-    VK_ASSERT(f(instance, &info, nullptr, &debugReportCallback));
-    return false;
-}
-
-bool initVulkanDebugging() {
-    return initDebugMessenger() || initDebugReportCallback();
-}
-
-static void destroyDebugMessenger() {
-    auto f = GET_VULKAN_FUNCTION(vkDestroyDebugUtilsMessengerEXT);
-    if(f == nullptr) {
-        LOG_WARNING("Could not find debug util messenger destroy function");
-        return;
-    }
-    f(instance, debugMessenger, nullptr);
-}
-
-static void destroyDebugReportCallback() {
-    auto f = GET_VULKAN_FUNCTION(vkDestroyDebugReportCallbackEXT);
-    if(f == nullptr) {
-        LOG_WARNING("Could not find debug report destroy function");
-        return;
-    }
-    f(instance, debugReportCallback, nullptr);
-}
-
-void destroyVulkanDebugging() {
-    if(instance != VK_NULL_HANDLE) {
-        destroyDebugMessenger();
-        destroyDebugReportCallback();
-    }
-}
-#else
-bool initVulkanDebugging() {
-    (void)getVulkanFunction;
-    return false;
-}
-
-void destroyVulkanDebugging() {
-}
-#endif
-
-u32 findVulkanQueueFamily(VkPhysicalDevice pd, VkQueueFlags flags) {
-    Core::Array<VkQueueFamilyProperties, 32> properties;
-    u32 count = properties.getLength();
-    vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, properties.begin());
-    for(u32 i = 0; i < count; i++) {
-        if((properties[i].queueFlags & flags) == flags) {
-            return i;
-        }
-    }
-    return INVALID_VULKAN_QUEUE_FAMILY;
-}
-
-static bool noPresentationSupport(
-    VkPhysicalDevice pd, VkSurfaceKHR s, u32 index) {
-    VkBool32 b = false;
-    VK_ASSERT(vkGetPhysicalDeviceSurfaceSupportKHR(pd, index, s, &b));
-    return !b;
-}
-
-u32 findVulkanSurfaceQueueFamily(VkPhysicalDevice pd, VkSurfaceKHR s) {
-    u32 count = 0;
-    vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, nullptr);
-    for(u32 i = 0; i < count; i++) {
-        if(!noPresentationSupport(pd, s, i)) {
-            return i;
-        }
-    }
-    return INVALID_VULKAN_QUEUE_FAMILY;
-}
-
-bool findVulkanSurfaceFormat(
-    VkSurfaceFormatKHR* sf, VkPhysicalDevice pd, VkSurfaceKHR s,
-    VulkanSurfaceFormatSelector sfs) {
-    Core::Array<VkSurfaceFormatKHR, 64> formats;
-    u32 c = formats.getLength();
-    VK_ASSERT(vkGetPhysicalDeviceSurfaceFormatsKHR(pd, s, &c, formats.begin()));
-    int bestPoints = 0;
-    for(u32 i = 0; i < c; i++) {
-        int points = sfs(&formats[i]);
-        if(points > bestPoints) {
-            bestPoints = points;
-            *sf = formats[i];
-        }
-    }
-    return bestPoints == 0;
-}
-
-bool findVulkanSurfacePresentMode(
-    VkPresentModeKHR* m, VkPhysicalDevice pd, VkSurfaceKHR s,
-    VulkanSurfacePresentModeSelector spms) {
-    Core::Array<VkPresentModeKHR, 64> modes;
-    u32 c = modes.getLength();
-    VK_ASSERT(
-        vkGetPhysicalDeviceSurfacePresentModesKHR(pd, s, &c, modes.begin()));
-    int bestPoints = 0;
-    for(u32 i = 0; i < c; i++) {
-        int points = spms(modes[i]);
-        if(points > bestPoints) {
-            bestPoints = points;
-            *m = modes[i];
-        }
-    }
-    return bestPoints == 0;
-}
-
-bool findVulkanPhysicalDevice(
-    VkPhysicalDevice* pd, VulkanPhysicalDeviceSelector s) {
-    Core::Array<VkPhysicalDevice, 32> devices;
-    u32 c = devices.getLength();
-    VK_ASSERT(vkEnumeratePhysicalDevices(instance, &c, devices.begin()));
-    int bestPoints = 0;
-    for(u32 i = 0; i < c; i++) {
-        int points = s(devices[i]);
-        if(points > bestPoints) {
-            bestPoints = points;
-            *pd = devices[i];
-        }
-    }
-    return bestPoints == 0;
-}
-
-bool hasVulkanExtension(VkPhysicalDevice pd, const char* extension) {
-    Core::Array<VkExtensionProperties, 1024> e;
-    u32 c = e.getLength();
-    VkResult r =
-        vkEnumerateDeviceExtensionProperties(pd, nullptr, &c, e.begin());
-    if(r != VK_SUCCESS) {
-        LOG_ERROR(
-            "Cannot get physical device extension properties: %s",
-            getVulkanResultString(r));
-        return false;
-    }
-    for(u32 i = 0; i < c; i++) {
-        if(strcmp(e[i].extensionName, extension) == 0) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool initVulkanDevice(
-    VkDevice* d, VkPhysicalDevice pd, const VulkanDeviceQueueData* data,
-    size_t n, const char** extensions, size_t nExtensions) {
-    constexpr size_t LENGTH = 32;
-    if(n >= LENGTH) {
-        LOG_ERROR("Vulkan device queue overload");
-        return true;
-    }
-    VkDeviceQueueCreateInfo deviceQueueInfo[LENGTH] = {};
-    for(size_t i = 0; i < n; i++) {
-        VkDeviceQueueCreateInfo* qInfo = deviceQueueInfo + i;
-        qInfo->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
-        qInfo->queueFamilyIndex = data[i].queueFamilyIndex;
-        qInfo->queueCount = 1;
-        qInfo->pQueuePriorities = &data[i].priority;
-    }
-    VkPhysicalDeviceFeatures deviceFeatures = {};
-    vkGetPhysicalDeviceFeatures(pd, &deviceFeatures);
-    VkDeviceCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-        .queueCreateInfoCount = static_cast<u32>(n),
-        .pQueueCreateInfos = deviceQueueInfo,
-        .enabledExtensionCount = static_cast<u32>(nExtensions),
-        .ppEnabledExtensionNames = extensions,
-        .pEnabledFeatures = &deviceFeatures};
-    VK_ASSERT(vkCreateDevice(pd, &info, nullptr, d));
-    return false;
-}
-
-void destroyVulkanDevice(VkDevice d) {
-    if(instance != VK_NULL_HANDLE) {
-        vkDestroyDevice(d, nullptr);
-    }
-}
-
-bool initVulkanSurface(VkSurfaceKHR* s, GLFWwindow* w) {
-    VK_ASSERT(glfwCreateWindowSurface(instance, w, nullptr, s));
-    return false;
-}
-
-void destroyVulkanSurface(VkSurfaceKHR s) {
-    if(instance != VK_NULL_HANDLE) {
-        vkDestroySurfaceKHR(instance, s, nullptr);
-    }
-}
+#include "core/VulkanUtility.hpp"
 
 static u32 getSwapImageCount(const VkSurfaceCapabilitiesKHR* caps) {
     u32 c = caps->minImageCount + 1;
@@ -370,11 +18,12 @@ static u32 getSwapImageCount(const VkSurfaceCapabilitiesKHR* caps) {
 
 bool initVulkanSwapchain(VkSwapchainKHR* sc, VulkanSwapchainData* d) {
     VkSurfaceCapabilitiesKHR caps = {0};
-    VK_ASSERT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
-        d->physicalDevice, d->surface, &caps));
+    if(d->base.getSurfaceCapabilities(caps)) {
+        return true;
+    }
     VkSwapchainCreateInfoKHR ci = {
         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
-        .surface = d->surface,
+        .surface = d->base,
         .minImageCount = getSwapImageCount(&caps),
         .imageFormat = d->surfaceFormat.format,
         .imageColorSpace = d->surfaceFormat.colorSpace,
@@ -382,14 +31,14 @@ bool initVulkanSwapchain(VkSwapchainKHR* sc, VulkanSwapchainData* d) {
         .imageArrayLayers = 1,
         .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
         .imageSharingMode = d->sharingMode,
-        .queueFamilyIndexCount = d->queueFamilyIndexCount,
-        .pQueueFamilyIndices = d->queueFamilyIndices,
+        .queueFamilyIndexCount = static_cast<u32>(d->queueFamilies.getLength()),
+        .pQueueFamilyIndices = &d->queueFamilies[0],
         .preTransform = caps.currentTransform,
         .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
         .presentMode = d->presentMode,
         .clipped = VK_TRUE,
         .oldSwapchain = VK_NULL_HANDLE};
-    VK_ASSERT(vkCreateSwapchainKHR(d->device, &ci, nullptr, sc));
+    VK_CHECK_TRUE(vkCreateSwapchainKHR(d->base, &ci, nullptr, sc));
     return false;
 }
 
@@ -400,7 +49,7 @@ void destroyVulkanSwapchain(VkSwapchainKHR s, VkDevice d) {
 }
 
 static bool createImageView(
-    VkImageView* view, VkDevice d, VkImage image, VkFormat format) {
+    VkImageView& view, VkDevice d, VkImage image, VkFormat format) {
     VkImageViewCreateInfo info = {
         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
         .image = image,
@@ -412,50 +61,48 @@ static bool createImageView(
             .levelCount = 1,
             .baseArrayLayer = 0,
             .layerCount = 1}};
-    VK_ASSERT(vkCreateImageView(d, &info, nullptr, view));
+    VK_CHECK_TRUE(vkCreateImageView(d, &info, nullptr, &view));
     return false;
 }
 
 bool initVulkanSwapchainImages(
-    VulkanSwapchainImages* si, VkDevice d, VkSwapchainKHR sc, VkFormat format) {
-    VK_ASSERT(vkGetSwapchainImagesKHR(d, sc, &si->amount, nullptr));
-    si->images = static_cast<VkImage*>(
-        Core::zeroAllocateRaw(sizeof(VkImage) * si->amount));
-    si->imageViews = static_cast<VkImageView*>(
-        Core::zeroAllocateRaw(sizeof(VkImageView) * si->amount));
-    VK_ASSERT(vkGetSwapchainImagesKHR(d, sc, &si->amount, si->images));
-    for(u32 x = 0; x < si->amount; x++) {
-        if(createImageView(si->imageViews + x, d, si->images[x], format)) {
+    VulkanSwapchainImages& si, VkDevice d, VkSwapchainKHR sc, VkFormat format) {
+    u32 c = 0;
+    VK_CHECK_TRUE(vkGetSwapchainImagesKHR(d, sc, &c, nullptr));
+    si.images.resize(c);
+    si.imageViews.resize(c);
+    VK_CHECK_TRUE(vkGetSwapchainImagesKHR(d, sc, &c, &si.images[0]));
+    for(u32 x = 0; x < c; x++) {
+        if(createImageView(si.imageViews[x], d, si.images[x], format)) {
             return true;
         }
     }
     return false;
 }
 
-void destroyVulkanSwapchainImages(VulkanSwapchainImages* si, VkDevice d) {
-    if(d == VK_NULL_HANDLE || si == nullptr) {
+void destroyVulkanSwapchainImages(VulkanSwapchainImages& si, VkDevice d) {
+    if(d == VK_NULL_HANDLE) {
         return;
     }
-    for(size_t x = 0; x < si->amount; x++) {
-        vkDestroyImageView(d, si->imageViews[x], nullptr);
+    for(VkImageView& v : si.imageViews) {
+        vkDestroyImageView(d, v, nullptr);
     }
-    Core::deallocateRaw(si->images);
-    Core::deallocateRaw(si->imageViews);
-    *si = VulkanSwapchainImages();
+    si.imageViews.clear();
+    si.images.clear();
 }
 
 static bool initShaderModule(
     Core::List<char>& f, VkDevice d, VkShaderModule* sm) {
     size_t l = f.getLength() - 1;
     if((l % 4) != 0) {
-        LOG_ERROR("Shader size is not a multiple of 4");
+        VK_REPORT_ERROR("Shader size is not a multiple of 4");
         return true;
     }
     VkShaderModuleCreateInfo info = {
         .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
         .codeSize = l,
         .pCode = reinterpret_cast<u32*>(static_cast<void*>(&f[0]))};
-    VK_ASSERT(vkCreateShaderModule(d, &info, nullptr, sm));
+    VK_CHECK_TRUE(vkCreateShaderModule(d, &info, nullptr, sm));
     return false;
 }
 
@@ -480,7 +127,7 @@ bool initVulkanPipelineLayout(VkPipelineLayout* pl, VkDevice d) {
         .pSetLayouts = nullptr,
         .pushConstantRangeCount = 0,
         .pPushConstantRanges = nullptr};
-    VK_ASSERT(vkCreatePipelineLayout(d, &info, nullptr, pl));
+    VK_CHECK_TRUE(vkCreatePipelineLayout(d, &info, nullptr, pl));
     return false;
 }
 
@@ -491,34 +138,30 @@ void destroyVulkanPipelineLayout(VkPipelineLayout pl, VkDevice d) {
 }
 
 bool initVulkanFramebuffers(
-    VkFramebuffer** f, VulkanSwapchainImages* si, VkDevice d, VkRenderPass rp,
-    u32 width, u32 height) {
-    *f = static_cast<VkFramebuffer*>(
-        Core::zeroAllocateRaw(sizeof(VkFramebuffer) * si->amount));
-    for(u32 i = 0; i < si->amount; i++) {
+    Core::List<VkFramebuffer>& f, VulkanSwapchainImages& si, VkDevice d,
+    VkRenderPass rp, u32 width, u32 height) {
+    f.resize(si.imageViews.getLength());
+    for(u32 i = 0; i < si.imageViews.getLength(); i++) {
         VkFramebufferCreateInfo info = {
             .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
             .renderPass = rp,
             .attachmentCount = 1,
-            .pAttachments = si->imageViews + i,
+            .pAttachments = &si.imageViews[i],
             .width = width,
             .height = height,
             .layers = 1};
-        VK_ASSERT(vkCreateFramebuffer(d, &info, nullptr, (*f) + i));
+        VK_CHECK_TRUE(vkCreateFramebuffer(d, &info, nullptr, &f[i]));
     }
     return false;
 }
 
-void destroyVulkanFramebuffers(VkFramebuffer** f, u32 amount, VkDevice d) {
-    if(f != nullptr) {
-        if(d != VK_NULL_HANDLE && *f != nullptr) {
-            for(u32 i = 0; i < amount; i++) {
-                vkDestroyFramebuffer(d, (*f)[i], nullptr);
-            }
+void destroyVulkanFramebuffers(Core::List<VkFramebuffer>& fs, VkDevice d) {
+    if(d != VK_NULL_HANDLE) {
+        for(VkFramebuffer f : fs) {
+            vkDestroyFramebuffer(d, f, nullptr);
         }
-        Core::deallocateRaw(*f);
-        *f = nullptr;
     }
+    fs.clear();
 }
 
 bool initCommandVulkanBuffer(
@@ -528,14 +171,14 @@ bool initCommandVulkanBuffer(
         .commandPool = cp,
         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
         .commandBufferCount = 1};
-    VK_ASSERT(vkAllocateCommandBuffers(d, &info, cb));
+    VK_CHECK_TRUE(vkAllocateCommandBuffers(d, &info, cb));
     return false;
 }
 
 bool initVulkanSemaphore(VkSemaphore* s, VkDevice d) {
     VkSemaphoreCreateInfo info = {
         .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
-    VK_ASSERT(vkCreateSemaphore(d, &info, nullptr, s));
+    VK_CHECK_TRUE(vkCreateSemaphore(d, &info, nullptr, s));
     return false;
 }
 
@@ -549,7 +192,7 @@ bool initVulkanFence(VkFence* f, VkDevice d) {
     VkFenceCreateInfo info = {
         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
         .flags = VK_FENCE_CREATE_SIGNALED_BIT};
-    VK_ASSERT(vkCreateFence(d, &info, nullptr, f));
+    VK_CHECK_TRUE(vkCreateFence(d, &info, nullptr, f));
     return false;
 }
 

+ 11 - 59
src/VulkanUtils.hpp

@@ -2,82 +2,34 @@
 #define GAMINGCORE_VULKAN_UTILS_HPP
 
 #define GLFW_INCLUDE_VULKAN
+#include <core/List.hpp>
 #include <core/Types.hpp>
 #include <core/Utility.hpp>
 
 #include <GLFW/glfw3.h>
 
-const char* getVulkanResultString(VkResult r);
-
-#define VK_ASSERT(a)                                                          \
-    do {                                                                      \
-        VkResult vkResult = (a);                                              \
-        if(vkResult != VK_SUCCESS) {                                          \
-            LOG_ERROR("Vulkan error: %s\n", getVulkanResultString(vkResult)); \
-            return true;                                                      \
-        }                                                                     \
-    } while(false)
-
-bool initVulkanInstance();
-void destroyVulkanInstance();
-
-bool initVulkanDebugging();
-void destroyVulkanDebugging();
-
-#define INVALID_VULKAN_QUEUE_FAMILY (static_cast<u32>(-1))
-u32 findVulkanQueueFamily(VkPhysicalDevice pd, VkQueueFlags flags);
-u32 findVulkanSurfaceQueueFamily(VkPhysicalDevice pd, VkSurfaceKHR s);
-typedef int (*VulkanSurfaceFormatSelector)(const VkSurfaceFormatKHR* sf);
-bool findVulkanSurfaceFormat(
-    VkSurfaceFormatKHR* sf, VkPhysicalDevice pd, VkSurfaceKHR s,
-    VulkanSurfaceFormatSelector sfs);
-typedef int (*VulkanSurfacePresentModeSelector)(VkPresentModeKHR m);
-bool findVulkanSurfacePresentMode(
-    VkPresentModeKHR* m, VkPhysicalDevice pd, VkSurfaceKHR s,
-    VulkanSurfacePresentModeSelector spms);
-
-typedef int (*VulkanPhysicalDeviceSelector)(VkPhysicalDevice pd);
-bool findVulkanPhysicalDevice(
-    VkPhysicalDevice* pd, VulkanPhysicalDeviceSelector s);
-bool hasVulkanExtension(VkPhysicalDevice pd, const char* extension);
-
-struct VulkanDeviceQueueData {
-    u32 queueFamilyIndex = 0;
-    float priority = 0.0f;
-};
-
-bool initVulkanDevice(
-    VkDevice* d, VkPhysicalDevice pd, const VulkanDeviceQueueData* data,
-    size_t nData, const char** extensions, size_t nExtensions);
-void destroyVulkanDevice(VkDevice d);
-
-bool initVulkanSurface(VkSurfaceKHR* s, GLFWwindow* w);
-void destroyVulkanSurface(VkSurfaceKHR s);
+#include "core/VulkanBase.hpp"
 
 struct VulkanSwapchainData {
-    VkPhysicalDevice physicalDevice{};
-    VkDevice device{};
-    VkSurfaceKHR surface{};
+    Core::Vulkan::Base& base;
     VkExtent2D size{};
     VkSurfaceFormatKHR surfaceFormat{};
     VkPresentModeKHR presentMode{};
     VkSharingMode sharingMode{};
-    u32 queueFamilyIndexCount = 0;
-    u32* queueFamilyIndices = nullptr;
+    Core::List<u32> queueFamilies{};
 };
 
 bool initVulkanSwapchain(VkSwapchainKHR* sc, VulkanSwapchainData* d);
 void destroyVulkanSwapchain(VkSwapchainKHR s, VkDevice d);
 
 struct VulkanSwapchainImages {
-    u32 amount;
-    VkImage* images;
-    VkImageView* imageViews;
+    Core::List<VkImage> images{};
+    Core::List<VkImageView> imageViews{};
 };
 
 bool initVulkanSwapchainImages(
-    VulkanSwapchainImages* si, VkDevice d, VkSwapchainKHR sc, VkFormat format);
-void destroyVulkanSwapchainImages(VulkanSwapchainImages* si, VkDevice d);
+    VulkanSwapchainImages& si, VkDevice d, VkSwapchainKHR sc, VkFormat format);
+void destroyVulkanSwapchainImages(VulkanSwapchainImages& si, VkDevice d);
 
 bool initVulkanShaderModule(VkShaderModule* sm, VkDevice d, const char* path);
 void destroyVulkanShaderModule(VkShaderModule sm, VkDevice d);
@@ -86,9 +38,9 @@ bool initVulkanPipelineLayout(VkPipelineLayout* pl, VkDevice d);
 void destroyVulkanPipelineLayout(VkPipelineLayout pl, VkDevice d);
 
 bool initVulkanFramebuffers(
-    VkFramebuffer** f, VulkanSwapchainImages* si, VkDevice d, VkRenderPass rp,
-    u32 width, u32 height);
-void destroyVulkanFramebuffers(VkFramebuffer** f, u32 amount, VkDevice d);
+    Core::List<VkFramebuffer>& f, VulkanSwapchainImages& si, VkDevice d,
+    VkRenderPass rp, u32 width, u32 height);
+void destroyVulkanFramebuffers(Core::List<VkFramebuffer>& f, VkDevice d);
 
 bool initCommandVulkanBuffer(VkCommandBuffer* cb, VkDevice d, VkCommandPool cp);
 

+ 96 - 107
src/VulkanWrapper.cpp

@@ -6,17 +6,23 @@
 
 #include "GLFW.hpp"
 #include "VulkanUtils.hpp"
+#include "core/VulkanBase.hpp"
+#include "core/VulkanUtility.hpp"
 
 namespace Vulkan = Core::Vulkan;
 
-static VkPhysicalDevice physicalDevice;
-static u32 graphicsFamily = 0;
-static u32 presentFamily = 0;
-static VkDevice device;
+static Core::Vulkan::Base base;
+
+struct BaseData {
+    u32 graphicsFamily = 0;
+    u32 presentFamily = 0;
+    VkSurfaceFormatKHR surfaceFormat{};
+    VkPresentModeKHR presentMode{};
+};
+
+static BaseData baseData;
 static VkQueue graphicsQueue;
 static VkQueue presentQueue;
-static VkSurfaceFormatKHR surfaceFormat;
-static VkSurfaceKHR surface;
 static VkExtent2D swapchainSize;
 static VkSwapchainKHR swapchain;
 static VulkanSwapchainImages images;
@@ -27,7 +33,7 @@ static VkRenderPass renderPass;
 static VkViewport viewport;
 static VkRect2D scissor;
 static VkPipeline pipeline;
-static VkFramebuffer* framebuffers;
+static Core::List<VkFramebuffer> framebuffers;
 static VkCommandPool commandPool;
 static constexpr size_t MAX_FRAMES = 2;
 static size_t currentFrame = 0;
@@ -41,9 +47,9 @@ typedef struct {
 
 static Frame frames[MAX_FRAMES];
 
-static int getSurfaceFormatPoints(const VkSurfaceFormatKHR* sf) {
-    if(sf->format == VK_FORMAT_B8G8R8A8_UNORM &&
-       sf->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+static int getSurfaceFormatPoints(const VkSurfaceFormatKHR& sf) {
+    if(sf.format == VK_FORMAT_B8G8R8A8_UNORM &&
+       sf.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
         return 10;
     }
     return 1;
@@ -60,8 +66,9 @@ static int getSurfacePresentModePoints(VkPresentModeKHR m) {
 
 static bool getSwapchainSize(VkExtent2D* size) {
     VkSurfaceCapabilitiesKHR c = {0};
-    VK_ASSERT(
-        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &c));
+    if(base.getSurfaceCapabilities(c)) {
+        return true;
+    }
     if(c.currentExtent.width != 0xFFFF'FFFFu &&
        c.currentExtent.height != 0xFFFF'FFFFu) {
         *size = c.currentExtent;
@@ -86,29 +93,18 @@ static bool getSwapchainSize(VkExtent2D* size) {
 
 static bool initSwapchain() {
     VulkanSwapchainData d = {
-        .physicalDevice = physicalDevice, .device = device, .surface = surface};
+        .base = base,
+        .surfaceFormat = baseData.surfaceFormat,
+        .presentMode = baseData.presentMode};
     if(getSwapchainSize(&d.size)) {
         LOG_ERROR("Could not retrieve any swapchain size");
         return true;
     }
     swapchainSize = d.size;
-    if(findVulkanSurfaceFormat(
-           &d.surfaceFormat, physicalDevice, surface, getSurfaceFormatPoints)) {
-        LOG_ERROR("Could not find surface format");
-        return true;
-    }
-    surfaceFormat = d.surfaceFormat;
-    if(findVulkanSurfacePresentMode(
-           &d.presentMode, physicalDevice, surface,
-           getSurfacePresentModePoints)) {
-        LOG_ERROR("Could not find present mode");
-        return true;
-    }
-    u32 queueFamilyIndices[] = {graphicsFamily, presentFamily};
-    if(graphicsFamily != presentFamily) {
+    d.queueFamilies.add(baseData.graphicsFamily);
+    if(baseData.graphicsFamily != baseData.presentFamily) {
+        d.queueFamilies.add(baseData.presentFamily);
         d.sharingMode = VK_SHARING_MODE_CONCURRENT;
-        d.queueFamilyIndexCount = 2;
-        d.queueFamilyIndices = queueFamilyIndices;
     } else {
         d.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
     }
@@ -116,22 +112,18 @@ static bool initSwapchain() {
 }
 
 static bool initDevice() {
-    graphicsFamily =
-        findVulkanQueueFamily(physicalDevice, VK_QUEUE_GRAPHICS_BIT);
-    presentFamily = findVulkanSurfaceQueueFamily(physicalDevice, surface);
-    if(graphicsFamily == INVALID_VULKAN_QUEUE_FAMILY ||
-       presentFamily == INVALID_VULKAN_QUEUE_FAMILY) {
-        return true;
-    }
-    bool same = graphicsFamily == presentFamily;
-    VulkanDeviceQueueData data[] = {
-        {graphicsFamily, 1.0f}, {presentFamily, 1.0f}};
-    const char* extensions[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
-    if(initVulkanDevice(
-           &device, physicalDevice, data, same ? 1 : 2, extensions, 1)) {
+    bool same = baseData.graphicsFamily == baseData.presentFamily;
+    Core::List<Vulkan::DeviceQueueData> data;
+    data.add(baseData.graphicsFamily, 1.0f);
+    if(!same) {
+        data.add(baseData.presentFamily, 1.0f);
+    };
+    Core::List<const char*> extensions;
+    extensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+    if(base.initDevice(data, extensions)) {
         return true;
     }
-    vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue);
+    vkGetDeviceQueue(base, baseData.graphicsFamily, 0, &graphicsQueue);
     if(graphicsQueue == VK_NULL_HANDLE) {
         LOG_ERROR("Cannot get device graphics queue");
         return true;
@@ -140,7 +132,7 @@ static bool initDevice() {
         presentQueue = graphicsQueue;
         return false;
     }
-    vkGetDeviceQueue(device, presentFamily, 0, &presentQueue);
+    vkGetDeviceQueue(base, baseData.presentFamily, 0, &presentQueue);
     if(presentQueue == VK_NULL_HANDLE) {
         LOG_ERROR("Cannot get device present queue");
         return true;
@@ -148,10 +140,10 @@ static bool initDevice() {
     return false;
 }
 
-static int getDevicePoints(VkPhysicalDevice pd) {
+static int getDevicePoints(Vulkan::Base& b, BaseData& d) {
     int points = 0;
     VkPhysicalDeviceProperties p;
-    vkGetPhysicalDeviceProperties(pd, &p);
+    b.getPhysicalDeviceProperties(p);
     LOG_INFO("Checking '#'", p.deviceName);
     switch(p.deviceType) {
         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: points += 100; break;
@@ -159,34 +151,31 @@ static int getDevicePoints(VkPhysicalDevice pd) {
         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: points += 20; break;
         default: break;
     }
-    u32 gf = findVulkanQueueFamily(pd, VK_QUEUE_GRAPHICS_BIT);
-    if(gf == INVALID_VULKAN_QUEUE_FAMILY) {
+    d.graphicsFamily = b.findQueueFamily(VK_QUEUE_GRAPHICS_BIT);
+    if(d.graphicsFamily == Vulkan::INVALID_QUEUE_FAMILY) {
         LOG_INFO("> ... has no graphics family");
         points = -1;
     }
-    u32 pf = findVulkanSurfaceQueueFamily(pd, surface);
-    if(pf == INVALID_VULKAN_QUEUE_FAMILY) {
+    d.presentFamily = b.findSurfaceQueueFamily();
+    if(d.presentFamily == Vulkan::INVALID_QUEUE_FAMILY) {
         LOG_INFO("> ... has no present family");
         points = -1;
     }
-    if(!hasVulkanExtension(pd, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+    if(!b.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
         LOG_INFO("> ... has no swapchain support");
         points = -1;
     }
-    VkSurfaceFormatKHR sf = {};
-    if(findVulkanSurfaceFormat(&sf, pd, surface, getSurfaceFormatPoints)) {
+    if(b.findSurfaceFormat(d.surfaceFormat, getSurfaceFormatPoints)) {
         LOG_INFO("> ... has no matching surface format");
         points = -1;
     } else {
-        points += getSurfaceFormatPoints(&sf);
+        points += getSurfaceFormatPoints(d.surfaceFormat);
     }
-    VkPresentModeKHR m = {};
-    if(findVulkanSurfacePresentMode(
-           &m, pd, surface, getSurfacePresentModePoints)) {
+    if(b.findSurfacePresentMode(d.presentMode, getSurfacePresentModePoints)) {
         LOG_INFO("> ... has no matching present mode");
         points = -1;
     } else {
-        points += getSurfacePresentModePoints(m);
+        points += getSurfacePresentModePoints(d.presentMode);
     }
     LOG_INFO("> Final points: #", points);
     return points;
@@ -194,31 +183,31 @@ static int getDevicePoints(VkPhysicalDevice pd) {
 
 static bool initPhysicalDevice() {
     LOG_INFO("Searching for physical devices ...");
-    if(findVulkanPhysicalDevice(&physicalDevice, getDevicePoints)) {
+    if(base.findPhysicalDevice(baseData, getDevicePoints)) {
         LOG_ERROR("No matching physical device was found");
         return true;
     }
     VkPhysicalDeviceProperties p;
-    vkGetPhysicalDeviceProperties(physicalDevice, &p);
+    base.getPhysicalDeviceProperties(p);
     LOG_INFO("Best Device: #", p.deviceName);
     return false;
 }
 
 static bool initSwapchainImages() {
     if(initVulkanSwapchainImages(
-           &images, device, swapchain, surfaceFormat.format)) {
+           images, base, swapchain, baseData.surfaceFormat.format)) {
         LOG_ERROR("Could not get swapchain images");
         return true;
     }
-    LOG_INFO("Found # images", images.amount);
+    LOG_INFO("Found # images", images.images.getLength());
     return false;
 }
 
 static bool initShaders() {
     return initVulkanShaderModule(
-               &vertexShaderModule, device, "shaders/vertex.spv") ||
+               &vertexShaderModule, base, "shaders/vertex.spv") ||
            initVulkanShaderModule(
-               &fragmentShaderModule, device, "shaders/fragment.spv");
+               &fragmentShaderModule, base, "shaders/fragment.spv");
 }
 
 static bool initPipeline() {
@@ -323,14 +312,14 @@ static bool initPipeline() {
         .basePipelineHandle = VK_NULL_HANDLE,
         .basePipelineIndex = -1};
 
-    VK_ASSERT(vkCreateGraphicsPipelines(
-        device, VK_NULL_HANDLE, 1, &info, nullptr, &pipeline));
+    VK_CHECK_TRUE(vkCreateGraphicsPipelines(
+        base, VK_NULL_HANDLE, 1, &info, nullptr, &pipeline));
     return false;
 }
 
 static bool initRenderPass() {
     VkAttachmentDescription c = {
-        .format = surfaceFormat.format,
+        .format = baseData.surfaceFormat.format,
         .samples = VK_SAMPLE_COUNT_1_BIT,
         .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
         .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
@@ -360,7 +349,7 @@ static bool initRenderPass() {
         .pSubpasses = &subpass,
         .dependencyCount = 1,
         .pDependencies = &dependency};
-    VK_ASSERT(vkCreateRenderPass(device, &info, nullptr, &renderPass));
+    VK_CHECK_TRUE(vkCreateRenderPass(base, &info, nullptr, &renderPass));
     return false;
 }
 
@@ -368,15 +357,15 @@ static bool initCommandPool() {
     VkCommandPoolCreateInfo info = {
         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
         .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
-        .queueFamilyIndex = graphicsFamily};
-    VK_ASSERT(vkCreateCommandPool(device, &info, nullptr, &commandPool));
+        .queueFamilyIndex = baseData.graphicsFamily};
+    VK_CHECK_TRUE(vkCreateCommandPool(base, &info, nullptr, &commandPool));
     return false;
 }
 
 static bool fillCommandBuffer(VkCommandBuffer cb, u32 index) {
     VkCommandBufferBeginInfo info = {
         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
-    VK_ASSERT(vkBeginCommandBuffer(cb, &info));
+    VK_CHECK_TRUE(vkBeginCommandBuffer(cb, &info));
     VkClearValue v = {.color = {.float32 = {0.0f, 0.5f, 0.0f, 1.0f}}};
     VkRenderPassBeginInfo rInfo = {
         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
@@ -391,17 +380,17 @@ static bool fillCommandBuffer(VkCommandBuffer cb, u32 index) {
     vkCmdSetScissor(cb, 0, 1, &scissor);
     vkCmdDraw(cb, 3, 1, 0, 0);
     vkCmdEndRenderPass(cb);
-    VK_ASSERT(vkEndCommandBuffer(cb));
+    VK_CHECK_TRUE(vkEndCommandBuffer(cb));
     return false;
 }
 
 static bool initFrames() {
     for(size_t i = 0; i < MAX_FRAMES; i++) {
         if(initCommandVulkanBuffer(
-               &frames[i].commandBuffer, device, commandPool) ||
-           initVulkanSemaphore(&frames[i].imageAvailableSemaphore, device) ||
-           initVulkanSemaphore(&frames[i].renderFinishedSemaphore, device) ||
-           initVulkanFence(&frames[i].inFlightFence, device)) {
+               &frames[i].commandBuffer, base, commandPool) ||
+           initVulkanSemaphore(&frames[i].imageAvailableSemaphore, base) ||
+           initVulkanSemaphore(&frames[i].renderFinishedSemaphore, base) ||
+           initVulkanFence(&frames[i].inFlightFence, base)) {
             return true;
         }
     }
@@ -409,14 +398,12 @@ static bool initFrames() {
 }
 
 bool Vulkan::init() {
-    return initVulkanInstance() || initVulkanDebugging() ||
-           initVulkanSurface(&surface, Core::Window::get()) ||
-           initPhysicalDevice() || initDevice() || initSwapchain() ||
-           initSwapchainImages() || initShaders() ||
-           initVulkanPipelineLayout(&pipelineLayout, device) ||
+    return base.init() || initPhysicalDevice() || initDevice() ||
+           initSwapchain() || initSwapchainImages() || initShaders() ||
+           initVulkanPipelineLayout(&pipelineLayout, base) ||
            initRenderPass() || initPipeline() ||
            initVulkanFramebuffers(
-               &framebuffers, &images, device, renderPass, swapchainSize.width,
+               framebuffers, images, base, renderPass, swapchainSize.width,
                swapchainSize.height) ||
            initCommandPool() || initFrames();
 }
@@ -428,13 +415,14 @@ static bool render() {
         return false;
     }
     Frame* f = frames + currentFrame;
-    VK_ASSERT(vkWaitForFences(device, 1, &f->inFlightFence, true, UINT64_MAX));
-    VK_ASSERT(vkResetFences(device, 1, &f->inFlightFence));
+    VK_CHECK_TRUE(
+        vkWaitForFences(base, 1, &f->inFlightFence, true, UINT64_MAX));
+    VK_CHECK_TRUE(vkResetFences(base, 1, &f->inFlightFence));
 
     uint32_t imageIndex = 0;
-    VK_ASSERT(vkAcquireNextImageKHR(
-        device, swapchain, UINT64_MAX, f->imageAvailableSemaphore,
-        VK_NULL_HANDLE, &imageIndex));
+    VK_CHECK_TRUE(vkAcquireNextImageKHR(
+        base, swapchain, UINT64_MAX, f->imageAvailableSemaphore, VK_NULL_HANDLE,
+        &imageIndex));
 
     vkResetCommandBuffer(f->commandBuffer, 0);
     fillCommandBuffer(f->commandBuffer, imageIndex);
@@ -452,7 +440,7 @@ static bool render() {
         .pCommandBuffers = &f->commandBuffer,
         .signalSemaphoreCount = 1,
         .pSignalSemaphores = signalSemaphores};
-    VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &info, f->inFlightFence));
+    VK_CHECK_TRUE(vkQueueSubmit(graphicsQueue, 1, &info, f->inFlightFence));
 
     VkPresentInfoKHR presentInfo = {
         .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
@@ -462,7 +450,7 @@ static bool render() {
         .pSwapchains = &swapchain,
         .pImageIndices = &imageIndex};
 
-    VK_ASSERT(vkQueuePresentKHR(presentQueue, &presentInfo));
+    VK_CHECK_TRUE(vkQueuePresentKHR(presentQueue, &presentInfo));
     currentFrame = (currentFrame + 1) % MAX_FRAMES;
     return false;
 }
@@ -474,26 +462,27 @@ void Vulkan::render() {
 }
 
 void Vulkan::destroy(void) {
-    if(device != VK_NULL_HANDLE) {
-        vkDeviceWaitIdle(device);
+    if(static_cast<VkDevice>(base) != VK_NULL_HANDLE) {
+        vkDeviceWaitIdle(base);
         for(size_t i = 0; i < MAX_FRAMES; i++) {
             Frame* f = frames + i;
-            destroyVulkanFence(f->inFlightFence, device);
-            destroyVulkanSemaphore(f->imageAvailableSemaphore, device);
-            destroyVulkanSemaphore(f->renderFinishedSemaphore, device);
+            destroyVulkanFence(f->inFlightFence, base);
+            destroyVulkanSemaphore(f->imageAvailableSemaphore, base);
+            destroyVulkanSemaphore(f->renderFinishedSemaphore, base);
         }
-        vkDestroyCommandPool(device, commandPool, nullptr);
-        destroyVulkanFramebuffers(&framebuffers, images.amount, device);
-        vkDestroyPipeline(device, pipeline, nullptr);
-        vkDestroyRenderPass(device, renderPass, nullptr);
+        vkDestroyCommandPool(base, commandPool, nullptr);
+        destroyVulkanFramebuffers(framebuffers, base);
+        vkDestroyPipeline(base, pipeline, nullptr);
+        vkDestroyRenderPass(base, renderPass, nullptr);
     }
-    destroyVulkanPipelineLayout(pipelineLayout, device);
-    destroyVulkanShaderModule(vertexShaderModule, device);
-    destroyVulkanShaderModule(fragmentShaderModule, device);
-    destroyVulkanSwapchainImages(&images, device);
-    destroyVulkanSwapchain(swapchain, device);
-    destroyVulkanDevice(device);
-    destroyVulkanSurface(surface);
-    destroyVulkanDebugging();
-    destroyVulkanInstance();
+    destroyVulkanPipelineLayout(pipelineLayout, base);
+    destroyVulkanShaderModule(vertexShaderModule, base);
+    destroyVulkanShaderModule(fragmentShaderModule, base);
+    destroyVulkanSwapchainImages(images, base);
+    destroyVulkanSwapchain(swapchain, base);
+    base.destroy();
+    // frees the memory before the static objects are gone
+    images.images = List<VkImage>();
+    images.imageViews = List<VkImageView>();
+    framebuffers = List<VkFramebuffer>();
 }

+ 1 - 1
test/modules/WindowManagerTests.cpp

@@ -51,7 +51,7 @@ static void render(void*, float) {
 
 static void printReport(
     Core::LogLevel l, const char* file, int line, void*, const char* message) {
-    printLog(l, file, line, "", TERMINAL_RED, "%s", message);
+    printLog(l, file, line, TERMINAL_RED, "#", message);
 }
 
 void testWindow() {