7#include <vulkan/vulkan.h> 
    9#include <GLFW/glfw3native.h> 
   17#include <unordered_map> 
   31        const bool enableValidationLayers = 
false;
 
   33        const bool enableValidationLayers = 
true;
 
   37    const std::vector<const char*> deviceExtentions = {
 
   38        VK_KHR_SWAPCHAIN_EXTENSION_NAME
 
   41        DISCRETE_GPU_SCORE_BOOST = 1000,
 
   42        MINIMUM_MAX_PUSH_CONSTANTS_SIZE = 64,
 
   43        MINIMUM_MAX_SAMPLER_ALLOCATION_COUNT = 4000,
 
   44        MINIMUM_MAX_IMAGE_DIMENSION_2D = 4090;
 
   45    constexpr u16 MAX_FRAMES_IN_FLIGHT = 3;
 
   48    u32Vec2 renderResolution { 0, 0 };
 
   49    u32Vec2 windowResolution { 0, 0 };
 
   50    GLFWwindow* glfwWindow;
 
   51    bool isInitialised = 
false;
 
   53    VkPhysicalDevice physicalDevice; 
 
   55    VkQueue graphicsQueue;
 
   56    VkDebugUtilsMessengerEXT debugMessenger;
 
   59    VkSwapchainKHR swapChain;
 
   60    std::vector<VkImage> swapChainImages;
 
   61    VkFormat swapChainImageFormat;
 
   62    VkExtent2D swapChainExtent;
 
   63    std::vector<VkImageView> swapChainImageViews;
 
   64    VkPipelineLayout pipelineLayout;
 
   65    VkPipeline graphicsPipeline;
 
   66    VkRenderPass renderPass;
 
   67    std::vector<VkFramebuffer> swapChainFramebuffers;
 
   68    VkCommandPool commandPool;
 
   69    std::vector<VkCommandBuffer> commandBuffers;
 
   72        VkSemaphore imageAvailableSemaphore;
 
   73        VkSemaphore renderFinishedSemaphore;
 
   74        VkFence inFlightFence;
 
   76    std::vector<Frame> frames;
 
   79    void CreateInstance();
 
   80    void SetupDebugMessenger();
 
   81    void PickPhysicalDevice();
 
   82    void CreateLogicalDevice();
 
   83    void CreateSwapChain();
 
   84    void CreateImageViews();
 
   85    void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, 
const VkAllocationCallbacks* pAllocator);
 
   87    void DebugDeviceDetails();
 
   88    void ClampSetResolution(u32 *resolution, 
const u32 maxResolution);
 
   89    void Error(
const char* msg);
 
   90    static std::vector<char> ReadFile(
const std::string& filename);
 
   91    void CreateGraphicsPipeline();
 
   92    void CreateRenderPass();
 
   93    void CreateFramebuffers();
 
   94    void CreateCommandPool();
 
   95    void CreateCommandBuffers();
 
   97    void CreateSyncObjects();
 
  102            Defer(std::function<
void()> Function) : DeferredFunction(Function) {}
 
  105                if (DeferredFunction) DeferredFunction();
 
  108            std::function<void()> DeferredFunction;
 
  119        if (!isInitialised) Error(
"Winow not initialised - call Window::Init() first");
 
  120        if (enableValidationLayers) std::cout << 
"Main loop has started\n";
 
  123        while(!glfwWindowShouldClose(glfwWindow)) 
 
  126            if (internal::isUpdateFunctionInitialised) internal::UpdateFunction();
 
  130        vkDeviceWaitIdle(device);
 
  142        if (isInitialised) Error(
"Winow already initialised - remove secondary call Window::Init()");
 
  145        if (windowResolution.x < 1 || windowResolution.y < 1 ||
 
  146            renderResolution.x < 1 || renderResolution.y < 1) Error(
"window and render resolution has to be set before initialisation - call Window::SetWindowResolution(u32 width, u32 height) and Window::SetRenderResolution(u32 width, u32 height) or directly set Window::windowResolution and Window::renderResolution values first");
 
  150        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 
 
  154        glfwWindow = glfwCreateWindow(windowResolution.x, windowResolution.y, 
title, 
nullptr, 
nullptr);
 
  155        if (!glfwWindow) Error(
"GLFW failed to create window");
 
  159        SetupDebugMessenger();
 
  161        PickPhysicalDevice();
 
  162        CreateLogicalDevice();
 
  166        CreateGraphicsPipeline();
 
  167        CreateFramebuffers();
 
  169        CreateCommandBuffers();
 
  173        isInitialised = 
true;
 
  176        if (enableValidationLayers)
 
  178            DebugDeviceDetails();
 
  179            std::cout << 
"Window is initialised\n";
 
 
  184        if (!isInitialised) 
