Table of Contents

Vulkan示例


VulkanMisc头文件

// VulkanMisc.h
#pragma once
 
#include"MathAIO.h"
#include"ToolAIO.h"
 
class Vertex
{
public:
    glm::vec3 m_Position;
 
public:
    Vertex() = default;
    Vertex(const glm::vec3& position) :m_Position(position) {}
 
public:
    ~Vertex() = default;
 
public:
    static VkVertexInputBindingDescription getBindingDescription()
    {
        VkVertexInputBindingDescription bindingDescription = {};
        bindingDescription.binding = 0;
        bindingDescription.stride = sizeof(Vertex);
        bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
 
        return bindingDescription;
    }
 
    static std::vector<VkVertexInputAttributeDescription> getAttributeDescription()
    {
        std::vector<VkVertexInputAttributeDescription> attributeDescription;
 
        attributeDescription.resize(1);
 
        attributeDescription[0].binding = 0;
        attributeDescription[0].location = 0;
        attributeDescription[0].format = VK_FORMAT_R32G32B32_SFLOAT;
        attributeDescription[0].offset = offsetof(Vertex, m_Position);
 
        return attributeDescription;
    }
 
public:
    friend class VulkanManager;
};
 
class QueueFamiliesIndices
{
public:
    int m_GraphicsIndex;
    int m_PresentIndex;
 
public:
    QueueFamiliesIndices()
    {
        m_GraphicsIndex = -1;
        m_PresentIndex = -1;
    }
 
public:
    ~QueueFamiliesIndices() = default;
 
public:
    bool Complete() const
    {
        if (m_GraphicsIndex < 0 || m_PresentIndex < 0)
        {
            return false;
        }
 
        return true;
    }
 
    void Clear()
    {
        m_GraphicsIndex = -1;
        m_PresentIndex = -1;
    }
};
 
class SwapChainDetails
{
public:
    VkSurfaceCapabilitiesKHR m_Capabilities;
    std::vector<VkSurfaceFormatKHR> m_Formats;
    std::vector<VkPresentModeKHR> m_PresentModes;
 
public:
    void Clear()
    {
        m_Formats.clear();
        m_PresentModes.clear();
    }
};
 
class VulkanInfo
{
public:
    VulkanInfo() = default;
    ~VulkanInfo() = default;
 
public:
    QueueFamiliesIndices queueFamiliesIndex;
    SwapChainDetails swapChainDetails;
 
    VkSurfaceFormatKHR swapSurfaceFormat;
    VkPresentModeKHR swapPresentMode;
    VkExtent2D swapChainExtent;
};
 
class VulkanMisc
{
public:
    VulkanMisc() = default;
    ~VulkanMisc() = default;
 
    //Checking Device
public:
    static bool checkQueueFamilies
    (
        const VkPhysicalDevice& device,
        const VkSurfaceKHR& surface,
        QueueFamiliesIndices& queueFamiliesIndex
    )
    {
        uint32_t queueFamiliesCount = 0;
        vkGetPhysicalDeviceQueueFamilyProperties
        (
            device, &queueFamiliesCount, nullptr
        );
 
        std::vector<VkQueueFamilyProperties> queueFamilies(queueFamiliesCount);
        vkGetPhysicalDeviceQueueFamilyProperties
        (
            device, &queueFamiliesCount, queueFamilies.data()
        );
 
        queueFamiliesIndex.Clear();
 
        int i = 0;
        auto pQF = &queueFamilies;
 
        for (auto qIndex = pQF->begin(); qIndex != pQF->end(); ++qIndex)
        {
            if (qIndex->queueCount > 0 && 
                qIndex->queueFlags & VK_QUEUE_GRAPHICS_BIT)
            {
                queueFamiliesIndex.m_GraphicsIndex = i;
            }
 
            VkBool32 presentSupport = false;
            vkGetPhysicalDeviceSurfaceSupportKHR
            (
                device, i, surface, &presentSupport
            );
 
            if (qIndex->queueCount > 0 && presentSupport)
            {
                queueFamiliesIndex.m_PresentIndex = i;
            }
 
            if (queueFamiliesIndex.Complete())
            {
                break;
            }
 
            i += 1;
        }
 
        if (!queueFamiliesIndex.Complete())
        {
            return false;
        }
 
        return true;
    }
 
    static bool checkSupportExtensions
    (
        const VkPhysicalDevice& device,
        const std::vector<const char*>& needExtensionsChar
    )
    {
        uint32_t deviceExtensionsCount;
        vkEnumerateDeviceExtensionProperties
        (
            device, nullptr, &deviceExtensionsCount, nullptr
        );
 
        std::vector<VkExtensionProperties> availableExtensions;
        availableExtensions.resize(deviceExtensionsCount);
 
        vkEnumerateDeviceExtensionProperties
        (
            device, nullptr, &deviceExtensionsCount, availableExtensions.data()
        );
 
        std::unordered_set<std::string> needExtensions;
 
        auto pNEC = &needExtensionsChar;
        for (auto extension = pNEC->begin(); extension != pNEC->end(); ++extension)
        {
            needExtensions.insert(std::string(*extension));
        }
 
        auto pAE = &availableExtensions;
        for (auto extension = pAE->begin(); extension != pAE->end(); ++extension)
        {
            if (needExtensions.count(extension->extensionName))
            {
                needExtensions.erase(extension->extensionName);
            }
        }
 
        if (!needExtensions.empty())
        {
            return false;
        }
 
        return true;
    }
 
    static bool checkSwapchainSupport
    (
        const VkPhysicalDevice& device,
        const VkSurfaceKHR& surface,
        SwapChainDetails& swapChainDetails
    )
    {
        swapChainDetails.Clear();
 
        vkGetPhysicalDeviceSurfaceCapabilitiesKHR
        (
            device, surface, &swapChainDetails.m_Capabilities
        );
 
        //Format
        uint32_t formatCount;
        vkGetPhysicalDeviceSurfaceFormatsKHR
        (
            device, surface, &formatCount, nullptr
        );
 
        if (formatCount)
        {
            swapChainDetails.m_Formats.resize(formatCount);
            vkGetPhysicalDeviceSurfaceFormatsKHR
            (
                device, surface, &formatCount, swapChainDetails.m_Formats.data()
            );
        }
 
        //PresentMode
        uint32_t presentModeCount;
        vkGetPhysicalDeviceSurfacePresentModesKHR
        (
            device, surface, &presentModeCount, nullptr
        );
 
        if (presentModeCount)
        {
            swapChainDetails.m_PresentModes.resize(presentModeCount);
            vkGetPhysicalDeviceSurfacePresentModesKHR
            (
                device, surface, &presentModeCount,
                swapChainDetails.m_PresentModes.data()
            );
        }
 
        return true;
    }
 
    static bool checkDevice
    (
        const VkPhysicalDevice& device,
        const VkSurfaceKHR& surface,
        const std::vector<const char*>& needExtensionsChar
    )
    {
        VkPhysicalDeviceProperties deviceProperties;
        VkPhysicalDeviceFeatures deviceFeatures;
 
        vkGetPhysicalDeviceProperties(device, &deviceProperties);
        vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
 
        QueueFamiliesIndices queueFamiliesIndex;
        checkQueueFamilies(device, surface, queueFamiliesIndex);
 
        if (!queueFamiliesIndex.Complete())
        {
            return false;
        }
 
        if (!checkSupportExtensions(device, needExtensionsChar))
        {
            return false;
        }
 
        SwapChainDetails swapChainDetails;
        checkSwapchainSupport(device, surface, swapChainDetails);
 
        if (swapChainDetails.m_Formats.empty() ||
            swapChainDetails.m_PresentModes.empty())
        {
            return false;
        }
 
        return true;
    }
 
