Просмотр исходного кода

Split Vulkan code, several improvements

Kajetan Johannes Hammerle 2 месяцев назад
Родитель
Сommit
0214ff3c5f
7 измененных файлов с 752 добавлено и 515 удалено
  1. 1 0
      CMakeLists.txt
  2. 0 0
      src/GLFW.h
  3. 507 0
      src/VulkanUtils.c
  4. 83 0
      src/VulkanUtils.h
  5. 159 513
      src/VulkanWrapper.c
  6. 1 1
      src/WindowManager.c
  7. 1 1
      test/Main.c

+ 1 - 0
CMakeLists.txt

@@ -8,6 +8,7 @@ set(CMAKE_C_STANDARD 23)
 set(SRC
     "src/Image.c"
     "src/Network.c"
+    "src/VulkanUtils.c"
     "src/VulkanWrapper.c"
     "src/WindowManager.c"
 )

+ 0 - 0
include/core/internal/GLFW.h → src/GLFW.h


+ 507 - 0
src/VulkanUtils.c

@@ -0,0 +1,507 @@
+#include "VulkanUtils.h"
+
+#include <core/Logger.h>
+
+static VkInstance instance;
+#ifdef DEBUG_VULKAN
+static VkDebugUtilsMessengerEXT debugMessenger;
+static VkDebugReportCallbackEXT debugReportCallback;
+#endif
+
+#define VK_ERROR_CASE(error)  \
+    case error: return #error
+
+const char* getVulkanErrorString(VkResult r) {
+    switch(r) {
+        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_LAYER_NOT_PRESENT);
+        VK_ERROR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
+        VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
+        default: return "unknown";
+    }
+}
+
+static PFN_vkVoidFunction getVulkanFunction(const char* name) {
+    return vkGetInstanceProcAddr(instance, name);
+}
+
+#define GET_VULKAN_FUNCTION(name) ((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;
+    const char* extensions[32];
+    if(count > ARRAY_LENGTH(extensions)) {
+        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;
+#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 = (const char*[]){"VK_LAYER_KHRONOS_validation"},
+#endif
+        .enabledExtensionCount = count,
+        .ppEnabledExtensionNames = extensions};
+    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) {
+    VkQueueFamilyProperties properties[32];
+    u32 count = ARRAY_LENGTH(properties);
+    vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, properties);
+    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) {
+    VkSurfaceFormatKHR formats[64];
+    u32 c = ARRAY_LENGTH(formats);
+    VK_ASSERT(vkGetPhysicalDeviceSurfaceFormatsKHR(pd, s, &c, formats));
+    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) {
+    VkPresentModeKHR modes[64];
+    u32 c = ARRAY_LENGTH(modes);
+    VK_ASSERT(vkGetPhysicalDeviceSurfacePresentModesKHR(pd, s, &c, modes));
+    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) {
+    VkPhysicalDevice devices[32];
+    u32 c = ARRAY_LENGTH(devices);
+    VK_ASSERT(vkEnumeratePhysicalDevices(instance, &c, devices));
+    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) {
+    VkExtensionProperties e[1024];
+    u32 c = ARRAY_LENGTH(e);
+    VkResult r = vkEnumerateDeviceExtensionProperties(pd, nullptr, &c, e);
+    if(r != VK_SUCCESS) {
+        LOG_ERROR(
+            "Cannot get physical device extension properties: %s",
+            getVulkanErrorString(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] = {0};
+    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 = {0};
+    vkGetPhysicalDeviceFeatures(pd, &deviceFeatures);
+    VkDeviceCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+        .queueCreateInfoCount = (u32)n,
+        .pQueueCreateInfos = deviceQueueInfo,
+        .enabledExtensionCount = (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);
+    }
+}
+
+static u32 getSwapImageCount(const VkSurfaceCapabilitiesKHR* caps) {
+    u32 c = caps->minImageCount + 1;
+    // according to VkSurfaceCapabilitiesKHR doc:
+    // maxImageCount is 0 when there is no strict limit
+    if(caps->maxImageCount != 0) {
+        return minU32(c, caps->maxImageCount);
+    }
+    return c;
+}
+
+bool initVulkanSwapchain(VkSwapchainKHR* sc, VulkanSwapchainData* d) {
+    VkSurfaceCapabilitiesKHR caps = {0};
+    VK_ASSERT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+        d->physicalDevice, d->surface, &caps));
+    VkSwapchainCreateInfoKHR ci = {
+        .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+        .surface = d->surface,
+        .minImageCount = getSwapImageCount(&caps),
+        .imageFormat = d->surfaceFormat.format,
+        .imageColorSpace = d->surfaceFormat.colorSpace,
+        .imageExtent = d->size,
+        .imageArrayLayers = 1,
+        .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+        .imageSharingMode = d->sharingMode,
+        .queueFamilyIndexCount = d->queueFamilyIndexCount,
+        .pQueueFamilyIndices = d->queueFamilyIndices,
+        .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));
+    return false;
+}
+
+void destroyVulkanSwapchain(VkSwapchainKHR s, VkDevice d) {
+    if(d != VK_NULL_HANDLE) {
+        vkDestroySwapchainKHR(d, s, nullptr);
+    }
+}
+
+static bool createImageView(
+    VkImageView* view, VkDevice d, VkImage image, VkFormat format) {
+    VkImageViewCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+        .image = image,
+        .viewType = VK_IMAGE_VIEW_TYPE_2D,
+        .format = format,
+        .subresourceRange = {
+            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+            .baseMipLevel = 0,
+            .levelCount = 1,
+            .baseArrayLayer = 0,
+            .layerCount = 1}};
+    VK_ASSERT(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 = coreAllocate(sizeof(VkImage) * si->amount);
+    si->imageViews = coreZeroAllocate(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)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+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);
+    }
+    coreFree(si->images);
+    coreFree(si->imageViews);
+    *si = (VulkanSwapchainImages){0};
+}
+
+bool initVulkanSemaphore(VkSemaphore* s, VkDevice d) {
+    VkSemaphoreCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
+    VK_ASSERT(vkCreateSemaphore(d, &info, nullptr, s));
+    return false;
+}
+
+void destroyVulkanSemaphore(VkSemaphore s, VkDevice d) {
+    if(d != VK_NULL_HANDLE) {
+        vkDestroySemaphore(d, s, nullptr);
+    }
+}
+
+/*static bool initCommandBuffers() {
+    VkCommandPoolCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+        .queueFamilyIndex = vk.device.graphicsFamily};
+    VK_ASSERT(vkCreateCommandPool(
+        vk.device.logical, &info, nullptr, &vk.swapchain.commandPool));
+    vk.swapchain.commandsBuffers =
+        coreAllocate(sizeof(VkCommandBuffer) * vk.swapchain.amount);
+    VkCommandBufferAllocateInfo a = {
+        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+        .commandPool = vk.swapchain.commandPool,
+        .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+        .commandBufferCount = vk.swapchain.amount};
+    VK_ASSERT(vkAllocateCommandBuffers(
+        vk.device.logical, &a, vk.swapchain.commandsBuffers));
+    return false;
+}
+
+static void destroyCommandBuffers() {
+    if(vk.swapchain.commandPool != VK_NULL_HANDLE && vk.swapchain.amount > 0) {
+        vkFreeCommandBuffers(
+            vk.device.logical, vk.swapchain.commandPool, vk.swapchain.amount,
+            vk.swapchain.commandsBuffers);
+    }
+    coreFree(vk.swapchain.commandsBuffers);
+    vkDestroyCommandPool(vk.device.logical, vk.swapchain.commandPool, nullptr);
+}
+
+static bool initRenderPass() {
+    VkAttachmentDescription c = {
+        .format = vk.swapchain.format,
+        .samples = VK_SAMPLE_COUNT_1_BIT,
+        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR};
+    VkAttachmentReference ca = {
+        .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
+    VkSubpassDescription subpass = {
+        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+        .colorAttachmentCount = 1,
+        .pColorAttachments = &ca};
+    VkRenderPassCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+        .attachmentCount = 1,
+        .pAttachments = &c,
+        .subpassCount = 1,
+        .pSubpasses = &subpass};
+    VK_ASSERT(
+        vkCreateRenderPass(vk.device.logical, &info, nullptr, &vk.renderPass));
+    return false;
+}
+
+static bool initFramebuffers() {
+    vk.swapchain.framebuffers =
+        coreAllocate(sizeof(VkFramebuffer) * vk.swapchain.amount);
+    for(u32 i = 0; i < vk.swapchain.amount; i++) {
+        VkFramebufferCreateInfo info = {
+            .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+            .renderPass = vk.renderPass,
+            .attachmentCount = 1,
+            .pAttachments = vk.swapchain.imageViews + i,
+            .width = vk.width,
+            .height = vk.height,
+            .layers = 1};
+        VK_ASSERT(vkCreateFramebuffer(
+            vk.device.logical, &info, nullptr, vk.swapchain.framebuffers + i));
+    }
+    printf("%u\n", vk.swapchain.amount);
+    return false;
+}
+
+static void destroyFramebuffers() {
+    for(u32 i = 0; i < vk.swapchain.amount; i++) {
+        vkDestroyFramebuffer(
+            vk.device.logical, vk.swapchain.framebuffers[i], nullptr);
+    }
+    coreFree(vk.swapchain.framebuffers);
+}
+
+static bool fillCommandBuffer(u32 index) {
+    (void)index;
+    // VkCommandBufferBeginInfo info = {
+    //     .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+    //     .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT};
+    // VK_ASSERT(vkBeginCommandBuffer(vk.swapchain.commandsBuffers[index],
+    // &info)); VkClearValue v = {.color = {.int32 = {255, 0, 0, 0}}};
+    // VkRenderPassBeginInfo rInfo = {
+    //     .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+    //     .renderPass = vk.renderPass,
+    //     .framebuffer = vk.swapchain.framebuffers[index],
+    //     .renderArea = {.offset = {0, 0}, .extent = {vk.width, vk.height}},
+    //     .clearValueCount = 1,
+    //     .pClearValues = &v};
+    // vkCmdBeginRenderPass(vk.swapchain.commandsBuffers[index], &rInfo,
+    //                      VK_SUBPASS_CONTENTS_INLINE);
+    return false;
+}*/