return; 
 
  187        if (enableValidationLayers) DestroyDebugUtilsMessengerEXT(instance, debugMessenger, 
nullptr);
 
  190        for (
size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
 
  192            if (frames[i].imageAvailableSemaphore) vkDestroySemaphore(device, frames[i].imageAvailableSemaphore, 
nullptr);
 
  193            if (frames[i].renderFinishedSemaphore) vkDestroySemaphore(device, frames[i].renderFinishedSemaphore, 
nullptr);
 
  194            if           (frames[i].inFlightFence) vkDestroyFence(device, frames[i].inFlightFence, 
nullptr);
 
  197        if (commandPool) vkDestroyCommandPool(device, commandPool, 
nullptr);
 
  199        for (
auto frambuffer : swapChainFramebuffers) vkDestroyFramebuffer(device, frambuffer, 
nullptr);
 
  201        if (graphicsPipeline) vkDestroyPipeline(device, graphicsPipeline, 
nullptr);
 
  202        if   (pipelineLayout) vkDestroyPipelineLayout(device, pipelineLayout, 
nullptr);
 
  203        if       (renderPass) vkDestroyRenderPass(device, renderPass, 
nullptr);
 
  205        for (
auto imageView : swapChainImageViews) vkDestroyImageView(device, imageView, 
nullptr);
 
  206        if (swapChain) vkDestroySwapchainKHR(device, swapChain, 
nullptr);
 
  207        if    (device) vkDestroyDevice(device, 
nullptr);
 
  208        if   (surface) vkDestroySurfaceKHR(instance, surface, 
nullptr);
 
  209        if  (instance) vkDestroyInstance(instance, 
nullptr);
 
  212        if (glfwWindow) glfwDestroyWindow(glfwWindow);
 
  214        isInitialised = 
false;
 
  215        if (enableValidationLayers) std::cout << 
"Window has been closed\n";
 
 
  219        ClampSetResolution(&width, INT_MAX);
 
  220        ClampSetResolution(&height, INT_MAX);
 
  222        windowResolution.x = width;
 
  223        windowResolution.y = height;
 
 
  232        ClampSetResolution(&width, INT_MAX);
 
  233        ClampSetResolution(&height, INT_MAX);
 
  235        renderResolution.x = width;
 
  236        renderResolution.y = height;
 
 
 
  249    const std::vector<const char*> validationLayers = {
 
  250        "VK_LAYER_KHRONOS_validation" 
  253    static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, 
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, 
void* pUserData)
 
  255        std::cerr <<
"validation layer: " << pCallbackData->pMessage << 
"\n";
 
  259    bool CheckValidationLayerSupport() 
 
  262        if (vkEnumerateInstanceLayerProperties(&layerCount, 
nullptr) != VK_SUCCESS) Error(
"No validation layer properties, try running not in debug mode");
 
  264        std::vector<VkLayerProperties> availableLayers(layerCount);
 
  265        if (vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()) != VK_SUCCESS) Error(
"No validation layer layers, try running not in debug mode");
 
  267        for (
const char* layerName : validationLayers) 
 
  269            bool layerFound = 
false;
 
  271            for (
const auto& layerProperties : availableLayers)
 
  272                if (strcmp(layerName, layerProperties.layerName) == 0) 
 
  278            if (!layerFound) 
return false;
 
  283    VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, 
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, 
const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) 
 
  285        auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, 
"vkCreateDebugUtilsMessengerEXT");
 
  286        if (func != 
nullptr) 
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
 
  287        else return VK_ERROR_EXTENSION_NOT_PRESENT;
 
  289    void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, 
const VkAllocationCallbacks* pAllocator) 
 
  291        auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, 
"vkDestroyDebugUtilsMessengerEXT");
 
  292        if (func != 
nullptr) func(instance, debugMessenger, pAllocator);
 
  294    void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) 
 
  296        createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
 
  297        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;
 
  298        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;
 
  299        createInfo.pfnUserCallback = DebugCallback;
 
  301    void SetupDebugMessenger()
 
  303        if (!enableValidationLayers) 
return;
 
  305        VkDebugUtilsMessengerCreateInfoEXT createInfo {};
 
  306        populateDebugMessengerCreateInfo(createInfo);
 
  308        if (CreateDebugUtilsMessengerEXT(instance, &createInfo, 
nullptr, &debugMessenger) != VK_SUCCESS) Error(
"failed to set up debug messenger!");
 
  310    std::vector<const char*> GetRequiredExtensions() 
 
  312        u32 glfwExtensionCount = 0;
 
  313        const char** glfwExtensions;
 
  314        glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
 
  316        std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
 
  318        if (enableValidationLayers) extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
 
  326    void CreateInstance()
 
  329        if (enableValidationLayers && !CheckValidationLayerSupport()) Error(
"DEBUG: validation layers are not available");
 
  332        VkApplicationInfo appInfo {};
 
  333        appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
 
  335        appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); 
 
  338        appInfo.apiVersion = VK_API_VERSION_1_0;
 
  341        VkInstanceCreateInfo createInfo {};
 
  342        createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
 
  343        createInfo.pApplicationInfo = &appInfo;
 
  345        auto glfwExtensions = GetRequiredExtensions();
 
  347        createInfo.enabledExtensionCount = 