    //Creating Swapchain
public:
    static bool chooseSwapSurfaceFormat
    (
        const std::vector<VkSurfaceFormatKHR>& formats, VkSurfaceFormatKHR& choice
    )
    {
        if (formats.empty())
        {
            return false;
        }
 
        VkFormat expectFormat = VK_FORMAT_B8G8R8A8_UNORM;
        VkColorSpaceKHR expectColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
 
        if (formats.size() == 1 && formats.begin()->format == VK_FORMAT_UNDEFINED)
        {
            choice.format = expectFormat;
            choice.colorSpace = expectColorSpace;
            return true;
        }
 
        for (auto format = formats.begin(); format != formats.end(); ++format)
        {
            if (format->format == expectFormat &&
                format->colorSpace == expectColorSpace)
            {
                choice = *format;
                return true;
            }
        }
 
        Out::Log(pType::WARNING, "No expect Format, Use the default");
        choice = *formats.begin();
 
        return true;
    }
 
    static bool chooseSwapPresentMode
    (
        const std::vector<VkPresentModeKHR>& modes, VkPresentModeKHR& choice
    )
    {
        std::vector<VkPresentModeKHR> expectModes;
 
        expectModes.push_back(VK_PRESENT_MODE_FIFO_KHR);
        expectModes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
        expectModes.push_back(VK_PRESENT_MODE_IMMEDIATE_KHR);
        expectModes.push_back(VK_PRESENT_MODE_FIFO_RELAXED_KHR);
 
        std::unordered_set<VkPresentModeKHR> supportModes;
        for (auto mode = modes.begin(); mode != modes.end(); ++mode)
        {
            supportModes.insert(*mode);
        }
 
        for (auto mode = expectModes.begin(); mode != expectModes.end(); ++mode)
        {
            if (supportModes.count(*mode))
            {
                choice = *mode;
                return true;
            }
        }
 
        Out::Log(pType::ERROR, "No expect PresentMode");
        return false;
    }
 
    static bool chooseSwapExtent
    (
        uint32_t windowWidth, uint32_t windowHeight,
        const VkSurfaceCapabilitiesKHR& capabilities, VkExtent2D& choice
    )
    {
        if (capabilities.currentExtent.width != 
            std::numeric_limits<uint32_t>::max())
        {
            choice = capabilities.currentExtent;
            return true;
        }
 
        choice.width = windowWidth;
        choice.height = windowHeight;
 
        using std::min;
        using std::max;
 
        choice.width = min(choice.width, capabilities.maxImageExtent.width);
        choice.width = max(choice.width, capabilities.minImageExtent.width);
 
        choice.height = min(choice.height, capabilities.maxImageExtent.height);
        choice.height = max(choice.height, capabilities.minImageExtent.height);
 
        return true;
    }
 
    //Create Buffers
public:
    static bool findMemoryType
    (
        uint32_t& result, uint32_t filter,
        const VkMemoryPropertyFlags& properties,
        const VkPhysicalDevice& physicalDevice
    )
    {
        VkPhysicalDeviceMemoryProperties memoryProperties;
        vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
 
        for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i += 1)
        {
            auto U = memoryProperties.memoryTypes[i].propertyFlags & properties;
            if ((filter & (1 << i)) && U == properties)
            {
                result = i;
                return true;
            }
        }
 
        Out::Log(pType::ERROR, "Cant find suit Memory Type");
        return false;
    }
 
public:
    friend class VulkanManager;
};

VulkanManager头文件

// VulkanManager.h
#pragma once
 
#include"VulkanMisc.h"
#include"Shader.h"
#include"Loader.h"
#include"Event.h"
 
class VulkanManager
{
protected:
    //Window Size
    uint32_t m_wWidth;
    uint32_t m_wHeight;
 
protected:
    //Extensions
    std::vector<const char*> m_NeedExtensionsChar;
 
protected:
    //Vertex
    std::vector<Vertex> m_Vertices;
    bool m_VerticesNeedUpdate;
 
protected:
    //Infos
    VulkanInfo m_VulkanInfo;
 
protected:
    //Init GLFW
    GLFWwindow* m_Window;
 
protected:
    //Creating Instance
    VkInstance m_Instance;
 
    //Creating Surface
    VkSurfaceKHR m_Surface;
 
    //Creating Device
    VkPhysicalDevice m_PhysicalDevice;
    VkDevice m_Device;
 
    //Creating Queue
    VkQueue m_GraphicsQueue;
    VkQueue m_PresentQueue;
 
    //Creating Swapchain
    VkSwapchainKHR m_SwapChain;
 
    //Creating Images & Views
    std::vector<VkImage> m_SwapChainImages;
    std::vector<VkImageView> m_SwapChainImageViews;
 
    //Ready to create Pipeline
    //Shader
    VkShaderModule m_ShaderFragment;
    VkShaderModule m_ShaderVertex;
    //Render Pass
    VkRenderPass m_RenderPass;
    //DescriptorSet Layout
    VkDescriptorSetLayout m_DescriptorSetLayout;
 
    //Creating Pipeline
    VkPipelineLayout m_PipelineLayout;
    VkPipeline m_GraphicsPipeline;
 
    //Creating Buffer
    //Frame Buffers
    std::vector<VkFramebuffer> m_SwapChainFrameBuffers;
    //Vertex Buffer
    VkBuffer m_VertexBuffer;
    VkDeviceMemory m_VertexBufferMemory;
    //Uniform Buffers
    std::vector<VkBuffer> m_UniformTransformMatBuffers;
    std::vector<VkDeviceMemory> m_UniformTransformMatBuffersMemory;
 
    //Creating Description
    //Descriptor Pool
    VkDescriptorPool m_DescriptorPool;
    //Descriptor Sets
    std::vector<VkDescriptorSet> m_DescriptorSets;
 
    //Creating Command
    //Command Pool
    VkCommandPool m_CommandPool;
    //Command Buffers
    std::vector<VkCommandBuffer> m_CommandBuffers;
 
    //Creating Semaphores & Fences
    std::vector<VkSemaphore> m_ImageAvailableSemaphores;
    std::vector<VkSemaphore> m_RenderFinishedSemaphores;
    std::vector<VkFence> m_InFlightFences;
    std::vector<VkFence> m_ImagesInFlight;
 
protected:
    //Use for Semaphores & Fences
    const uint32_t FramesInFlightLimit = 2;
    uint32_t m_CurrentFrame;
 
    //UI
protected:
    ImGui_ImplVulkanH_Window m_MainWindowData;
    VkDescriptorPool m_UIPool;
 
public:
    VulkanManager(uint32_t width = 1024, uint32_t height = 768) :
        m_wWidth(width), m_wHeight(height)
    {
        m_NeedExtensionsChar.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
        Event::resetCamera();
        Event::initEventState();
 
        m_CurrentFrame = 0;
 
        m_VerticesNeedUpdate = false;
    }
 
public:
    ~VulkanManager() = default;
 
    //Steps
protected:
    bool createInstance();
    bool createSurface();
 
    bool createPhysicalDevice();
    bool createLogicalDevice();
    bool createQueue();
 
    bool createSwapChain();
    bool createImages();
    bool createImageViews();
 
    bool createShader();
    bool createRenderPass();
    bool createDescriptorSetLayout();
 
    bool createGraphicsPipeline();
 
    bool createFrameBuffers();
    bool createVertexBuffer();
    bool createUniformBuffers();
 
    bool createDescriptorPool();
    bool createDescriptorSets();
 
    bool createCommandPool();
    bool createCommandBuffers();
 
    bool createSemaphores();
 
protected:
    bool Render();
    bool RenderUI();
 
protected:
    bool loadScene();
 
protected:
    bool initGLFW();
    bool initVulkan();
    bool initUI();
 
protected:
    bool destroyGLFW();
    bool destroyVulkan();
    bool destroyUI();
 
public:
    bool Init();
    bool Destroy();
 
public:
    void Loop();
};

