/** * @file vulkanBase.cpp * @author Piotr Krygier (everyonecancode@gmail.com) * @brief Base configuration for Vulkan API * @version 0.1 * @date 2022-05-13 * * @copyright Copyright (c) 2022 * */ /* TODO: Replace with more dynamic include */ #define VK_USE_PLATFORM_XCB_KHR #include "vulkanBase.hpp" #include #include #include #include "localeVulkan.hpp" #include "log.hpp" #include "window.hpp" #include #include enum VULKAN_ERROR { VULKAN_ERROR_NO_ERROR = 0x0U, VULKAN_ERROR_INSTANCE_INIT_FAILED, VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND, VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND, VULKAN_ERROR_QUEUE_NOT_SUPPORTED, VULKAN_ERROR_DEVICE_CREATION_FAILED, VULKAN_ERROR_ALLOCATOR_CREATION_FAILED, VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED, VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED, VULKAN_ERROR_SURFACE_CREATION_FAILED, VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED, VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED, }; /* Macro for checking status of function execution in initVulkan. Created to avoid writing boilerplate code */ #define STATUS_CHECK(FUNC) \ status = FUNC; \ if (VULKAN_ERROR_NO_ERROR != status) { \ return status; \ } #define APPLICATION_NAME "RedScarfEngine PoC" #define ENGINE_NAME "RedScarf Engine" #define SWAP_BUFFER_COUNT 2U /* Define Validation Layers for debug build */ #ifndef NDEBUG std::vector gEnabledInstanceLayersNames = {"VK_LAYER_KHRONOS_validation"}; #else std::vector gEnabledInstanceLayersNames = {}; #endif #define ENABLED_DEVICE_EXTENSIONS_COUNT 1U /* Extensions required by GLFW. TODO: Check for extensions required on other platforms */ std::vector gEnabledInstanceExtensionsNames = { "VK_KHR_surface", "VK_KHR_xcb_surface", "VK_KHR_device_group_creation", #ifndef NDEBUG "VK_EXT_debug_utils", #endif }; std::vector gEnabledDeviceExtensionsNames[ENABLED_DEVICE_EXTENSIONS_COUNT] = { "VK_KHR_swapchain", }; uint32_t gQueueFamilyIndices[1] = {0U}; /* TODO: Change when more families are needed */ uint32_t gSwapchainImagesCount = 0U; VkInstance gVulkanInstance = VK_NULL_HANDLE; VkSurfaceKHR gSurface = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT gDebugMessenger = VK_NULL_HANDLE; VkPhysicalDevice gPhysicalDevice = VK_NULL_HANDLE; VkDevice gDevice = VK_NULL_HANDLE; VmaAllocator gAllocator = VK_NULL_HANDLE; VkCommandPool gCommandPool = VK_NULL_HANDLE; VkCommandBuffer* gpCommandBuffers = NULL; /* This one is an array. Allocated during runtime */ VkSwapchainKHR gSwapchain = VK_NULL_HANDLE; VkImage* gpSwapChainImages = NULL; VkImageView* gpSwapChainImageViews = NULL; /** * @brief Create the Vulkan Instance object * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_INSTANCE_INIT_FAILED */ static int createInstance(); /** * @brief Create a Surface, connection between Vulkan and actual window * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: */ static int createSurface(); /** * @brief Choose physical device. Used later for vkDevice * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND * VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND */ static int pickPhysicalDevice(); /** * @brief Create vkDevice object * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_QUEUE_NOT_SUPPORTED * VULKAN_ERROR_DEVICE_CREATION_FAILED */ static int createDevice(); #ifndef NDEBUG /** * @brief Setup debugging system for Vulkan API * */ static void setupDebugMessenger(); /** * @brief Create a Memory Allocator object * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_ALLOCATOR_CREATION_FAILED */ static int createMemoryAllocator(); /** * @brief Create Command Pools * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED */ static int createCommandPools(); /** * @brief Allocate Command Buffers * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED */ static int allocateCommandBuffers(); /** * @brief Create a Swapchain * * @return int VULKAN_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED */ static int createSwapchain(); /** * @brief Create a Swapchain Image Views * * @return int int VULKAN_ERROR_NO_ERROR on success. Possible errors: */ static int createSwapchainImageViews(); /** * @brief Calback for debug messenger * * @param messageSeverity Message severity * @param messageType Type of a message * @param pCallbackData Contains all the callback related data in the VkDebugUtilsMessengerCallbackDataEXT structure * @param pUserData Data provided by the user * @return VkBool32 Should always return VK_FALSE. The VK_TRUE value is reserved for use in layer development */ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { (void)messageSeverity; (void)messageType; (void)pUserData; fprintf(stderr, "validation layer: %s\n", pCallbackData->pMessage); return VK_FALSE; } /** * @brief Proxy for vkCreateDebugUtilsMessengerEXT * * @param instance Vulkan instance object * @param pCreateInfo VkDebugUtilsMessengerCreateInfoEXT structure * @param pAllocator Memory allocator * @param pDebugMessenger Debug messanger handle * @return VkResult VK_SUCCESS on success */ static VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) { PFN_vkCreateDebugUtilsMessengerEXT func = NULL; func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); if (func != NULL) { return func(instance, pCreateInfo, pAllocator, pDebugMessenger); } else { return VK_ERROR_EXTENSION_NOT_PRESENT; } return VK_SUCCESS; } /** * @brief Proxy for vkDestroyDebugUtilsMessengerEXT * * @param instance Vulkan instance object * @param debugMessenger Debug messanger handle * @param pAllocator Memory allocator */ static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) { PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); if (func != NULL) { func(instance, debugMessenger, pAllocator); } } static void setupDebugMessenger() { VkDebugUtilsMessengerCreateInfoEXT createInfo; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; createInfo.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; createInfo.pfnUserCallback = debugCallback; createInfo.pUserData = NULL; // Optional createInfo.flags = 0U; if (CreateDebugUtilsMessengerEXT(gVulkanInstance, &createInfo, NULL, &gDebugMessenger) != VK_SUCCESS) { fprintf(stderr, "failed to set up debug messenger!"); } } #endif static int createInstance() { uint32_t extensionCount = 0; uint32_t layersCount = 0; VkApplicationInfo applicationInfo; VkInstanceCreateInfo createInfo; std::vector layerProperties; std::vector extensionsProperties; /* TODO: Remove or use later layer and extension properties */ vkEnumerateInstanceLayerProperties(&layersCount, NULL); layerProperties.resize(layersCount); vkEnumerateInstanceLayerProperties(&layersCount, layerProperties); vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL); extensionsProperties = malloc(sizeof(VkExtensionProperties) * extensionCount); vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionsProperties); printf("Supported Layers: \n"); for (size_t i = 0; i < layersCount; i++) { printf("%s\n", layerProperties[i].layerName); } printf("Supported Extensions: \n"); for (size_t i = 0; i < extensionCount; i++) { printf("%s\n", extensionsProperties[i].extensionName); } applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; applicationInfo.pNext = NULL; applicationInfo.pApplicationName = APPLICATION_NAME; applicationInfo.applicationVersion = VK_MAKE_VERSION(0, 1, 0); applicationInfo.pEngineName = ENGINE_NAME; applicationInfo.engineVersion = VK_MAKE_VERSION(0, 1, 0); applicationInfo.apiVersion = VK_API_VERSION_1_2; /* TODO: Wait for package update to 1.3 */ createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pNext = NULL; createInfo.flags = 0U; createInfo.pApplicationInfo = &applicationInfo; createInfo.enabledLayerCount = gEnabledInstanceLayersNames.size(); #ifndef NDEBUG createInfo.ppEnabledLayerNames = gEnabledInstanceLayersNames; #else createInfo.ppEnabledLayerNames = NULL; #endif createInfo.enabledExtensionCount = gEnabledInstanceExtensionsNames.size(); createInfo.ppEnabledExtensionNames = gEnabledInstanceExtensionsNames; VkResult result = vkCreateInstance(&createInfo, NULL, &gVulkanInstance); if (VK_SUCCESS != result) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_INTANCE_INIT_FAILED])); return VULKAN_ERROR_INSTANCE_INIT_FAILED; } return VULKAN_ERROR_NO_ERROR; } static int createSurface() { if (VK_SUCCESS != glfwCreateWindowSurface(gVulkanInstance, getWindowHandle(), NULL, &gSurface)) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_SURFACE_CREATION_FAILED])); return VULKAN_ERROR_SURFACE_CREATION_FAILED; } return VULKAN_ERROR_NO_ERROR; } static int pickPhysicalDevice() { uint32_t physicalDeviceCount = 0U; VkPhysicalDevice* pPhysicalDevices = NULL; /* Get number of existing physical devices */ vkEnumeratePhysicalDevices(gVulkanInstance, &physicalDeviceCount, NULL); if (0 == physicalDeviceCount) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND])); return VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND; } pPhysicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); vkEnumeratePhysicalDevices(gVulkanInstance, &physicalDeviceCount, pPhysicalDevices); /* Check for suitability */ for (size_t physicalDeviceIdx = 0U; physicalDeviceIdx < physicalDeviceCount; ++physicalDeviceIdx) { /* TODO: Check for support */ VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceFeatures deviceFeatures; vkGetPhysicalDeviceProperties(pPhysicalDevices[physicalDeviceIdx], &deviceProperties); vkGetPhysicalDeviceFeatures(pPhysicalDevices[physicalDeviceIdx], &deviceFeatures); /* Expect discrete graphics device type */ if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { gPhysicalDevice = pPhysicalDevices[physicalDeviceIdx]; } } free(pPhysicalDevices); if (VK_NULL_HANDLE == gPhysicalDevice) { /* No suitable device found */ LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_NO_SUITABLE_PHYSICAL_DEVICES])); return VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND; } return VULKAN_ERROR_NO_ERROR; } static int createDevice() { uint32_t queueFamiliesPropertyCount = 0U; ssize_t supportingQueueFamilityIdx = -1; VkQueueFamilyProperties* pQueueFamilyProperties = NULL; VkDeviceCreateInfo deviceCreateInfo = {0}; VkDeviceQueueCreateInfo deviceQueueCreateInfos[1] = {0}; /* TODO: Change when we want more queues */ float* pQueuePriorities = NULL; /* Get information about supported queue families */ vkGetPhysicalDeviceQueueFamilyProperties(gPhysicalDevice, &queueFamiliesPropertyCount, NULL); pQueueFamilyProperties = malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertyCount); vkGetPhysicalDeviceQueueFamilyProperties(gPhysicalDevice, &queueFamiliesPropertyCount, pQueueFamilyProperties); /* Get queue families that support graphics operations AND have most * queues. */ { size_t numberOfQueues = 0; for (size_t familyIdx = 0; familyIdx < queueFamiliesPropertyCount; ++familyIdx) { if (pQueueFamilyProperties[familyIdx].queueFlags & VK_QUEUE_GRAPHICS_BIT) { if (pQueueFamilyProperties[familyIdx].queueCount > numberOfQueues) { supportingQueueFamilityIdx = familyIdx; numberOfQueues = pQueueFamilyProperties[familyIdx].queueCount; } } } } /* This is not magic number ;P. We want to support exact number of required queues flags */ if (0 > supportingQueueFamilityIdx) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_QUEUE_NOT_SUPPORTED])); return VULKAN_ERROR_QUEUE_NOT_SUPPORTED; } gQueueFamilyIndices[0] = supportingQueueFamilityIdx; /* TODO: Change when more families are needed */ pQueuePriorities = malloc(pQueueFamilyProperties[supportingQueueFamilityIdx].queueCount * sizeof(float)); for (size_t i = 0; i < pQueueFamilyProperties[supportingQueueFamilityIdx].queueCount; i++) { pQueuePriorities[i] = 1.0f; /* TODO: When queues have different tasks, change this if needed */ } deviceQueueCreateInfos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; deviceQueueCreateInfos[0].pNext = NULL; deviceQueueCreateInfos[0].flags = 0; deviceQueueCreateInfos[0].queueFamilyIndex = supportingQueueFamilityIdx; deviceQueueCreateInfos[0].queueCount = pQueueFamilyProperties[supportingQueueFamilityIdx].queueCount; deviceQueueCreateInfos[0].pQueuePriorities = pQueuePriorities; free(pQueueFamilyProperties); /* Not needed anymore */ deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.pNext = NULL; deviceCreateInfo.flags = 0U; deviceCreateInfo.queueCreateInfoCount = 1u; /* For now one is enough. TODO: Change when needed. */ deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfos; deviceCreateInfo.enabledLayerCount = 0; deviceCreateInfo.ppEnabledLayerNames = NULL; deviceCreateInfo.enabledExtensionCount = ENABLED_DEVICE_EXTENSIONS_COUNT; deviceCreateInfo.ppEnabledExtensionNames = gEnabledDeviceExtensionsNames; deviceCreateInfo.pEnabledFeatures = NULL; /* TODO: Enable features, when needed */ if (VK_SUCCESS != vkCreateDevice(gPhysicalDevice, &deviceCreateInfo, NULL, &gDevice)) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_FAILED_TO_CREATE_DEVICE])); free(pQueuePriorities); return VULKAN_ERROR_DEVICE_CREATION_FAILED; } free(pQueuePriorities); return VULKAN_ERROR_NO_ERROR; } static int createMemoryAllocator() { VmaVulkanFunctions vulkanFunctions = {0}; vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr; vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr; VmaAllocatorCreateInfo allocatorCreateInfo = {0}; allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2; allocatorCreateInfo.physicalDevice = gPhysicalDevice; allocatorCreateInfo.device = gDevice; allocatorCreateInfo.instance = gVulkanInstance; allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; if (VK_SUCCESS != vmaCreateAllocator(&allocatorCreateInfo, &gAllocator)) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_ERROR_ALLOCATOR_CREATION_FAILED])); return VULKAN_ERROR_ALLOCATOR_CREATION_FAILED; } return VULKAN_ERROR_NO_ERROR; } static int createCommandPools() { VkCommandPoolCreateInfo createInfo; createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; createInfo.pNext = NULL; createInfo.flags = 0U; createInfo.queueFamilyIndex = gQueueFamilyIndices[0]; /* TODO: Change when more families are needed */ if (VK_SUCCESS != vkCreateCommandPool(gDevice, &createInfo, NULL, &gCommandPool)) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_COMMAND_POOL_CREATION_FAILED])); return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED; } return VULKAN_ERROR_NO_ERROR; } static int allocateCommandBuffers() { VkCommandBufferAllocateInfo allocateInfo; /* Allocate memory for command buffers */ gpCommandBuffers = malloc(sizeof(VkCommandBuffer) * SWAP_BUFFER_COUNT); allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocateInfo.pNext = NULL; allocateInfo.commandPool = gCommandPool; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; /* TODO: When needed, add secondary command buffer */ allocateInfo.commandBufferCount = SWAP_BUFFER_COUNT; if (VK_SUCCESS != vkAllocateCommandBuffers(gDevice, &allocateInfo, gpCommandBuffers)) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED])); return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED; } return VULKAN_ERROR_NO_ERROR; } static int createSwapchain() { VkSwapchainCreateInfoKHR createInfo; VkSurfaceCapabilitiesKHR physicalDeviceSurfaceCapabilities; VkBool32 surfaceSupported; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gPhysicalDevice, gSurface, &physicalDeviceSurfaceCapabilities); /* Check if device supports surface for presentation */ vkGetPhysicalDeviceSurfaceSupportKHR(gPhysicalDevice, gQueueFamilyIndices[0], gSurface, &surfaceSupported); createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.flags = 0U; createInfo.surface = gSurface; createInfo.minImageCount = SWAP_BUFFER_COUNT; createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; /* TODO: Check for supported formats */ createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; /* TODO: Check for supported color space */ createInfo.imageExtent = physicalDeviceSurfaceCapabilities.currentExtent; createInfo.imageArrayLayers = 1U; /* For non-stereoscopic-3D applications, this value is 1. */ createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; /* TODO: Probably change later? Dunno */ createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; /* Using only one queue family, so this is ok */ createInfo.queueFamilyIndexCount = 1U; createInfo.pQueueFamilyIndices = gQueueFamilyIndices; createInfo.preTransform = physicalDeviceSurfaceCapabilities.currentTransform; createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; /* TODO: Choose present mode from VkPresentModeKHR */ createInfo.clipped = VK_TRUE; createInfo.oldSwapchain = VK_NULL_HANDLE; if (VK_SUCCESS != vkCreateSwapchainKHR(gDevice, &createInfo, NULL, &gSwapchain)) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_SWAPCHAIN_CREATION_FAILED])); return VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED; } /* Obtain swapchain images */ vkGetSwapchainImagesKHR(gDevice, gSwapchain, &gSwapchainImagesCount, NULL); gpSwapChainImages = malloc(sizeof(VkImage) * gSwapchainImagesCount); vkGetSwapchainImagesKHR(gDevice, gSwapchain, &gSwapchainImagesCount, gpSwapChainImages); return VULKAN_ERROR_NO_ERROR; } static int createSwapchainImageViews() { gpSwapChainImageViews = malloc(sizeof(VkImageView) * gSwapchainImagesCount); for (size_t i = 0; i < gSwapchainImagesCount; i++) { VkImageViewCreateInfo createInfo; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.pNext = NULL; createInfo.flags = 0U; createInfo.image = gpSwapChainImages[i]; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; /* 2D Texture */ createInfo.format = VK_FORMAT_B8G8R8A8_SRGB; createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; createInfo.subresourceRange.baseMipLevel = 0U; createInfo.subresourceRange.levelCount = 1U; createInfo.subresourceRange.baseArrayLayer = 0U; createInfo.subresourceRange.layerCount = 1U; if(VK_SUCCESS != vkCreateImageView(gDevice, &createInfo, NULL, &gpSwapChainImageViews[i])) { LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED])); return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED; } } return VULKAN_ERROR_NO_ERROR; } int initVulkan() { int status = VULKAN_ERROR_NO_ERROR; STATUS_CHECK(createInstance()); #ifndef NDEBUG setupDebugMessenger(); #endif STATUS_CHECK(createSurface()); STATUS_CHECK(pickPhysicalDevice()); STATUS_CHECK(createDevice()); STATUS_CHECK(createMemoryAllocator()); STATUS_CHECK(createCommandPools()); STATUS_CHECK(allocateCommandBuffers()); STATUS_CHECK(createSwapchain()); STATUS_CHECK(createSwapchainImageViews()); return status; } void deinitVulkan() { for (size_t i = 0; i < gSwapchainImagesCount; i++) { vkDestroyImageView(gDevice ,gpSwapChainImageViews[i], NULL); } vkDestroySwapchainKHR(gDevice, gSwapchain, NULL); vkDestroyCommandPool(gDevice, gCommandPool, NULL); vmaDestroyAllocator(gAllocator); vkDestroyDevice(gDevice, NULL); #ifndef NDEBUG DestroyDebugUtilsMessengerEXT(gVulkanInstance, gDebugMessenger, NULL); #endif vkDestroySurfaceKHR(gVulkanInstance, gSurface, NULL); vkDestroyInstance(gVulkanInstance, NULL); }