static_cast<u32
>(glfwExtensions.size());
 
  348        createInfo.ppEnabledExtensionNames = glfwExtensions.data();
 
  350        if (enableValidationLayers) 
 
  352            createInfo.enabledLayerCount = 
static_cast<u32
>(validationLayers.size());
 
  353            createInfo.ppEnabledLayerNames = validationLayers.data();
 
  355        else createInfo.enabledLayerCount = 0;
 
  359        if (vkCreateInstance(&createInfo, 
nullptr, &instance) != VK_SUCCESS) Error(
"failed to create Vulkan instance :(");
 
  362        VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
 
  363        if (enableValidationLayers) 
 
  365            createInfo.enabledLayerCount = 
static_cast<u32
>(validationLayers.size());
 
  366            createInfo.ppEnabledLayerNames = validationLayers.data();
 
  368            populateDebugMessengerCreateInfo(debugCreateInfo);
 
  369            createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
 
  373            createInfo.enabledLayerCount = 0;
 
  374            createInfo.pNext = 
nullptr;
 
  381    struct SwapChainSupportDetails {
 
  382        VkSurfaceCapabilitiesKHR capabilities;
 
  383        std::vector<VkSurfaceFormatKHR> formats;
 
  384        std::vector<VkPresentModeKHR> presentModes;
 
  386    SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice device) 
 
  388        SwapChainSupportDetails details;
 
  389        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
 
  391        vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, 
nullptr);
 
  393        if (formatCount != 0) {
 
  394            details.formats.resize(formatCount);
 
  395            vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
 
  397        u32 presentModeCount;
 
  398        vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, 
nullptr);
 
  400        if (presentModeCount != 0) {
 
  401            details.presentModes.resize(presentModeCount);
 
  402            vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
 
  407    VkSurfaceFormatKHR ChooseSwapSurfaceFormat(
const std::vector<VkSurfaceFormatKHR>& availableFormats) {
 
  408        for (
const auto& availableFormat : availableFormats) 
 
  410            if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
 
  412                return availableFormat;
 
  416        return availableFormats[0];
 
  418    VkPresentModeKHR ChooseSwapPresentMode(
const std::vector<VkPresentModeKHR>& availablePresentModes) 
 
  420        for (
const auto& availablePresentMode : availablePresentModes) {
 
  421            if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) 
return availablePresentMode;
 
  424        return VK_PRESENT_MODE_FIFO_KHR;
 
  426    VkExtent2D ChooseSwapExtent(
const VkSurfaceCapabilitiesKHR& capabilities) 
 
  428        if (capabilities.currentExtent.width != std::numeric_limits<u32>::max()) 
return capabilities.currentExtent;
 
  432            glfwGetFramebufferSize(glfwWindow, &width, &height);
 
  434            VkExtent2D actualExtent = {
 
  435                static_cast<u32
>(width),
 
  436                static_cast<u32
>(height)
 
  439            actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
 
  440            actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
 
  445    struct QueueFamilyIndices 
 
  447        std::optional<u32> graphicsFamily;
 
  448        std::optional<u32> presentFamily;
 
  452            return graphicsFamily.has_value() && presentFamily.has_value();
 
  455    QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice device)
 
  457        QueueFamilyIndices indices {};
 
  459        u32 queueFamilyCount = 0;
 
  460        vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, 
nullptr);
 
  461        std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
 
  462        vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
 
  465        for (
const auto& queueFamily : queueFamilies)
 
  468            if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) indices.graphicsFamily = i;
 
  471            VkBool32 presentSupport = 
false;
 
  472            vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
 
  473            if (presentSupport) indices.presentFamily = i;
 
  475            if (indices.isComplete()) 
break;;
 
  480    void CreateSwapChain() 
 
  482        SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(physicalDevice);
 
  484        VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.formats);
 
  485        VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.presentModes);
 
  486        VkExtent2D extent = ChooseSwapExtent(swapChainSupport.capabilities);
 
  488        u32 imageCount = swapChainSupport.capabilities.minImageCount + 1;
 
  489        if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount)
 
  490            imageCount = swapChainSupport.capabilities.maxImageCount;
 
  492        VkSwapchainCreateInfoKHR createInfo{};
 
  493        createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
 
  494        createInfo.surface = surface;
 
  495        createInfo.minImageCount = imageCount;
 
  496        createInfo.imageFormat = surfaceFormat.format;
 
  497        createInfo.imageColorSpace = surfaceFormat.colorSpace;
 
  498        createInfo.imageExtent = extent;
 
  499        createInfo.imageArrayLayers = 1;
 
  500        createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 
  502        QueueFamilyIndices indices = FindQueueFamilies(physicalDevice);
 
  503        u32 queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
 
  505        if (indices.graphicsFamily != indices.presentFamily) 
 
  507            createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
 
  508            createInfo.queueFamilyIndexCount = 2;
 
  509            createInfo.pQueueFamilyIndices = queueFamilyIndices;
 
  513            createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
  514            createInfo.queueFamilyIndexCount = 0;
 
  515            createInfo.pQueueFamilyIndices = 