VulkanManager源文件

// VulkanManager.cpp
#include"VulkanManager.h"
 
//From class Event
Camera Event::mainCamera;
 
bool Event::shouldQuit;
bool Event::moveState;
 
bool VulkanManager::createInstance()
{
    VkApplicationInfo appInfo = {};
 
    appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    appInfo.pApplicationName = "Vulkan Manager";
    appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
    appInfo.pEngineName = "None";
    appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
    appInfo.apiVersion = VK_API_VERSION_1_0;
 
    uint32_t glfwExtensionCount;
    const char** glfwExtensions;
    glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
 
    VkInstanceCreateInfo createInfo = {};
 
    createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    createInfo.pApplicationInfo = &appInfo;
    createInfo.enabledExtensionCount = glfwExtensionCount;
    createInfo.ppEnabledExtensionNames = glfwExtensions;
    createInfo.enabledLayerCount = 0;
 
    VkResult result = vkCreateInstance(&createInfo, nullptr, &m_Instance);
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "Cant Create Instance");
        return false;
    }
 
    uint32_t vulkanExtensionCount = 0;
    vkEnumerateInstanceExtensionProperties(nullptr, &vulkanExtensionCount, nullptr);
 
    std::vector<VkExtensionProperties> vulkanInstanceExtensions(vulkanExtensionCount);
    vkEnumerateInstanceExtensionProperties
    (
        nullptr, &vulkanExtensionCount, vulkanInstanceExtensions.data()
    );
 
    Out::Log
    (
        pType::MESSAGE,
        "Vulkan Extensions Count: %d", static_cast<int>(vulkanExtensionCount)
    );
 
    return true;
}
 
bool VulkanManager::createSurface()
{
    VkResult result;
    result = glfwCreateWindowSurface(m_Instance, m_Window, nullptr, &m_Surface);
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "GLFW cant create surface");
        return false;
    }
 
    return true;
}
 
bool VulkanManager::createPhysicalDevice()
{
    m_PhysicalDevice = VK_NULL_HANDLE;
 
    uint32_t physicalDeviceCount;
    vkEnumeratePhysicalDevices(m_Instance, &physicalDeviceCount, nullptr);
 
    Out::Log
    (
        pType::MESSAGE,
        "Physical Device count: %d", static_cast<int>(physicalDeviceCount)
    );
 
    if (!physicalDeviceCount)
    {
        return false;
    }
 
    std::vector<VkPhysicalDevice> devices(physicalDeviceCount);
    vkEnumeratePhysicalDevices(m_Instance, &physicalDeviceCount, devices.data());
 
    for (auto device = devices.begin(); device != devices.end(); ++device)
    {
        if (VulkanMisc::checkDevice(*device, m_Surface, m_NeedExtensionsChar))
        {
            m_PhysicalDevice = *device;
            break;
        }
    }
 
    if (m_PhysicalDevice == VK_NULL_HANDLE)
    {
        Out::Log(pType::ERROR, "Cant find suitable physical device");
        return false;
    }
 
    VkPhysicalDeviceProperties physicalDeviceProperties;
    vkGetPhysicalDeviceProperties(m_PhysicalDevice, &physicalDeviceProperties);
    Out::Log(pType::MESSAGE, "Pick device: %s", physicalDeviceProperties.deviceName);
 
    //Get Vulkan Info
    VulkanMisc::checkQueueFamilies(m_PhysicalDevice, m_Surface, m_VulkanInfo.queueFamiliesIndex);
    VulkanMisc::checkSwapchainSupport(m_PhysicalDevice, m_Surface, m_VulkanInfo.swapChainDetails);
 
    VulkanMisc::chooseSwapSurfaceFormat
    (
        m_VulkanInfo.swapChainDetails.m_Formats,
        m_VulkanInfo.swapSurfaceFormat
    );
    VulkanMisc::chooseSwapPresentMode
    (
        m_VulkanInfo.swapChainDetails.m_PresentModes,
        m_VulkanInfo.swapPresentMode
    );
 
    VulkanMisc::chooseSwapExtent
    (
        m_wWidth, m_wHeight,
        m_VulkanInfo.swapChainDetails.m_Capabilities,
        m_VulkanInfo.swapChainExtent
    );
 
    return true;
}
 
bool VulkanManager::createLogicalDevice()
{
    std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
    std::unordered_set<int> queueIndices;
 
    QueueFamiliesIndices queueFamiliesIndex = m_VulkanInfo.queueFamiliesIndex;
 
    queueIndices.insert(queueFamiliesIndex.m_GraphicsIndex);
    queueIndices.insert(queueFamiliesIndex.m_PresentIndex);
 
    float queuePriority = 1.0f;
 
    auto pQI = &queueIndices;
    for (auto createIndex = pQI->begin(); createIndex != pQI->end(); ++createIndex)
    {
        VkDeviceQueueCreateInfo queueCreateInfo = {};
 
        queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
        queueCreateInfo.queueFamilyIndex = *createIndex;
        queueCreateInfo.queueCount = 1;
        queueCreateInfo.pQueuePriorities = &queuePriority;
 
        queueCreateInfos.push_back(queueCreateInfo);
    }
 
    VkPhysicalDeviceFeatures deviceFeatures = {};
 
    VkDeviceCreateInfo deviceCreateInfo = {};
 
    deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
    deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size();
    deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
    deviceCreateInfo.ppEnabledExtensionNames = m_NeedExtensionsChar.data();
    deviceCreateInfo.enabledExtensionCount = (uint32_t)m_NeedExtensionsChar.size();
 
    VkResult result = vkCreateDevice(m_PhysicalDevice, &deviceCreateInfo, nullptr, &m_Device);
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "Create Device Failed");
        return false;
    }
 
    return true;
}
 
bool VulkanManager::createQueue()
{
    QueueFamiliesIndices QFI = m_VulkanInfo.queueFamiliesIndex;
 
    vkGetDeviceQueue(m_Device, QFI.m_GraphicsIndex, 0, &m_GraphicsQueue);
    vkGetDeviceQueue(m_Device, QFI.m_PresentIndex, 0, &m_PresentQueue);
 
    return true;
}
 
bool VulkanManager::createSwapChain()
{
    VkResult result;
 
    QueueFamiliesIndices queueFamiliesIndex = m_VulkanInfo.queueFamiliesIndex;
    SwapChainDetails swapChainDetails = m_VulkanInfo.swapChainDetails;
 
    uint32_t swapChainImagesCount;
    swapChainImagesCount = swapChainDetails.m_Capabilities.minImageCount + 1;
 
    if (swapChainDetails.m_Capabilities.maxImageCount > 0)
    {
        swapChainImagesCount = std::min
        (
            swapChainImagesCount, swapChainDetails.m_Capabilities.maxImageCount
        );
    }
 
    VkSwapchainCreateInfoKHR swapChainCreateInfo = {};
 
    swapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    swapChainCreateInfo.surface = m_Surface;
    swapChainCreateInfo.minImageCount = swapChainImagesCount;
    swapChainCreateInfo.imageFormat = m_VulkanInfo.swapSurfaceFormat.format;
    swapChainCreateInfo.imageColorSpace = m_VulkanInfo.swapSurfaceFormat.colorSpace;
    swapChainCreateInfo.imageExtent = m_VulkanInfo.swapChainExtent;
    swapChainCreateInfo.imageArrayLayers = 1;
    swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 
    if (queueFamiliesIndex.m_GraphicsIndex != queueFamiliesIndex.m_PresentIndex)
    {
        uint32_t indices[2] = {};
        indices[0] = (uint32_t)queueFamiliesIndex.m_GraphicsIndex;
        indices[1] = (uint32_t)queueFamiliesIndex.m_PresentIndex;
 
        swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
        swapChainCreateInfo.queueFamilyIndexCount = 2;
        swapChainCreateInfo.pQueueFamilyIndices = indices;
    }
    else
    {
        swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
        swapChainCreateInfo.queueFamilyIndexCount = 0;
        swapChainCreateInfo.pQueueFamilyIndices = nullptr;
    }
 
    swapChainCreateInfo.preTransform = swapChainDetails.m_Capabilities.currentTransform;
    swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
    swapChainCreateInfo.presentMode = m_VulkanInfo.swapPresentMode;
    swapChainCreateInfo.clipped = VK_TRUE;
    swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE;
 
    result = vkCreateSwapchainKHR(m_Device, &swapChainCreateInfo, nullptr, &m_SwapChain);
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "Create swap chain failed");
        return false;
    }
 
    //make sure Get swap chain images count again
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    Out::Log(pType::MESSAGE, "Swapchain Count: %d", (int)swapChainImagesCount);
 
    return true;
}
 