+ 83 - 0
src/VulkanUtils.h

@@ -0,0 +1,83 @@
+#ifndef CORE_VULKAN_UTILS_H
+#define CORE_VULKAN_UTILS_H
+
+#define GLFW_INCLUDE_VULKAN
+#include <GLFW/glfw3.h>
+#include <core/Utility.h>
+
+const char* getVulkanErrorString(VkResult r);
+
+#define VK_ASSERT(a)                                                         \
+    do {                                                                     \
+        VkResult vkResult = (a);                                             \
+        if(vkResult != VK_SUCCESS) {                                         \
+            LOG_ERROR("Vulkan error: %s\n", getVulkanErrorString(vkResult)); \
+            return true;                                                     \
+        }                                                                    \
+    } while(false)
+
+bool initVulkanInstance();
+void destroyVulkanInstance();
+
+bool initVulkanDebugging();
+void destroyVulkanDebugging();
+
+#define INVALID_VULKAN_QUEUE_FAMILY ((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);
+
+typedef struct {
+    u32 queueFamilyIndex;
+    float priority;
+} VulkanDeviceQueueData;
+
+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);
+
+typedef struct {
+    VkPhysicalDevice physicalDevice;
+    VkDevice device;
+    VkSurfaceKHR surface;
+    VkExtent2D size;
+    VkSurfaceFormatKHR surfaceFormat;
+    VkPresentModeKHR presentMode;
+    VkSharingMode sharingMode;
+    u32 queueFamilyIndexCount;
+    u32* queueFamilyIndices;
+} VulkanSwapchainData;
+
+bool initVulkanSwapchain(VkSwapchainKHR* sc, VulkanSwapchainData* d);
+void destroyVulkanSwapchain(VkSwapchainKHR s, VkDevice d);
+
+typedef struct {
+    u32 amount;
+    VkImage* images;
+    VkImageView* imageViews;
+} VulkanSwapchainImages;
+
+bool initVulkanSwapchainImages(
+    VulkanSwapchainImages* si, VkDevice d, VkSwapchainKHR sc, VkFormat format);
+void destroyVulkanSwapchainImages(VulkanSwapchainImages* si, VkDevice d);
+
+bool initVulkanSemaphore(VkSemaphore* s, VkDevice d);
+void destroyVulkanSemaphore(VkSemaphore s, VkDevice d);
+
+#endif