nullptr;
 
  517        createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
 
  518        createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
 
  520        createInfo.presentMode = presentMode;
 
  521        createInfo.clipped = VK_TRUE;
 
  522        createInfo.oldSwapchain = VK_NULL_HANDLE;
 
  524        if (vkCreateSwapchainKHR(device, &createInfo, 
nullptr, &swapChain) != VK_SUCCESS) Error(
"Failed to create swap chain");
 
  526        vkGetSwapchainImagesKHR(device, swapChain, &imageCount, 
nullptr);
 
  527        swapChainImages.resize(imageCount);
 
  528        vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
 
  530        swapChainImageFormat = surfaceFormat.format;
 
  531        swapChainExtent = extent;
 
  537    void CreateImageViews()
 
  539        swapChainImageViews.resize(swapChainImages.size());
 
  540        for (
size_t i = 0; i < swapChainImages.size(); i++)
 
  542            VkImageViewCreateInfo createInfo {};
 
  543            createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 
  544            createInfo.image = swapChainImages[i];
 
  545            createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
 
  546            createInfo.format = swapChainImageFormat;
 
  547            createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
 
  548            createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
 
  549            createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
 
  550            createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
 
  551            createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  552            createInfo.subresourceRange.baseMipLevel = 0;
 
  553            createInfo.subresourceRange.levelCount = 1;
 
  554            createInfo.subresourceRange.baseArrayLayer = 0;
 
  555            createInfo.subresourceRange.layerCount = 1;
 
  557            if (vkCreateImageView(device, &createInfo, 
nullptr, &swapChainImageViews[i]) != VK_SUCCESS) Error(
"Failed to create image views");
 
  564    bool CheckDeviceExtensionSupport(VkPhysicalDevice device)
 
  567        vkEnumerateDeviceExtensionProperties(device, 
nullptr, &extensionCount, 
nullptr);
 
  569        std::vector<VkExtensionProperties> availableExtensions(extensionCount);
 
  570        vkEnumerateDeviceExtensionProperties(device, 
nullptr, &extensionCount, availableExtensions.data());
 
  572        std::set<std::string> requiredExtentions(deviceExtentions.begin(), deviceExtentions.end());
 
  574        for (
const auto& extension : availableExtensions) requiredExtentions.erase(extension.extensionName);
 
  575        return requiredExtentions.empty();
 
  577    std::pair<u32, VkPhysicalDevice> RateDeviceSuitability(VkPhysicalDevice device)
 
  579        VkPhysicalDeviceProperties properties;
 
  580        vkGetPhysicalDeviceProperties(device, &properties);
 
  581        VkPhysicalDeviceFeatures features;
 
  582        vkGetPhysicalDeviceFeatures(device, &features);
 
  585        const std::pair BELOW_MINIMUM_SPEC = std::make_pair((u32)0, device);
 
  588        if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) score += DISCRETE_GPU_SCORE_BOOST;
 
  591        score += properties.limits.maxImageDimension2D;
 
  594        if (enableValidationLayers) 
 
  596            VkPhysicalDeviceProperties deviceProperties;
 
  597            vkGetPhysicalDeviceProperties(device, &deviceProperties);
 
  598            std::cout << 
"Device and its score: " << deviceProperties.deviceName << 
" : " << score << 
'\n';
 
  602        if (!CheckDeviceExtensionSupport(device)) 
return BELOW_MINIMUM_SPEC;
 
  603        SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(device);
 
  604        if (swapChainSupport.formats.empty() || swapChainSupport.presentModes.empty()) 
return BELOW_MINIMUM_SPEC;
 
  609            !features.geometryShader ||
 
  611            properties.limits.maxPushConstantsSize < MINIMUM_MAX_PUSH_CONSTANTS_SIZE ||
 
  612            properties.limits.maxSamplerAllocationCount < MINIMUM_MAX_SAMPLER_ALLOCATION_COUNT ||
 
  613            properties.limits.maxImageDimension2D < MINIMUM_MAX_IMAGE_DIMENSION_2D
 
  614        )   
return BELOW_MINIMUM_SPEC;
 
  616        if (!FindQueueFamilies(device).graphicsFamily.has_value()) 