bool VulkanManager::createImages()
{
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    m_SwapChainImages.resize(swapChainImagesCount);
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, m_SwapChainImages.data());
 
    return true;
}
 
bool VulkanManager::createImageViews()
{
    VkResult result;
 
    SwapChainDetails swapChainDetails = m_VulkanInfo.swapChainDetails;
    VkSurfaceFormatKHR swapSurfaceFormat = m_VulkanInfo.swapSurfaceFormat;
 
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
    m_SwapChainImageViews.resize(swapChainImagesCount);
 
    for (unsigned int i = 0; i < swapChainImagesCount; i += 1)
    {
        VkImageViewCreateInfo viewCreateInfo = {};
 
        viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        viewCreateInfo.image = m_SwapChainImages[i];
        viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
        viewCreateInfo.format = swapSurfaceFormat.format;
        viewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
        viewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
        viewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
        viewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
        viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        viewCreateInfo.subresourceRange.baseMipLevel = 0;
        viewCreateInfo.subresourceRange.levelCount = 1;
        viewCreateInfo.subresourceRange.baseArrayLayer = 0;
        viewCreateInfo.subresourceRange.layerCount = 1;
 
        result = vkCreateImageView
        (
            m_Device, &viewCreateInfo, nullptr, &m_SwapChainImageViews[i]
        );
 
        if (result != VK_SUCCESS)
        {
            Out::Log(pType::ERROR, "Cant create views for image in swap chain");
            return false;
        }
    }
 
    return true;
}
 
bool VulkanManager::createShader()
{
    VkResult result;
 
    Shader fragmentShader("./Shader/frag.spv");
    Shader vertexShader("./Shader/vert.spv");
 
    VkShaderModuleCreateInfo shaderCreateInfo = {};
    shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
 
    shaderCreateInfo.codeSize = fragmentShader.m_ShaderCode.size();
    shaderCreateInfo.pCode = reinterpret_cast<const uint32_t*>(fragmentShader.m_ShaderCode.data());
    result = vkCreateShaderModule(m_Device, &shaderCreateInfo, nullptr, &m_ShaderFragment);
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "Load Shader Failed");
        return false;
    }
 
    shaderCreateInfo.codeSize = vertexShader.m_ShaderCode.size();
    shaderCreateInfo.pCode = reinterpret_cast<const uint32_t*>(vertexShader.m_ShaderCode.data());
    result = vkCreateShaderModule(m_Device, &shaderCreateInfo, nullptr, &m_ShaderVertex);
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "Load Shader Failed");
        return false;
    }
 
    return true;
}
 
bool VulkanManager::createRenderPass()
{
    SwapChainDetails swapChainDetails = m_VulkanInfo.swapChainDetails;
    VkSurfaceFormatKHR swapSurfaceFormat = m_VulkanInfo.swapSurfaceFormat;
 
    VkAttachmentDescription colorAttachment = {};
    colorAttachment.format = swapSurfaceFormat.format;
    colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
    colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
    colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
 
    VkAttachmentReference colorAttachmentReference = {};
    colorAttachmentReference.attachment = 0;
    colorAttachmentReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 
    VkSubpassDescription subPass = {};
    subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
    subPass.colorAttachmentCount = 1;
    subPass.pColorAttachments = &colorAttachmentReference;
 
    VkSubpassDependency subpassDependency = {};
    subpassDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    subpassDependency.dstSubpass = 0;
    subpassDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    subpassDependency.srcAccessMask = 0;
    subpassDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    subpassDependency.dstAccessMask = (VkFlags)VK_NULL_HANDLE;
    subpassDependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
    subpassDependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
 
    VkRenderPassCreateInfo renderPassCreateInfo = {};
    renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
    renderPassCreateInfo.attachmentCount = 1;
    renderPassCreateInfo.pAttachments = &colorAttachment;
    renderPassCreateInfo.subpassCount = 1;
    renderPassCreateInfo.pSubpasses = &subPass;
    renderPassCreateInfo.pDependencies = &subpassDependency;
 
    VkResult result = vkCreateRenderPass(m_Device, &renderPassCreateInfo, nullptr, &m_RenderPass);
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "Create Render Pass Failed");
        return false;
    }
 
    return true;
}
 
bool VulkanManager::createDescriptorSetLayout()
{
    VkDescriptorSetLayoutBinding UBOLayoutBinding = {};
    UBOLayoutBinding.binding = 0;
    UBOLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
    UBOLayoutBinding.descriptorCount = 1;
    UBOLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
    UBOLayoutBinding.pImmutableSamplers = nullptr;
 
    VkDescriptorSetLayoutCreateInfo layoutCreateInfo = {};
    layoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
    layoutCreateInfo.bindingCount = 1;
    layoutCreateInfo.pBindings = &UBOLayoutBinding;
 
    vkCreateDescriptorSetLayout(m_Device, &layoutCreateInfo, nullptr, &m_DescriptorSetLayout);
 
    return true;
}
 