+ 159 - 513
src/VulkanWrapper.c

@@ -2,220 +2,139 @@
 
 #include <core/Logger.h>
 #include <core/Utility.h>
-#include <stdio.h>
 
-#include "core/internal/GLFW.h"
+#include "GLFW.h"
+#include "VulkanUtils.h"
 
-typedef struct {
-    VkPhysicalDevice physical;
-    VkDevice logical;
-    u32 graphicsFamily;
-    VkQueue graphicsQueue;
-} Device;
+// VkCommandPool commandPool;
+// VkCommandBuffer* commandsBuffers;
+// VkFramebuffer* framebuffers;
+// VkSemaphore semaphore;
+// VkSemaphore renderSemaphore;
+// VkRenderPass renderPass;
 
-typedef struct {
-    VkFormat format;
-    VkSwapchainKHR handle;
-    u32 amount;
-    VkImage* images;
-    VkImageView* imageViews;
-    VkCommandPool commandPool;
-    VkCommandBuffer* commandsBuffers;
-    VkFramebuffer* framebuffers;
-} Swapchain;
+static VkPhysicalDevice physicalDevice;
+static u32 graphicsFamily = 0;
+static u32 presentFamily = 0;
+static VkDevice device;
+static VkQueue graphicsQueue;
+static VkQueue presentQueue;
+static VkSurfaceFormatKHR surfaceFormat;
+static VkSurfaceKHR surface;
+static VkSwapchainKHR swapchain;
+static VulkanSwapchainImages images;
 
-typedef struct {
-    // basic setup
-    VkInstance instance;
-    VkSurfaceKHR surface;
-#ifdef DEBUG_VULKAN
-    VkDebugUtilsMessengerEXT debugMessenger;
-    VkDebugReportCallbackEXT debugReportCallback;
-#endif
-    // render setup
-    Device device;
-    VkSemaphore semaphore;
-    VkSemaphore renderSemaphore;
-    Swapchain swapchain;
-    VkRenderPass renderPass;
-    u32 width;
-    u32 height;
-} VulkanData;
-
-static VulkanData vk = {0};
-
-#define VK_ERROR_CASE(error)  \
-    case error: return #error
-
-static const char* getVulkanErrorString(VkResult r) {
-    switch(r) {
-        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_LAYER_NOT_PRESENT);
-        VK_ERROR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
-        VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
-        default: return "unknown";
+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;
 }
 