return BELOW_MINIMUM_SPEC;
 
  618        return std::make_pair(score, device);
 
  620    void PickPhysicalDevice()
 
  623        vkEnumeratePhysicalDevices(instance, &deviceCount, 
nullptr);
 
  625        if (deviceCount == 0) Error(
"Couldn't find any GPU with Vulkan support :(");
 
  627        std::vector<VkPhysicalDevice> devices(deviceCount);
 
  628        vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
 
  630        std::vector<std::pair<u32, VkPhysicalDevice>> candidates;
 
  633        for (
const auto& device : devices) candidates.push_back(RateDeviceSuitability(device));
 
  635        auto selectedDevice = std::max_element(
 
  638            [](
const auto& a, 
const auto& b)
 
  640                return a.first < b.first;
 
  643        if ((*selectedDevice).first == 0) Error(
"Couldn't find suitable GPU :(");
 
  645        physicalDevice = (*selectedDevice).second;
 
  651    void CreateLogicalDevice()
 
  653        QueueFamilyIndices indices = FindQueueFamilies(physicalDevice);
 
  655        std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
 
  656        std::set<u32> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
 
  658        float queuePriority = 1.0f;
 
  659        for (u32 queueFamily : uniqueQueueFamilies) {
 
  660            VkDeviceQueueCreateInfo queueCreateInfo{};
 
  661            queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 
  662            queueCreateInfo.queueFamilyIndex = queueFamily;
 
  663            queueCreateInfo.queueCount = 1;
 
  664            queueCreateInfo.pQueuePriorities = &queuePriority;
 
  665            queueCreateInfos.push_back(queueCreateInfo);
 
  668        VkDeviceQueueCreateInfo queueCreateInfo{};
 
  669        queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 
  670        queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
 
  671        queueCreateInfo.queueCount = 1;
 
  673        queueCreateInfo.pQueuePriorities = &queuePriority;
 
  675        VkPhysicalDeviceFeatures deviceFeatures{};
 
  677        VkDeviceCreateInfo createInfo{};
 
  678        createInfo.queueCreateInfoCount = 
static_cast<u32
>(queueCreateInfos.size());
 
  679        createInfo.pQueueCreateInfos = queueCreateInfos.data();
 
  681        createInfo.pEnabledFeatures = &deviceFeatures;
 
  683        createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
 
  684        createInfo.pQueueCreateInfos = &queueCreateInfo;
 
  685        createInfo.queueCreateInfoCount = 1;
 
  687        createInfo.enabledExtensionCount = 
static_cast<u32
>(deviceExtentions.size());
 
  688        createInfo.ppEnabledExtensionNames = deviceExtentions.data();
 
  690        if (vkCreateDevice(physicalDevice, &createInfo, 
nullptr, &device) != VK_SUCCESS) Error(
"failed to create logical device");
 
  691        vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
 
  692        vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
 
  701        if (glfwCreateWindowSurface(instance, glfwWindow, NULL, &surface) != VK_SUCCESS)
 
  703            Error(
"Failed to create window surface");
 
  710    VkShaderModule CreateShaderModule(
const std::vector<char>& code)
 
  712        VkShaderModuleCreateInfo createInfo {};
 
  713        createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
 
  714        createInfo.codeSize = code.size();
 
  715        createInfo.pCode = 
reinterpret_cast<const u32*
>(code.data());
 
  717        VkShaderModule shaderModule;
 
  718        if (vkCreateShaderModule(device, &createInfo, 
nullptr, &shaderModule) != VK_SUCCESS) Error(
"failed to create shader module");
 
  721    void CreateGraphicsPipeline()
 
  723        auto vertShaderCode = ReadFile(
"shaders/vert.spv");
 
  724        auto fragShaderCode = ReadFile(
"shaders/frag.spv");
 
  726        VkShaderModule vertShaderModule = CreateShaderModule(vertShaderCode);
 
  727        VkShaderModule fragShaderModule = CreateShaderModule(fragShaderCode);
 
  729        VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
 
  730        vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 
  731        vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
 
  732        vertShaderStageInfo.module = vertShaderModule;
 
  733        vertShaderStageInfo.pName = 
"main";
 
  735        VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
 
  736        fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 
  737        fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
 
  738        fragShaderStageInfo.module = fragShaderModule;
 
  739        fragShaderStageInfo.pName = 
"main";
 
  741        VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
 
  743        VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
 
  744        vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
 
  745        vertexInputInfo.vertexBindingDescriptionCount = 0;
 
  746        vertexInputInfo.vertexAttributeDescriptionCount = 0;
 
  748        VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
 
  749        inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
 
  750        inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
 
  751        inputAssembly.primitiveRestartEnable = VK_FALSE;
 
  753        VkPipelineViewportStateCreateInfo viewportState{};
 
  754        viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
 
  755        viewportState.viewportCount = 1;
 
  756        viewportState.scissorCount = 1;
 
  758        VkPipelineRasterizationStateCreateInfo rasterizer{};
 
  759        rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
 
  760        rasterizer.depthClampEnable = VK_FALSE;
 
  761        rasterizer.rasterizerDiscardEnable = VK_FALSE;
 
  762        rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
 
  763        rasterizer.lineWidth = 1.0f;
 
  764        rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
 
  765        rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
 
  766        rasterizer.depthBiasEnable = VK_FALSE;
 
  768        VkPipelineMultisampleStateCreateInfo multisampling{};
 
  769        multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
 
  770        multisampling.sampleShadingEnable = VK_FALSE;
 
  771        multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
 
  773        VkPipelineColorBlendAttachmentState colorBlendAttachment{};
 
  774        colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
 
  775        colorBlendAttachment.blendEnable = VK_FALSE;
 
  777        VkPipelineColorBlendStateCreateInfo colorBlending{};
 
  778        colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
 
  779        colorBlending.logicOpEnable = VK_FALSE;
 
  780        colorBlending.logicOp = VK_LOGIC_OP_COPY;
 
  781        colorBlending.attachmentCount = 1;
 
  782        colorBlending.pAttachments = &colorBlendAttachment;
 
  783        colorBlending.blendConstants[0] = 0.0f;
 
  784        colorBlending.blendConstants[1] = 0.0f;
 
  785        colorBlending.blendConstants[2] = 0.0f;
 
  786        colorBlending.blendConstants[3] = 0.0f;
 
  788        std::vector<VkDynamicState> dynamicStates = {
 
  789            VK_DYNAMIC_STATE_VIEWPORT,
 
  790            VK_DYNAMIC_STATE_SCISSOR
 
  792        VkPipelineDynamicStateCreateInfo dynamicState{};
 
  793        dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
 
  794        dynamicState.dynamicStateCount = 
static_cast<uint32_t
>(dynamicStates.size());
 
  795        dynamicState.pDynamicStates = dynamicStates.data();
 
  797        VkPipelineLayoutCreateInfo pipelineLayoutInfo {};
 
  798        pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
 
  799        pipelineLayoutInfo.setLayoutCount = 0;
 
  800        pipelineLayoutInfo.pushConstantRangeCount = 0;
 
  802        if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, 
nullptr, &pipelineLayout) != VK_SUCCESS) Error(
"failed to create pipeline layout");
 
  804        VkGraphicsPipelineCreateInfo pipelineInfo{};
 
  805        pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
 
  806        pipelineInfo.stageCount = 2;
 
  807        pipelineInfo.pStages = shaderStages;
 
  808        pipelineInfo.pVertexInputState = &vertexInputInfo;
 
  809        pipelineInfo.pInputAssemblyState = &inputAssembly;
 
  810        pipelineInfo.pViewportState = &viewportState;
 
  811        pipelineInfo.pRasterizationState = &rasterizer;
 
  812        pipelineInfo.pMultisampleState = &multisampling;
 
  813        pipelineInfo.pColorBlendState = &colorBlending;
 
  814        pipelineInfo.pDynamicState = &dynamicState;
 
  815        pipelineInfo.layout = pipelineLayout;
 
  816        pipelineInfo.renderPass = renderPass;
 
  817        pipelineInfo.subpass = 0;
 
  818        pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
 
  820        if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, 
nullptr, &graphicsPipeline) != VK_SUCCESS) Error(
"failed to create graphics pipeline");
 
  822        vkDestroyShaderModule(device, fragShaderModule, 
nullptr);
 
  823        vkDestroyShaderModule(device, vertShaderModule, 
nullptr);
 
  825    void CreateRenderPass()
 
  827        VkAttachmentDescription colorAttachment{};
 
  828        colorAttachment.format = swapChainImageFormat;
 
  829        colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
 
  830        colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 
  831        colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 
  832        colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 
  833        colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
 
  834        colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
  835        colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
 
  837        VkAttachmentReference colorAttachmentRef{};
 
  838        colorAttachmentRef.attachment = 0;
 
  839        colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 
  841        VkSubpassDescription subpass{};
 
  842        subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
 
  843        subpass.colorAttachmentCount = 1;
 
  844        subpass.pColorAttachments = &colorAttachmentRef;
 
  846        VkSubpassDependency dependency{};
 
  847        dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
 
  848        dependency.dstSubpass = 0;
 
  849        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 
  850        dependency.srcAccessMask = 0;
 
  851        dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 
  852        dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
 
  854        VkRenderPassCreateInfo renderPassInfo{};
 
  855        renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
 
  856        renderPassInfo.attachmentCount = 1;
 
  857        renderPassInfo.pAttachments = &colorAttachment;
 
  858        renderPassInfo.subpassCount = 1;
 
  859        renderPassInfo.pSubpasses = &subpass;
 
  860        renderPassInfo.dependencyCount = 1;
 
  861        renderPassInfo.pDependencies = &dependency;
 
  863        if (vkCreateRenderPass(device, &renderPassInfo, 
nullptr, &renderPass) != VK_SUCCESS) Error(
"failed to create render pass");
 
  869    void CreateFramebuffers() 
 
  871        swapChainFramebuffers.resize(swapChainImageViews.size());
 
  873        for (
size_t i = 0; i < swapChainImageViews.size(); i++) {
 
  874            VkImageView attachments[] = {
 
  875                swapChainImageViews[i]
 
  878            VkFramebufferCreateInfo framebufferInfo{};
 
  879            framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
 
  880            framebufferInfo.renderPass = renderPass;
 
  881            framebufferInfo.attachmentCount = 1;
 
  882            framebufferInfo.pAttachments = attachments;
 
  883            framebufferInfo.width = swapChainExtent.width;
 
  884            framebufferInfo.height = swapChainExtent.height;
 
  885            framebufferInfo.layers = 1;
 
  887            if (vkCreateFramebuffer(device, &framebufferInfo, 
nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) Error(
"failed to create framebuffer");
 
  890    void CreateCommandPool() 
 
  892        QueueFamilyIndices queueFamilyIndices = FindQueueFamilies(physicalDevice);
 
  894        VkCommandPoolCreateInfo poolInfo{};
 
  895        poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
 
  896        poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
 
  897        poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
 
  899        if (vkCreateCommandPool(device, &poolInfo, 
nullptr, &commandPool) != VK_SUCCESS) Error(
"Failed to create command pool");
 
  901    void CreateCommandBuffers()
 
  903        commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
 
  905        VkCommandBufferAllocateInfo allocInfo {};
 
  906        allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
 
  907        allocInfo.commandPool = commandPool;
 
  908        allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
 
  909        allocInfo.commandBufferCount = (u32)commandBuffers.size();
 
  911        if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) Error(
"failed to allocate command buffers");
 
  913    VkClearColorValue ConvertBackgroundColour()
 
  922    void RecordCommandBuffer(VkCommandBuffer commandBuffer, u32 imageIndex) 
 
  924        VkCommandBufferBeginInfo beginInfo{};
 
  925        beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
 
  927        beginInfo.pInheritanceInfo = 
nullptr; 
 
  929        if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) Error(
"failed to begin recording command buffer");
 
  931        VkRenderPassBeginInfo renderPassInfo{};
 
  932        renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
 
  933        renderPassInfo.renderPass = renderPass;
 
  934        renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
 
  935        renderPassInfo.renderArea.offset = {0, 0};
 
  936        renderPassInfo.renderArea.extent = swapChainExtent;
 
  937        VkClearValue clearColor = { ConvertBackgroundColour() };
 
  938        renderPassInfo.clearValueCount = 1;
 
  939        renderPassInfo.pClearValues = &clearColor;
 
  940        vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
 
  942        vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
 
  943        VkViewport viewport{};
 
  946        viewport.width = 
static_cast<float>(swapChainExtent.width);
 
  947        viewport.height = 
static_cast<float>(swapChainExtent.height);
 
  948        viewport.minDepth = 0.0f;
 
  949        viewport.maxDepth = 1.0f;
 
  950        vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
 
  953        scissor.offset = {0, 0};
 
  954        scissor.extent = swapChainExtent;
 
  955        vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
 
  958        vkCmdDraw(commandBuffer, 3, 1, 0, 0);
 
  960        vkCmdEndRenderPass(commandBuffer);
 
  961        if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) Error(
"failed to record command buffer");
 
  967    void CreateSyncObjects()
 
  969        frames.resize(MAX_FRAMES_IN_FLIGHT);
 
  971        VkSemaphoreCreateInfo semaphoreInfo {};
 
  972        semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
 
  974        VkFenceCreateInfo fenceInfo {};
 
  975        fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
 
  976        fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
 
  978        for (
size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) 
 
  979            if (vkCreateSemaphore(device, &semaphoreInfo, 
nullptr, &frames[i].imageAvailableSemaphore) != VK_SUCCESS 
 
  980            || vkCreateSemaphore(device, &semaphoreInfo, 
nullptr, &frames[i].renderFinishedSemaphore) != VK_SUCCESS 
 
  981            || vkCreateFence(device, &fenceInfo, 
nullptr, &frames[i].inFlightFence) != VK_SUCCESS) Error(
"failed to create semaphores");
 
  985        vkWaitForFences(device, 1, &frames[currentFrame].inFlightFence, VK_TRUE, UINT64_MAX);
 
  986        vkResetFences(device, 1, &frames[currentFrame].inFlightFence);
 
  989        vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, frames[currentFrame].imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
 
  991        vkResetCommandBuffer(commandBuffers[currentFrame], 0);
 
  992        RecordCommandBuffer(commandBuffers[currentFrame], imageIndex);
 
  994        VkSubmitInfo submitInfo {};
 
  995        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
 
  997        VkSemaphore waitSemaphores[] = { frames[currentFrame].imageAvailableSemaphore };
 
  998        VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
 
  999        submitInfo.waitSemaphoreCount = 1;
 
 1000        submitInfo.pWaitSemaphores = waitSemaphores;
 
 1001        submitInfo.pWaitDstStageMask = waitStages;
 
 1002        submitInfo.commandBufferCount = 1;
 
 1003        submitInfo.pCommandBuffers = &commandBuffers[currentFrame];
 
 1005        VkSemaphore signalSemaphores[] = { frames[currentFrame].renderFinishedSemaphore };
 
 1006        submitInfo.signalSemaphoreCount = 1;
 
 1007        submitInfo.pSignalSemaphores = signalSemaphores;
 
 1009        if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, frames[currentFrame].inFlightFence) != VK_SUCCESS) Error(
"failed to submit draw command buffer");
 
 1011        VkSubpassDependency dependency{};
 
 1012        dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
 
 1013        dependency.dstSubpass = 0;
 
 1014        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 
 1015        dependency.srcAccessMask = 0;
 
 1016        dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 
 1017        dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
 
 1019        VkPresentInfoKHR presentInfo{};
 
 1020        presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
 
 1022        presentInfo.waitSemaphoreCount = 1;
 
 1023        presentInfo.pWaitSemaphores = signalSemaphores;
 
 1025        VkSwapchainKHR swapChains[] = { swapChain };
 
 1026        presentInfo.swapchainCount = 1;
 
 1027        presentInfo.pSwapchains = swapChains;
 
 1028        presentInfo.pImageIndices = &imageIndex;
 
 1029        presentInfo.pResults = 