bool VulkanManager::createGraphicsPipeline()
{
    SwapChainDetails swapChainDetails = m_VulkanInfo.swapChainDetails;
    VkExtent2D swapChainExtent = m_VulkanInfo.swapChainExtent;
 
    VkPipelineShaderStageCreateInfo vertexShaderStageCreateInfo = {};
    vertexShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    vertexShaderStageCreateInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
    vertexShaderStageCreateInfo.module = m_ShaderVertex;
    vertexShaderStageCreateInfo.pName = "main";
 
    VkPipelineShaderStageCreateInfo fragmentShaderStageCreateInfo = {};
    fragmentShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    fragmentShaderStageCreateInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
    fragmentShaderStageCreateInfo.module = m_ShaderFragment;
    fragmentShaderStageCreateInfo.pName = "main";
 
    VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2] = {};
    shaderStageCreateInfos[0] = vertexShaderStageCreateInfo;
    shaderStageCreateInfos[1] = fragmentShaderStageCreateInfo;
 
    VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {};
    vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
 
    auto bindingDescription = Vertex::getBindingDescription();
    auto attributeDescription = Vertex::getAttributeDescription();
 
    vertexInputStateCreateInfo.vertexBindingDescriptionCount = 1;
    vertexInputStateCreateInfo.pVertexBindingDescriptions = &bindingDescription;
 
    vertexInputStateCreateInfo.vertexAttributeDescriptionCount = attributeDescription.size();
    vertexInputStateCreateInfo.pVertexAttributeDescriptions = attributeDescription.data();
 
    VkPipelineInputAssemblyStateCreateInfo vertexInputAssemblyCreateInfo = {};
    vertexInputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
    vertexInputAssemblyCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
    vertexInputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE;
 
    VkViewport viewport = {};
    viewport.x = 0.0f;
    viewport.y = 0.0f;
    viewport.width = (float)swapChainExtent.width;
    viewport.height = (float)swapChainExtent.height;
    viewport.minDepth = 0.0f;
    viewport.maxDepth = 1.0f;
 
    VkRect2D scissor = {};
    scissor.offset.x = 0;
    scissor.offset.y = 0;
    scissor.extent = swapChainExtent;
 
    VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {};
    viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
    viewportStateCreateInfo.viewportCount = 1;
    viewportStateCreateInfo.pViewports = &viewport;
    viewportStateCreateInfo.scissorCount = 1;
    viewportStateCreateInfo.pScissors = &scissor;
 
    VkPipelineRasterizationStateCreateInfo resterizationStateCreateInfo = {};
    resterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
    resterizationStateCreateInfo.depthClampEnable = VK_FALSE;
    resterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE;
    resterizationStateCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
    resterizationStateCreateInfo.lineWidth = 1.0f;
    resterizationStateCreateInfo.cullMode = VK_CULL_MODE_NONE;
    resterizationStateCreateInfo.frontFace = VK_FRONT_FACE_CLOCKWISE;
    resterizationStateCreateInfo.depthBiasEnable = VK_FALSE;
    resterizationStateCreateInfo.depthBiasConstantFactor = 0.0f;
    resterizationStateCreateInfo.depthBiasClamp = 0.0f;
    resterizationStateCreateInfo.depthBiasSlopeFactor = 0.0f;
 
    VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {};
    multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
    multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE;
    multisampleStateCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
    multisampleStateCreateInfo.minSampleShading = 1.0f;
    multisampleStateCreateInfo.pSampleMask = nullptr;
    multisampleStateCreateInfo.alphaToCoverageEnable = VK_FALSE;
    multisampleStateCreateInfo.alphaToOneEnable = VK_FALSE;
 
    VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
    colorBlendAttachment.colorWriteMask = (VkFlags)VK_NULL_HANDLE;
 
    colorBlendAttachment.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
    colorBlendAttachment.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
    colorBlendAttachment.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
    colorBlendAttachment.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
 
    colorBlendAttachment.blendEnable = VK_FALSE;
    colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
    colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
    colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
    colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
    colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
    colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
 
    VkPipelineColorBlendStateCreateInfo colorBlendCreateInfo = {};
    colorBlendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    colorBlendCreateInfo.logicOpEnable = VK_FALSE;
    colorBlendCreateInfo.logicOp = VK_LOGIC_OP_COPY;
    colorBlendCreateInfo.attachmentCount = 1;
    colorBlendCreateInfo.pAttachments = &colorBlendAttachment;
 
    for (unsigned int i = 0; i <= 3; i += 1)
    {
        colorBlendCreateInfo.blendConstants[i] = 0.0f;
    }
 
    VkPipelineLayoutCreateInfo layoutCreateInfo = {};
    layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
    layoutCreateInfo.setLayoutCount = 1;
    layoutCreateInfo.pSetLayouts = &m_DescriptorSetLayout;
    layoutCreateInfo.pushConstantRangeCount = 0;
    layoutCreateInfo.pPushConstantRanges = nullptr;
 
    VkResult result = vkCreatePipelineLayout(m_Device, &layoutCreateInfo, nullptr, &m_PipelineLayout);
 
    VkGraphicsPipelineCreateInfo pipelineCreateInfo = {};
    pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    pipelineCreateInfo.stageCount = 2;
    pipelineCreateInfo.pStages = shaderStageCreateInfos;
    pipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo;
    pipelineCreateInfo.pInputAssemblyState = &vertexInputAssemblyCreateInfo;
    pipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
    pipelineCreateInfo.pRasterizationState = &resterizationStateCreateInfo;
    pipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo;
    pipelineCreateInfo.pDepthStencilState = nullptr;
    pipelineCreateInfo.pColorBlendState = &colorBlendCreateInfo;
    pipelineCreateInfo.pDynamicState = nullptr;
    pipelineCreateInfo.layout = m_PipelineLayout;
    pipelineCreateInfo.renderPass = m_RenderPass;
    pipelineCreateInfo.subpass = 0;
    pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
    pipelineCreateInfo.basePipelineIndex = -1;
 
    result = vkCreateGraphicsPipelines
    (
        m_Device, VK_NULL_HANDLE, 1, &pipelineCreateInfo, nullptr, &m_GraphicsPipeline
    );
 
    if (result != VK_SUCCESS)
    {
        Out::Log(pType::ERROR, "Create Pipeline Failed");
        return false;
    }
 
    return true;
}
 
bool VulkanManager::createFrameBuffers()
{
    VkResult result;
 
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
    m_SwapChainFrameBuffers.resize(swapChainImagesCount);
 
    for (unsigned int i = 0; i < swapChainImagesCount; i += 1)
    {
        VkImageView attachments[1] = {};
 
        attachments[0] = m_SwapChainImageViews[i];
 
        VkFramebufferCreateInfo frameBufferCreateInfo = {};
        frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
        frameBufferCreateInfo.renderPass = m_RenderPass;
        frameBufferCreateInfo.attachmentCount = 1;
        frameBufferCreateInfo.pAttachments = attachments;
        frameBufferCreateInfo.width = m_VulkanInfo.swapChainExtent.width;
        frameBufferCreateInfo.height = m_VulkanInfo.swapChainExtent.height;
        frameBufferCreateInfo.layers = 1;
 
        result = vkCreateFramebuffer
        (
            m_Device, &frameBufferCreateInfo, nullptr, &m_SwapChainFrameBuffers[i]
        );
 
        if (result != VK_SUCCESS)
        {
            Out::Log(pType::ERROR, "Create Frame Buffer Failed");
            return false;
        }
    }
 
    return true;
}
 
bool VulkanManager::createVertexBuffer()
{
    VkResult result;
 
    VkBufferCreateInfo vertexBufferCreateInfo = {};
    vertexBufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    vertexBufferCreateInfo.size = sizeof(Vertex) * m_Vertices.size();
    vertexBufferCreateInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
    vertexBufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
    result = vkCreateBuffer(m_Device, &vertexBufferCreateInfo, nullptr, &m_VertexBuffer);
 
    Out::Log
    (
        pType::MESSAGE,
        "Create Vertex buffer with size of %d", (int)vertexBufferCreateInfo.size
    );
 
    VkMemoryRequirements memoryRequitments;
    vkGetBufferMemoryRequirements(m_Device, m_VertexBuffer, &memoryRequitments);
 
    VkMemoryAllocateInfo allocMemoryInfo = {};
    allocMemoryInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    allocMemoryInfo.allocationSize = memoryRequitments.size;
 
    VulkanMisc::findMemoryType
    (
        allocMemoryInfo.memoryTypeIndex, memoryRequitments.memoryTypeBits,
        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
        m_PhysicalDevice
    );
 
    result = vkAllocateMemory(m_Device, &allocMemoryInfo, nullptr, &m_VertexBufferMemory);
 
    vkBindBufferMemory(m_Device, m_VertexBuffer, m_VertexBufferMemory, 0);
 
    void* vertexData;
    vkMapMemory(m_Device, m_VertexBufferMemory, 0, vertexBufferCreateInfo.size, 0, &vertexData);
 
    memcpy(vertexData, m_Vertices.data(), (size_t)vertexBufferCreateInfo.size);
    vkUnmapMemory(m_Device, m_VertexBufferMemory);
 
    return true;
}
 