-#define VK_ASSERT(a)                                                         \
-    do {                                                                     \
-        VkResult vkResult = (a);                                             \
-        if(vkResult != VK_SUCCESS) {                                         \
-            LOG_ERROR("Vulkan error: %s\n", getVulkanErrorString(vkResult)); \
-            return true;                                                     \
-        }                                                                    \
-    } while(false)
-
-static PFN_vkVoidFunction getVulkanFunction(const char* name) {
-    return vkGetInstanceProcAddr(vk.instance, name);
+static int getSurfacePresentModePoints(VkPresentModeKHR m) {
+    if(m == VK_PRESENT_MODE_MAILBOX_KHR) {
+        return 5;
+    } else if(m == VK_PRESENT_MODE_FIFO_KHR) {
+        return 2;
+    }
+    return 0;
 }
 
-#define GET_VULKAN_FUNCTION(name) ((PFN_##name)getVulkanFunction(#name))
-
-static bool initInstance() {
-    u32 baseCount = 0;
-    const char** baseExtensions = glfwGetRequiredInstanceExtensions(&baseCount);
-    if(baseExtensions == nullptr) {
-        LOG_ERROR("Could not get required extensions from GLFW");
-        return true;
+static bool getSwapchainSize(VkExtent2D* size) {
+    VkSurfaceCapabilitiesKHR c = {0};
+    VK_ASSERT(
+        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &c));
+    if(c.currentExtent.width != 0xFFFF'FFFFu &&
+       c.currentExtent.height != 0xFFFF'FFFFu) {
+        *size = c.currentExtent;
+        LOG_INFO("Swapchain size: %ux%u", size->width, size->height);
+        return false;
     }
-#ifdef DEBUG_VULKAN
-    u32 count = baseCount + 2;
-    const char* extensions[32];
-    if(count > ARRAY_LENGTH(extensions)) {
-        LOG_ERROR("Extension buffer is too small");
+    int w = 0;
+    int h = 0;
+    glfwGetFramebufferSize(getWindow(), &w, &h);
+    if(w <= 0 || h <= 0) {
+        LOG_ERROR("Could not get framebuffer size");
         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;
-#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 = (const char*[]){"VK_LAYER_KHRONOS_validation"},
-#endif
-        .enabledExtensionCount = count,
-        .ppEnabledExtensionNames = extensions};
-    VK_ASSERT(vkCreateInstance(&info, nullptr, &vk.instance));
-    return false;
-}
-
-#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);
+    LOG_INFO("Framebuffer size: %dx%d", w, h);
+    size->width =
+        clampU32((u32)w, c.minImageExtent.width, c.maxImageExtent.width);
+    size->height =
+        clampU32((u32)h, c.minImageExtent.height, c.maxImageExtent.height);
+    LOG_INFO("Swapchain size: %ux%u", size->width, size->height);
     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;
+static bool initSwapchain() {
+    VulkanSwapchainData d = {
+        .physicalDevice = physicalDevice, .device = device, .surface = surface};
+    if(getSwapchainSize(&d.size)) {
+        LOG_ERROR("Could not retrieve any swapchain size");
+        return true;
     }
-    VK_ASSERT(f(vk.instance, &info, nullptr, &vk.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;
+    if(findVulkanSurfaceFormat(
+           &d.surfaceFormat, physicalDevice, surface, getSurfaceFormatPoints)) {
+        LOG_ERROR("Could not find surface format");
+        return true;
     }
-    VK_ASSERT(f(vk.instance, &info, nullptr, &vk.debugReportCallback));
-    return false;
-}
-
-static bool initDebugging() {
-    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;
+    surfaceFormat = d.surfaceFormat;
+    if(findVulkanSurfacePresentMode(
+           &d.presentMode, physicalDevice, surface,
+           getSurfacePresentModePoints)) {
+        LOG_ERROR("Could not find present mode");
+        return true;
     }
-    f(vk.instance, vk.debugMessenger, nullptr);
-}
-
-static void destroyDebugReportCallback() {
-    auto f = GET_VULKAN_FUNCTION(vkDestroyDebugReportCallbackEXT);
-    if(f == nullptr) {
-        LOG_WARNING("Could not find debug report destroy function");
-        return;
+    u32 queueFamilyIndices[] = {graphicsFamily, presentFamily};
+    if(graphicsFamily != presentFamily) {
+        d.sharingMode = VK_SHARING_MODE_CONCURRENT;
+        d.queueFamilyIndexCount = 2;
+        d.queueFamilyIndices = queueFamilyIndices;
+    } else {
+        d.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
     }
-    f(vk.instance, vk.debugReportCallback, nullptr);
-}
-#else
-static bool initDebugging() {
-    (void)getVulkanFunction;
-    return false;
-}
-
-static void destroyDebugMessenger() {
+    return initVulkanSwapchain(&swapchain, &d);
 }
 
-static void destroyDebugReportCallback() {
-}
-#endif
-
-static u32 findQueueFamilies(VkPhysicalDevice pd, VkQueueFlags flags) {
-    VkQueueFamilyProperties properties[32];
-    u32 count = ARRAY_LENGTH(properties);
-    vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, properties);
-    for(u32 i = 0; i < count; i++) {
-        if((properties[i].queueFlags & flags) == flags) {
-            return i;
-        }
+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,
+           ARRAY_LENGTH(extensions))) {
+        return true;
+    }
+    vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue);
+    if(graphicsQueue == VK_NULL_HANDLE) {
+        LOG_ERROR("Cannot get device graphics queue");
+        return true;
+    }
+    if(same) {
+        presentQueue = graphicsQueue;
+        return false;
+    }
+    vkGetDeviceQueue(device, presentFamily, 0, &presentQueue);
+    if(presentQueue == VK_NULL_HANDLE) {
+        LOG_ERROR("Cannot get device present queue");
+        return true;
     }
-    return (u32)-1;
+    return false;
 }
 
-static int getDevicePoints(Device* d) {
+static int getDevicePoints(VkPhysicalDevice pd) {
     int points = 0;
     VkPhysicalDeviceProperties p;
-    vkGetPhysicalDeviceProperties(d->physical, &p);
+    vkGetPhysicalDeviceProperties(pd, &p);
     LOG_INFO("Checking '%s'", p.deviceName);
     switch(p.deviceType) {
         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: points += 100; break;
@@ -223,358 +142,85 @@ static int getDevicePoints(Device* d) {
         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: points += 20; break;
         default: break;
     }
-    d->graphicsFamily = findQueueFamilies(d->physical, VK_QUEUE_GRAPHICS_BIT);
-    if(d->graphicsFamily == (u32)-1) {
+    u32 gf = findVulkanQueueFamily(pd, VK_QUEUE_GRAPHICS_BIT);
+    if(gf == INVALID_VULKAN_QUEUE_FAMILY) {
         LOG_INFO("> ... has no graphics family");
         points = -1;
     }
+    u32 pf = findVulkanSurfaceQueueFamily(pd, surface);
+    if(pf == INVALID_VULKAN_QUEUE_FAMILY) {
+        LOG_INFO("> ... has no present family");
+        points = -1;
+    }
+    if(!hasVulkanExtension(pd, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+        LOG_INFO("> ... has no swapchain support");
+        points = -1;
+    }
+    VkSurfaceFormatKHR sf = {0};
+    if(findVulkanSurfaceFormat(&sf, pd, surface, getSurfaceFormatPoints)) {
+        LOG_INFO("> ... has no matching surface format");
+        points = -1;
+    } else {
+        points += getSurfaceFormatPoints(&sf);
+    }
+    VkPresentModeKHR m = 0;
+    if(findVulkanSurfacePresentMode(
+           &m, pd, surface, getSurfacePresentModePoints)) {
+        LOG_INFO("> ... has no matching present mode");
+        points = -1;
+    } else {
+        points += getSurfacePresentModePoints(m);
+    }
     LOG_INFO("> Final points: %d", points);
     return points;
 }
 
 static bool initPhysicalDevice() {
-    VkPhysicalDevice devices[32];
-    u32 c = ARRAY_LENGTH(devices);
-    VK_ASSERT(vkEnumeratePhysicalDevices(vk.instance, &c, devices));
-    LOG_INFO("Found %u physical devices", c);
-    int bestPoints = 0;
-    for(u32 i = 0; i < c; i++) {
-        Device d = {.physical = devices[i]};
-        int points = getDevicePoints(&d);
-        if(points > bestPoints) {
-            bestPoints = points;
-            vk.device = d;
-        }
-    }
-    if(bestPoints == 0) {
+    LOG_INFO("Searching for physical devices ...");
+    if(findVulkanPhysicalDevice(&physicalDevice, getDevicePoints)) {
         LOG_ERROR("No matching physical device was found");
         return true;
     }
     VkPhysicalDeviceProperties p;
-    vkGetPhysicalDeviceProperties(vk.device.physical, &p);
+    vkGetPhysicalDeviceProperties(physicalDevice, &p);
     LOG_INFO("Best Device: %s", p.deviceName);
     return false;
 }
 
-static bool getDeviceQueue(Device* d, VkQueue* q) {
-    vkGetDeviceQueue(d->logical, d->graphicsFamily, 0, q);
-    return *q == VK_NULL_HANDLE;
-}
-
-static bool initDevice(Device* d) {
-    VkPhysicalDeviceFeatures deviceFeatures = {0};
-    vkGetPhysicalDeviceFeatures(d->physical, &deviceFeatures);
-    VkDeviceQueueCreateInfo deviceQueueInfo = {
-        .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
-        .queueFamilyIndex = d->graphicsFamily,
-        .queueCount = 1,
-        .pQueuePriorities = (float[]){1.0f}};
-    VkDeviceCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-        .queueCreateInfoCount = 1,
-        .pQueueCreateInfos = &deviceQueueInfo,
-        .enabledExtensionCount = 1,
-        .ppEnabledExtensionNames =
-            (const char*[]){VK_KHR_SWAPCHAIN_EXTENSION_NAME},
-        .pEnabledFeatures = &deviceFeatures};
-    VK_ASSERT(vkCreateDevice(d->physical, &info, nullptr, &d->logical));
-    if(getDeviceQueue(d, &d->graphicsQueue)) {
-        LOG_ERROR("Cannot get device graphics queue");
-        return true;
-    }
-    return false;
-}
-
-static bool initSurface() {
-    VK_ASSERT(glfwCreateWindowSurface(
-        vk.instance, getWindow(), nullptr, &vk.surface));
-    return false;
-}
-
-static u32 getSwapImageCount(const VkSurfaceCapabilitiesKHR* caps) {
-    u32 c = caps->minImageCount + 1;
-    // according to VkSurfaceCapabilitiesKHR doc:
-    // maxImageCount is 0 when there is no strict limit
-    if(caps->maxImageCount != 0 && c > caps->maxImageCount) {
-        return caps->maxImageCount;
-    }
-    return c;
-}
-
-static bool getSurfaceFormat(VkSurfaceFormatKHR* sf) {
-    u32 c = 0;
-    VK_ASSERT(vkGetPhysicalDeviceSurfaceFormatsKHR(
-        vk.device.physical, vk.surface, &c, nullptr));
-    VkSurfaceFormatKHR* formats = coreAllocate(sizeof(VkSurfaceFormatKHR) * c);
-    VK_ASSERT(vkGetPhysicalDeviceSurfaceFormatsKHR(
-        vk.device.physical, vk.surface, &c, formats));
-    for(u32 i = 0; i < c; i++) {
-        if(formats[i].format == VK_FORMAT_B8G8R8A8_UNORM &&
-           formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
-            *sf = formats[i];
-            coreFree(formats);
-            return false;
-        }
-    }
-    coreFree(formats);
-    LOG_ERROR("Could not find any matching surface format");
-    return true;
-}
-
-static bool getPresentMode(VkPresentModeKHR* pm) {
-    u32 c = 0;
-    VK_ASSERT(vkGetPhysicalDeviceSurfacePresentModesKHR(
-        vk.device.physical, vk.surface, &c, nullptr));
-    VkPresentModeKHR* modes = coreAllocate(sizeof(VkPresentModeKHR) * c);
-    VK_ASSERT(vkGetPhysicalDeviceSurfacePresentModesKHR(
-        vk.device.physical, vk.surface, &c, modes));
-    for(u32 i = 0; i < c; i++) {
-        if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
-            *pm = modes[i];
-            coreFree(modes);
-            return false;
-        }
-    }
-    coreFree(modes);
-    LOG_ERROR("Could not find any matching present modes");
-    return true;
-}
-
-static bool initSwapchain() {
-    VkSurfaceCapabilitiesKHR caps = {0};
-    VK_ASSERT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
-        vk.device.physical, vk.surface, &caps));
-    VkSurfaceFormatKHR sf = {0};
-    if(getSurfaceFormat(&sf)) {
-        return true;
-    }
-    vk.swapchain.format = sf.format;
-    VkPresentModeKHR pm = {0};
-    if(getPresentMode(&pm)) {
-        return true;
-    }
-    VkSwapchainCreateInfoKHR ci = {
-        .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
-        .surface = vk.surface,
-        .minImageCount = getSwapImageCount(&caps),
-        .imageFormat = sf.format,
-        .imageColorSpace = sf.colorSpace,
-        .imageExtent = {.width = vk.width, .height = vk.height},
-        .imageArrayLayers = 1,
-        .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                      VK_IMAGE_USAGE_TRANSFER_DST_BIT,
-        .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
-        .queueFamilyIndexCount = 1,
-        .pQueueFamilyIndices = &vk.device.graphicsFamily,
-        .preTransform = caps.currentTransform,
-        .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
-        .presentMode = pm,
-        .clipped = VK_TRUE,
-        .oldSwapchain = VK_NULL_HANDLE};
-    VK_ASSERT(vkCreateSwapchainKHR(
-        vk.device.logical, &ci, nullptr, &vk.swapchain.handle));
-    return false;
-}
-
-static bool createImageView(VkImage image, VkImageView* view) {
-    VkImageViewCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
-        .image = image,
-        .viewType = VK_IMAGE_VIEW_TYPE_2D,
-        .format = VK_FORMAT_B8G8R8A8_UNORM,
-        .subresourceRange = {
-            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
-            .baseMipLevel = 0,
-            .levelCount = 1,
-            .baseArrayLayer = 0,
-            .layerCount = 1}};
-    VK_ASSERT(vkCreateImageView(vk.device.logical, &info, nullptr, view));
-    return false;
-}
-
-static void destroySwapchainImages() {
-    for(size_t x = 0; x < vk.swapchain.amount; x++) {
-        vkDestroyImageView(
-            vk.device.logical, vk.swapchain.imageViews[x], nullptr);
-    }
-    coreFree(vk.swapchain.images);
-    coreFree(vk.swapchain.imageViews);
-}
-
 static bool initSwapchainImages() {
-    u32 c = 0;
-    VK_ASSERT(vkGetSwapchainImagesKHR(
-        vk.device.logical, vk.swapchain.handle, &c, nullptr));
-    LOG_INFO("Found %u images", c);
-    vk.swapchain.amount = c;
-    vk.swapchain.images = coreAllocate(sizeof(VkImage) * c);
-    vk.swapchain.imageViews = coreZeroAllocate(sizeof(VkImageView) * c);
-    VK_ASSERT(vkGetSwapchainImagesKHR(
-        vk.device.logical, vk.swapchain.handle, &c, vk.swapchain.images));
-    for(u32 x = 0; x < c; x++) {
-        if(createImageView(
-               vk.swapchain.images[x], vk.swapchain.imageViews + x)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static bool initSemaphore(VkSemaphore* s) {
-    VkSemaphoreCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
-    VK_ASSERT(vkCreateSemaphore(vk.device.logical, &info, nullptr, s));
-    return false;
-}
-
-static void destroySemaphore(VkSemaphore s) {
-    vkDestroySemaphore(vk.device.logical, s, nullptr);
-}
-
-static bool checkPresentationSupport() {
-    VkBool32 b = false;
-    VK_ASSERT(vkGetPhysicalDeviceSurfaceSupportKHR(
-        vk.device.physical, vk.device.graphicsFamily, vk.surface, &b));
-    if(!b) {
-        LOG_ERROR("Presentation is not supported");
+    if(initVulkanSwapchainImages(
+           &images, device, swapchain, surfaceFormat.format)) {
+        LOG_ERROR("Could not get swapchain images");
         return true;
     }
+    LOG_INFO("Found %u images", images.amount);
     return false;
 }
 
-static bool initCommandBuffers() {
-    VkCommandPoolCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
-        .queueFamilyIndex = vk.device.graphicsFamily};
-    VK_ASSERT(vkCreateCommandPool(
-        vk.device.logical, &info, nullptr, &vk.swapchain.commandPool));
-    vk.swapchain.commandsBuffers =
-        coreAllocate(sizeof(VkCommandBuffer) * vk.swapchain.amount);
-    VkCommandBufferAllocateInfo a = {
-        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
-        .commandPool = vk.swapchain.commandPool,
-        .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
-        .commandBufferCount = vk.swapchain.amount};
-    VK_ASSERT(vkAllocateCommandBuffers(
-        vk.device.logical, &a, vk.swapchain.commandsBuffers));
-    return false;
-}
-
-static void destroyCommandBuffers() {
-    if(vk.swapchain.commandPool != VK_NULL_HANDLE && vk.swapchain.amount > 0) {
-        vkFreeCommandBuffers(
-            vk.device.logical, vk.swapchain.commandPool, vk.swapchain.amount,
-            vk.swapchain.commandsBuffers);
-    }
-    coreFree(vk.swapchain.commandsBuffers);
-    vkDestroyCommandPool(vk.device.logical, vk.swapchain.commandPool, nullptr);
-}
-
-static bool initRenderPass() {
-    VkAttachmentDescription c = {
-        .format = vk.swapchain.format,
-        .samples = VK_SAMPLE_COUNT_1_BIT,
-        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
-        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
-        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
-        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
-        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
-        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR};
-    VkAttachmentReference ca = {
-        .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
-    VkSubpassDescription subpass = {
-        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-        .colorAttachmentCount = 1,
-        .pColorAttachments = &ca};
-    VkRenderPassCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-        .attachmentCount = 1,
-        .pAttachments = &c,
-        .subpassCount = 1,
-        .pSubpasses = &subpass};
-    VK_ASSERT(
-        vkCreateRenderPass(vk.device.logical, &info, nullptr, &vk.renderPass));
-    return false;
-}
-
-static bool initFramebuffers() {
-    vk.swapchain.framebuffers =
-        coreAllocate(sizeof(VkFramebuffer) * vk.swapchain.amount);
-    for(u32 i = 0; i < vk.swapchain.amount; i++) {
-        VkFramebufferCreateInfo info = {
-            .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
-            .renderPass = vk.renderPass,
-            .attachmentCount = 1,
-            .pAttachments = vk.swapchain.imageViews + i,
-            .width = vk.width,
-            .height = vk.height,
-            .layers = 1};
-        VK_ASSERT(vkCreateFramebuffer(
-            vk.device.logical, &info, nullptr, vk.swapchain.framebuffers + i));
-    }
-    printf("%u\n", vk.swapchain.amount);
-    return false;
-}
-
-static void destroyFramebuffers() {
-    for(u32 i = 0; i < vk.swapchain.amount; i++) {
-        vkDestroyFramebuffer(
-            vk.device.logical, vk.swapchain.framebuffers[i], nullptr);
-    }
-    coreFree(vk.swapchain.framebuffers);
-}
-
 bool initVulkan() {
-    vk.width = 400;
-    vk.height = 300;
-    return initInstance() || initDebugging() || initSurface() ||
-           initPhysicalDevice() || initDevice(&vk.device) ||
-           checkPresentationSupport() || initSwapchain() ||
-           initSwapchainImages() || initSemaphore(&vk.semaphore) ||
-           initSemaphore(&vk.renderSemaphore) || initCommandBuffers() ||
-           initRenderPass() || initFramebuffers();
-}
-
-static bool fillCommandBuffer(u32 index) {
-    (void)index;
-    // VkCommandBufferBeginInfo info = {
-    //     .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
-    //     .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT};
-    // VK_ASSERT(vkBeginCommandBuffer(vk.swapchain.commandsBuffers[index],
-    // &info)); VkClearValue v = {.color = {.int32 = {255, 0, 0, 0}}};
-    // VkRenderPassBeginInfo rInfo = {
-    //     .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-    //     .renderPass = vk.renderPass,
-    //     .framebuffer = vk.swapchain.framebuffers[index],
-    //     .renderArea = {.offset = {0, 0}, .extent = {vk.width, vk.height}},
-    //     .clearValueCount = 1,
-    //     .pClearValues = &v};
-    // vkCmdBeginRenderPass(vk.swapchain.commandsBuffers[index], &rInfo,
-    //                      VK_SUBPASS_CONTENTS_INLINE);
-    return false;
+    return initVulkanInstance() || initVulkanDebugging() ||
+           initVulkanSurface(&surface, getWindow()) || initPhysicalDevice() ||
+           initDevice() || initSwapchain() || initSwapchainImages();
+    /*  || initSemaphore(&vk.semaphore) ||
+       initSemaphore(&vk.renderSemaphore) || initCommandBuffers() ||
+       initRenderPass() || initFramebuffers()*/
 }
 
 void renderVulkan() {
-    for(u32 i = 0; i < vk.swapchain.amount; i++) {
-        fillCommandBuffer(i);
-    }
 }
 
 void destroyVulkan(void) {
-    if(vk.device.logical != VK_NULL_HANDLE) {
-        destroyFramebuffers();
-        vkDestroyRenderPass(vk.device.logical, vk.renderPass, nullptr);
-        destroyCommandBuffers();
-        destroySemaphore(vk.semaphore);
-        destroySemaphore(vk.renderSemaphore);
-        destroySwapchainImages();
-        vkDestroySwapchainKHR(vk.device.logical, vk.swapchain.handle, nullptr);
-    }
-    vkDestroyDevice(vk.device.logical, nullptr);
-    if(vk.instance != VK_NULL_HANDLE) {
-        vkDestroySurfaceKHR(vk.instance, vk.surface, nullptr);
-        destroyDebugMessenger();
-        destroyDebugReportCallback();
-    }
-    vkDestroyInstance(vk.instance, nullptr);
+    // if(vk.device.logical != VK_NULL_HANDLE) {
+    //     destroyFramebuffers();
+    //     vkDestroyRenderPass(vk.device.logical, vk.renderPass, nullptr);
+    //     destroyCommandBuffers();
+    //     destroySemaphore(vk.semaphore);
+    //     destroySemaphore(vk.renderSemaphore);
+    // }
+    destroyVulkanSwapchainImages(&images, device);
+    destroyVulkanSwapchain(swapchain, device);
+    destroyVulkanDevice(device);
+    destroyVulkanSurface(surface);
+    destroyVulkanDebugging();
+    destroyVulkanInstance();
 }

+ 1 - 1
src/WindowManager.c

@@ -6,8 +6,8 @@
 #include <stdio.h>
 #include <uchar.h>
 
+#include "GLFW.h"
 #include "core/VulkanWrapper.h"
-#include "core/internal/GLFW.h"
 
 static bool dummyWindowRunHandler(void*) {
     return !shouldWindowClose();

+ 1 - 1
test/Main.c

@@ -8,7 +8,7 @@
 
 int main(int argAmount, char** args) {
     if(argAmount >= 2 && strcmp(args[1], "help") == 0) {
-        puts("test");
+        // puts("test");
         puts("window");
         return 0;
     }