nullptr;
 
 1031        vkQueuePresentKHR(presentQueue, &presentInfo);
 
 1032        currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
 
 1038    void DebugDeviceDetails()
 
 1040        VkPhysicalDeviceProperties deviceProperties;
 
 1041        vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
 
 1043        static const std::unordered_map<u32, const char*> gpuVendors = {
 
 1050        static const u8 LABEL_WIDTH = 15,
 
 1052        auto PrintDetail = [](
const char* label, 
const auto& value) 
 
 1054            std::cout << std::setw(LABEL_WIDTH) << std::left << label << 
": "  
 1055                      << std::setw(VALUE_WIDTH) << std::left << value << 
"\n";
 
 1058        PrintDetail(
"GPU selected", deviceProperties.deviceName);
 
 1059        PrintDetail(
"API version", std::to_string(deviceProperties.apiVersion) + 
" (" +
 
 1060            std::to_string(VK_VERSION_MAJOR(deviceProperties.apiVersion)) + 
"." +
 
 1061            std::to_string(VK_VERSION_MINOR(deviceProperties.apiVersion)) + 
"." +
 
 1062            std::to_string(VK_VERSION_PATCH(deviceProperties.apiVersion)) + 
")");
 
 1064        PrintDetail(
"Driver version", deviceProperties.driverVersion);
 
 1065        PrintDetail(
"Device ID", deviceProperties.deviceID);
 
 1067        u32 vendorID = deviceProperties.vendorID;
 
 1068        std::string vendorName = gpuVendors.count(vendorID) ? gpuVendors.at(vendorID) : 
"Unknown";
 
 1069        PrintDetail(
"Vendor ID", std::to_string(vendorID) + 
" (" + vendorName + 
")");
 
 1071    void ClampSetResolution(u32 *resolution, 
const u32 maxResolution)
 
 1074        *resolution = *resolution < maxResolution ? *resolution : maxResolution;
 
 1076    void Error(
const char* msg)
 
 1078        if (enableValidationLayers) std::cerr << 
"Error: " << msg << 
'\n';
 
 1080        throw std::runtime_error(msg);
 
 1082    static std::vector<char> ReadFile(
const std::string& filename)
 
 1085        std::ifstream file(filename, std::ios::ate | std::ios::binary);
 
 1087        if (!file.is_open()) Error(
"failed to open file!");
 
 1089        size_t fileSize = (size_t) file.tellg();
 
 1090        std::vector<char> buffer(fileSize);
 
 1093        file.read(buffer.data(), fileSize);
 
constexpr u16 UPDATE_PATCH
Patch update version.
constexpr u16 UPDATE_MAJOR
Major update version.
constexpr u16 UPDATE_MINOR
Minor update version.
constexpr const char * ENGINE_NAME
The name of the game engine TODO: instert name here when decided.
Handles window creation and Vulkan initialization and main loop. code can be found in window....
const char * title
Title of the window.
void SetWindowResolution(u32 width, u32 height)
Sets the window resolution.
u32Vec2 GetWindowResolution()
Gets the window resolution.
Colour backgroundColour
Background colour, has alias backgroundColor.
void SetRenderResolution(u32 width, u32 height)
Sets the render resolution.
void Close()
Closes the window and cleans up Vulkan.
bool isResizable
Going to be flags later on...
void Init()
alias for backgroundColour
u32Vec2 GetRenderResolution()
Gets the render resolution.
Has alias 'Color'. Holds an 24 bit colour (+ an alpha channel)
2D vector of 32 bit width unsigned integers
Defines window namespace, can be found in window.cpp.