bool VulkanManager::createUniformBuffers()
{
    VkDeviceSize bufferSize = sizeof(UniformMVP);
 
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    m_UniformTransformMatBuffers.resize(swapChainImagesCount);
    m_UniformTransformMatBuffersMemory.resize(swapChainImagesCount);
 
    VkBufferUsageFlags bufferUsage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
 
    VkMemoryPropertyFlags memProperties = (VkMemoryPropertyFlags)VK_NULL_HANDLE;
    memProperties |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    memProperties |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
 
    VkBufferCreateInfo bufferCreateInfo = {};
    bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    bufferCreateInfo.size = sizeof(UniformMVP);
    bufferCreateInfo.usage = bufferUsage;
    bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
    for (size_t i = 0; i < swapChainImagesCount; i += 1)
    {
        vkCreateBuffer(m_Device, &bufferCreateInfo, nullptr, &m_UniformTransformMatBuffers[i]);
 
        VkMemoryRequirements memRequirements;
        vkGetBufferMemoryRequirements(m_Device, m_UniformTransformMatBuffers[i], &memRequirements);
 
        VkMemoryAllocateInfo memoryAllocInfo = {};
        memoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
        memoryAllocInfo.allocationSize = memRequirements.size;
 
        VulkanMisc::findMemoryType
        (
            memoryAllocInfo.memoryTypeIndex, memRequirements.memoryTypeBits,
            memProperties, m_PhysicalDevice
        );
 
        vkAllocateMemory
        (
            m_Device, &memoryAllocInfo, nullptr,
            &m_UniformTransformMatBuffersMemory[i]
        );
 
        vkBindBufferMemory
        (
            m_Device, m_UniformTransformMatBuffers[i],
            m_UniformTransformMatBuffersMemory[i], 0
        );
    }
 
    return true;
}
 
bool VulkanManager::createDescriptorPool()
{
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    VkDescriptorPoolSize descriptorPoolSize = {};
    descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
    descriptorPoolSize.descriptorCount = swapChainImagesCount;
 
    VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {};
    descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    descriptorPoolCreateInfo.poolSizeCount = 1;
    descriptorPoolCreateInfo.pPoolSizes = &descriptorPoolSize;
    descriptorPoolCreateInfo.maxSets = swapChainImagesCount;
 
    vkCreateDescriptorPool(m_Device, &descriptorPoolCreateInfo, nullptr, &m_DescriptorPool);
 
    return true;
}
 
bool VulkanManager::createDescriptorSets()
{
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    std::vector<VkDescriptorSetLayout> layouts(swapChainImagesCount, m_DescriptorSetLayout);
 
    VkDescriptorSetAllocateInfo descriptorSetAllocInfo = {};
    descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
    descriptorSetAllocInfo.descriptorPool = m_DescriptorPool;
    descriptorSetAllocInfo.descriptorSetCount = swapChainImagesCount;
    descriptorSetAllocInfo.pSetLayouts = layouts.data();
 
    m_DescriptorSets.resize(swapChainImagesCount);
 
    vkAllocateDescriptorSets(m_Device, &descriptorSetAllocInfo, m_DescriptorSets.data());
 
    for (size_t i = 0; i < swapChainImagesCount; i += 1)
    {
        VkDescriptorBufferInfo bufferInfo = {};
        bufferInfo.buffer = m_UniformTransformMatBuffers[i];
        bufferInfo.offset = 0;
        bufferInfo.range = sizeof(UniformMVP);
 
        VkWriteDescriptorSet descriptorWrite = {};
        descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
        descriptorWrite.dstSet = m_DescriptorSets[i];
        descriptorWrite.dstBinding = 0;
        descriptorWrite.dstArrayElement = 0;
        descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        descriptorWrite.descriptorCount = 1;
        descriptorWrite.pBufferInfo = &bufferInfo;
        descriptorWrite.pImageInfo = nullptr;
        descriptorWrite.pTexelBufferView = nullptr;
 
        vkUpdateDescriptorSets(m_Device, 1, &descriptorWrite, 0, nullptr);
    }
 
    return true;
}
 
bool VulkanManager::createCommandPool()
{
    VkResult result;
 
    VkCommandPoolCreateInfo commandPoolCreateInfo = {};
    commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
    commandPoolCreateInfo.queueFamilyIndex = m_VulkanInfo.queueFamiliesIndex.m_GraphicsIndex;
    commandPoolCreateInfo.flags = 0;
 
    result = vkCreateCommandPool(m_Device, &commandPoolCreateInfo, nullptr, &m_CommandPool);
 
    return true;
}
 
bool VulkanManager::createCommandBuffers()
{
    VkResult result;
 
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    m_CommandBuffers.resize(swapChainImagesCount);
 
    VkCommandBufferAllocateInfo commandBufferAllocInfo = {};
 
    commandBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    commandBufferAllocInfo.commandPool = m_CommandPool;
    commandBufferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    commandBufferAllocInfo.commandBufferCount = swapChainImagesCount;
 
    result = vkAllocateCommandBuffers(m_Device, &commandBufferAllocInfo, m_CommandBuffers.data());
 
    for (unsigned int i = 0; i < swapChainImagesCount; i += 1)
    {
        VkCommandBufferBeginInfo beginInfo = {};
        beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
        beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
        beginInfo.pInheritanceInfo = nullptr;
 
        result = vkBeginCommandBuffer(m_CommandBuffers[i], &beginInfo);
 
        VkRenderPassBeginInfo renderPassBeginInfo = {};
        renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
        renderPassBeginInfo.renderPass = m_RenderPass;
        renderPassBeginInfo.framebuffer = m_SwapChainFrameBuffers[i];
        renderPassBeginInfo.renderArea.offset.x = 0;
        renderPassBeginInfo.renderArea.offset.y = 0;
        renderPassBeginInfo.renderArea.extent = m_VulkanInfo.swapChainExtent;
 
        VkClearValue clearColor = { 0.3f,0.1f,0.1f,1.0f };
        renderPassBeginInfo.clearValueCount = 1;
        renderPassBeginInfo.pClearValues = &clearColor;
 
        vkCmdBeginRenderPass(m_CommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
 
        vkCmdBindPipeline(m_CommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, m_GraphicsPipeline);
 
        VkBuffer vertexBuffers[] = { m_VertexBuffer };
        VkDeviceSize offsets[] = { 0 };
        vkCmdBindVertexBuffers(m_CommandBuffers[i], 0, 1, vertexBuffers, offsets);
 
        vkCmdBindDescriptorSets
        (
            m_CommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS,
            m_PipelineLayout, 0, 1, &m_DescriptorSets[i], 0, nullptr
        );
 
        vkCmdDraw(m_CommandBuffers[i], (uint32_t)m_Vertices.size(), 1, 0, 0);
 
        vkCmdEndRenderPass(m_CommandBuffers[i]);
 
        result = vkEndCommandBuffer(m_CommandBuffers[i]);
 
        if (result != VK_SUCCESS)
        {
            Out::Log(pType::ERROR, "Record Command Failed");
            return false;
        }
    }
 
    return true;
}
 
bool VulkanManager::createSemaphores()
{
    VkResult result;
 
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    m_ImageAvailableSemaphores.resize(FramesInFlightLimit);
    m_RenderFinishedSemaphores.resize(FramesInFlightLimit);
 
    m_InFlightFences.resize(FramesInFlightLimit);
    m_ImagesInFlight.resize(swapChainImagesCount, VK_NULL_HANDLE);
 
    VkSemaphoreCreateInfo semaphoreCreateInfo = {};
    semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
 
    VkFenceCreateInfo fenceCreateInfo = {};
    fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
 
    for (unsigned int i = 0; i < FramesInFlightLimit; i += 1)
    {
        result = vkCreateSemaphore
        (
            m_Device, &semaphoreCreateInfo, nullptr, &m_ImageAvailableSemaphores[i]
        );
        result = vkCreateSemaphore
        (
            m_Device, &semaphoreCreateInfo, nullptr, &m_RenderFinishedSemaphores[i]
        );
 
        result = vkCreateFence(m_Device, &fenceCreateInfo, nullptr, &m_InFlightFences[i]);
    }
 
    return true;
}
 
bool VulkanManager::Render()
{
    uint64_t max64 = std::numeric_limits<uint64_t>::max();
    vkWaitForFences(m_Device, 1, &m_InFlightFences[m_CurrentFrame], VK_TRUE, max64);
 
    uint32_t imageIndex;
    vkAcquireNextImageKHR
    (
        m_Device, m_SwapChain, max64, m_ImageAvailableSemaphores[m_CurrentFrame],
        VK_NULL_HANDLE, &imageIndex
    );
 
    UniformMVP mvp;
 
    auto swapChainExtent = m_VulkanInfo.swapChainExtent;
    float r = (float)swapChainExtent.width / swapChainExtent.height;
 
    if (Event::mainCamera.updateMVP(r, mvp))
    {
        void* uniformData;
        vkMapMemory
        (
            m_Device, m_UniformTransformMatBuffersMemory[imageIndex], 0,
            sizeof(UniformMVP), 0, &uniformData
        );
 
        memcpy(uniformData, &mvp, sizeof(UniformMVP));
        vkUnmapMemory(m_Device, m_UniformTransformMatBuffersMemory[imageIndex]);
    }
 
    if (m_ImagesInFlight[imageIndex] != VK_NULL_HANDLE)
    {
        vkWaitForFences(m_Device, 1, &m_ImagesInFlight[imageIndex], VK_TRUE, max64);
    }
    m_ImagesInFlight[imageIndex] = m_InFlightFences[m_CurrentFrame];
 
    VkSubmitInfo submitInfo = {};
    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
 
    VkSemaphore waitSemaphores[1] = {};
    waitSemaphores[0] = m_ImageAvailableSemaphores[m_CurrentFrame];
 
    VkPipelineStageFlags waitStages[1] = {};
    waitStages[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 
    submitInfo.waitSemaphoreCount = 1;
    submitInfo.pWaitSemaphores = waitSemaphores;
    submitInfo.pWaitDstStageMask = waitStages;
 
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &m_CommandBuffers[imageIndex];
 
    VkSemaphore signalSemaphores[1] = {};
    signalSemaphores[0] = m_RenderFinishedSemaphores[m_CurrentFrame];
 
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = signalSemaphores;
 
    vkResetFences(m_Device, 1, &m_InFlightFences[m_CurrentFrame]);
 
    VkResult result = vkQueueSubmit(m_GraphicsQueue, 1, &submitInfo, m_InFlightFences[m_CurrentFrame]);
 
    VkPresentInfoKHR presentInfo = {};
    presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
    presentInfo.waitSemaphoreCount = 1;
    presentInfo.pWaitSemaphores = signalSemaphores;
 
    VkSwapchainKHR swapChains[1] = {};
    swapChains[0] = m_SwapChain;
 
    presentInfo.swapchainCount = 1;
    presentInfo.pSwapchains = swapChains;
    presentInfo.pImageIndices = &imageIndex;
    presentInfo.pResults = &result;
 
    vkQueuePresentKHR(m_PresentQueue, &presentInfo);
 
    vkQueueWaitIdle(m_PresentQueue);
 
    m_CurrentFrame = (m_CurrentFrame + 1) % FramesInFlightLimit;
 
    return true;
}
 
bool VulkanManager::RenderUI()
{
    ImGui_ImplVulkan_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();
 
    ImGui::ShowDemoWindow();
 
    ImGui::Render();
 
    ImDrawData* drawData = ImGui::GetDrawData();
 
    auto wd = &m_MainWindowData;
 
    VkSemaphore image_acquired_semaphore  = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
    VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
    vkAcquireNextImageKHR(m_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex);
 
 
    ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex];
    {
        vkWaitForFences(m_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX);
 
        vkResetFences(m_Device, 1, &fd->Fence);
    }
    {
        vkResetCommandPool(m_Device, fd->CommandPool, 0);
        VkCommandBufferBeginInfo info = {};
        info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
        info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
        vkBeginCommandBuffer(fd->CommandBuffer, &info);
    }
    {
        VkRenderPassBeginInfo info = {};
        info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
        info.renderPass = wd->RenderPass;
        info.framebuffer = fd->Framebuffer;
        info.renderArea.extent.width = wd->Width;
        info.renderArea.extent.height = wd->Height;
        info.clearValueCount = 1;
        info.pClearValues = &wd->ClearValue;
        vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
    }
 
    ImGui_ImplVulkan_RenderDrawData(drawData, fd->CommandBuffer);
 
    vkCmdEndRenderPass(fd->CommandBuffer);
        VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
        VkSubmitInfo info = {};
        info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
        info.waitSemaphoreCount = 1;
        info.pWaitSemaphores = &image_acquired_semaphore;
        info.pWaitDstStageMask = &wait_stage;
        info.commandBufferCount = 1;
        info.pCommandBuffers = &fd->CommandBuffer;
        info.signalSemaphoreCount = 1;
        info.pSignalSemaphores = &render_complete_semaphore;
 
        vkEndCommandBuffer(fd->CommandBuffer);
 
        vkQueueSubmit(m_GraphicsQueue, 1, &info, fd->Fence);
 
        {
            VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
            VkPresentInfoKHR info = {};
            info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
            info.waitSemaphoreCount = 1;
            info.pWaitSemaphores = &render_complete_semaphore;
            info.swapchainCount = 1;
            info.pSwapchains = &wd->Swapchain;
            info.pImageIndices = &wd->FrameIndex;
            VkResult err = vkQueuePresentKHR(m_GraphicsQueue, &info);
 
 
            wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount;
        }
 
    return true;
}
 
bool VulkanManager::loadScene()
{
    m_Vertices.push_back(Vertex(Convert(Point( 5, -5, 0))));
    m_Vertices.push_back(Vertex(Convert(Point( 0,  5, 0))));
    m_Vertices.push_back(Vertex(Convert(Point(-5, -5, 0))));
 
    return true;
}
 
bool VulkanManager::initGLFW()
{
    if (!glfwInit())
    {
        Out::Log(pType::ERROR, "GLFW Init Failed");
 
        return false;
    }
 
    //No OpenGL API
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
 
    m_Window = glfwCreateWindow(m_wWidth, m_wHeight, "reEngine", nullptr, nullptr);
 
    if (!m_Window)
    {
        Out::Log(pType::ERROR, "GLFW cant create window");
        return false;
    }
 
    glfwSetKeyCallback(m_Window, Event::glfwKeyCallback);
    glfwSetCursorPosCallback(m_Window, Event::glfwCursorPositionCallback);
    glfwSetMouseButtonCallback(m_Window, Event::glfwMouseButtonCallback);
 
    glfwSetInputMode(m_Window, GLFW_STICKY_KEYS, GLFW_TRUE);
    glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
 
    Out::Log(pType::MESSAGE, "Init GLFW Done");
    return true;
}
 
bool VulkanManager::initVulkan()
{
    createInstance();
    createSurface();
 
    createPhysicalDevice();
    createLogicalDevice();
    createQueue();
 
    createSwapChain();
    createImages();
    createImageViews();
 
    createShader();
    createRenderPass();
    createDescriptorSetLayout();
 
    createGraphicsPipeline();
 
    createFrameBuffers();
    createVertexBuffer();
    createUniformBuffers();
 
    createDescriptorPool();
    createDescriptorSets();
 
    createCommandPool();
    createCommandBuffers();
 
    createSemaphores();
 
    return true;
}
 
bool VulkanManager::initUI()
{
    VkDescriptorPoolSize poolSizes[] =
    {
        { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
        { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
        { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
        { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
        { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
        { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
        { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
        { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
        { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
        { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
        { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 }
    };
    VkDescriptorPoolCreateInfo poolInfo = {};
    poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
    poolInfo.maxSets = 1000 * IM_ARRAYSIZE(poolSizes);
    poolInfo.poolSizeCount = (uint32_t)IM_ARRAYSIZE(poolSizes);
    poolInfo.pPoolSizes = poolSizes;
    vkCreateDescriptorPool(m_Device, &poolInfo, nullptr, &m_UIPool);
 
    m_MainWindowData.Surface = m_Surface;
    m_MainWindowData.SurfaceFormat = m_VulkanInfo.swapSurfaceFormat;
    m_MainWindowData.PresentMode = m_VulkanInfo.swapPresentMode;
 
    ImGui_ImplVulkanH_CreateOrResizeWindow
    (
        m_Instance, m_PhysicalDevice, m_Device, &m_MainWindowData,
        m_VulkanInfo.queueFamiliesIndex.m_GraphicsIndex, nullptr,
        m_wWidth, m_wHeight, 2
    );
 
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGui::StyleColorsDark();
 
    ImGui_ImplGlfw_InitForVulkan(m_Window, true);
 
    ImGui_ImplVulkan_InitInfo initInfo = {};
    initInfo.Instance = m_Instance;
    initInfo.PhysicalDevice = m_PhysicalDevice;
    initInfo.Device = m_Device;
    initInfo.QueueFamily = m_VulkanInfo.queueFamiliesIndex.m_GraphicsIndex;
    initInfo.Queue = m_GraphicsQueue;
    initInfo.PipelineCache = VK_NULL_HANDLE;
    initInfo.DescriptorPool = m_UIPool;
    initInfo.Allocator = nullptr;
    initInfo.MinImageCount = 2;
    initInfo.ImageCount = m_MainWindowData.ImageCount;
    initInfo.CheckVkResultFn = nullptr;
    ImGui_ImplVulkan_Init(&initInfo, m_MainWindowData.RenderPass);
 
    auto wd = &m_MainWindowData;
    VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
    VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer;
 
    vkResetCommandPool(m_Device, command_pool, 0);
 
    VkCommandBufferBeginInfo begin_info = {};
    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    vkBeginCommandBuffer(command_buffer, &begin_info);
 
 
    ImGui_ImplVulkan_CreateFontsTexture(command_buffer);
 
    VkSubmitInfo end_info = {};
    end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    end_info.commandBufferCount = 1;
    end_info.pCommandBuffers = &command_buffer;
    vkEndCommandBuffer(command_buffer);
 
    vkQueueSubmit(m_GraphicsQueue, 1, &end_info, VK_NULL_HANDLE);
 
 
    vkDeviceWaitIdle(m_Device);
 
    ImGui_ImplVulkan_DestroyFontUploadObjects();
 
    return true;
}
 
bool VulkanManager::destroyGLFW()
{
    if (m_Window)
    {
        glfwDestroyWindow(m_Window);
    }
    glfwTerminate();
 
    Out::Log(pType::MESSAGE, "Cleaned GLFW");
 
    return true;
}
 
bool VulkanManager::destroyVulkan()
{
    uint32_t swapChainImagesCount;
    vkGetSwapchainImagesKHR(m_Device, m_SwapChain, &swapChainImagesCount, nullptr);
 
    for (auto i = m_SwapChainFrameBuffers.begin(); i != m_SwapChainFrameBuffers.end(); ++i)
    {
        vkDestroyFramebuffer(m_Device, *i, nullptr);
    }
    vkFreeCommandBuffers
    (
        m_Device, m_CommandPool,
        static_cast<uint32_t>(m_CommandBuffers.size()), m_CommandBuffers.data()
    );
 
    vkDestroyPipeline(m_Device, m_GraphicsPipeline, nullptr);
    vkDestroyPipelineLayout(m_Device, m_PipelineLayout, nullptr);
    vkDestroyRenderPass(m_Device, m_RenderPass, nullptr);
 
    for (auto i = m_SwapChainImageViews.begin(); i != m_SwapChainImageViews.end(); ++i)
    {
        vkDestroyImageView(m_Device, *i, nullptr);
    }
 
    vkDestroySwapchainKHR(m_Device, m_SwapChain, nullptr);
 
    for (size_t i = 0; i < swapChainImagesCount; i += 1)
    {
        vkDestroyBuffer(m_Device, m_UniformTransformMatBuffers[i], nullptr);
        vkFreeMemory(m_Device, m_UniformTransformMatBuffersMemory[i], nullptr);
    }
 
    vkDestroyDescriptorPool(m_Device, m_DescriptorPool, nullptr);
 
    vkDestroyDescriptorSetLayout(m_Device, m_DescriptorSetLayout, nullptr);
 
    vkDestroyBuffer(m_Device, m_VertexBuffer, nullptr);
    vkFreeMemory(m_Device, m_VertexBufferMemory, nullptr);
 
    vkDestroyShaderModule(m_Device, m_ShaderFragment, nullptr);
    vkDestroyShaderModule(m_Device, m_ShaderVertex, nullptr);
 
    for (unsigned int i = 0; i < FramesInFlightLimit; i += 1)
    {
        vkDestroySemaphore(m_Device, m_ImageAvailableSemaphores[i], nullptr);
        vkDestroySemaphore(m_Device, m_RenderFinishedSemaphores[i], nullptr);
 
        vkDestroyFence(m_Device, m_InFlightFences[i], nullptr);
    }
 
    vkDestroyCommandPool(m_Device, m_CommandPool, nullptr);
 
    vkDestroyDevice(m_Device, nullptr);
 
    vkDestroySurfaceKHR(m_Instance, m_Surface, nullptr);
 
    vkDestroyInstance(m_Instance, nullptr);
 
    Out::Log(pType::MESSAGE, "Cleaned Vulkan");
 
    return true;
}
 
bool VulkanManager::destroyUI()
{
    ImGui_ImplVulkan_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
 
    ImGui_ImplVulkanH_DestroyWindow(m_Instance, m_Device, &m_MainWindowData, nullptr);
 
    return true;
}
 
bool VulkanManager::Init()
{
    loadScene();
 
    initGLFW();
    initVulkan();
    initUI();
 
    return true;
}
 
bool VulkanManager::Destroy()
{
    destroyVulkan();
    destroyGLFW();
    destroyUI();
 
    return true;
}
 
void VulkanManager::Loop()
{
    static time_t lastTime = time(nullptr);
    static unsigned int renderedFrame = 0;
 
    while (!glfwWindowShouldClose(m_Window) && !Event::shouldQuit)
    {
        glfwPollEvents();
 
        Event::Loop(m_Window);
 
        if (m_VerticesNeedUpdate)
        {
            uint32_t bufferSize = sizeof(Vertex) * m_Vertices.size();
 
            void* vertexData;
            vkMapMemory(m_Device, m_VertexBufferMemory, 0, bufferSize, 0, &vertexData);
 
            memcpy(vertexData, m_Vertices.data(), (size_t)bufferSize);
            vkUnmapMemory(m_Device, m_VertexBufferMemory);
 
            m_VerticesNeedUpdate = false;
        }
 
        //Render();
        RenderUI();
 
        time_t nowTime = time(nullptr);
 
        if (lastTime != nowTime)
        {
            char fpsTitle[16];
            sprintf(fpsTitle, "FPS: %u", renderedFrame);
 
            glfwSetWindowTitle(m_Window, fpsTitle);
            renderedFrame = 0;
        }
        else
        {
            renderedFrame += 1;
        }
 
        lastTime = nowTime;
    }
 
    vkDeviceWaitIdle(m_Device);
}