Facebook
From Beige Crocodile, 3 Years ago, written in C++.
This paste is a reply to Untitled from jojo7682345 - view diff
Embed
Download Paste or View Raw
Hits: 108
  1. #define GLFW_INCLUDE_VULKAN
  2. #include <GLFW/glfw3.h>
  3.  
  4. #include <iostream>
  5. #include <fstream>
  6. #include <stdexcept>
  7. #include <algorithm>
  8. #include <vector>
  9. #include <cstring>
  10. #include <cstdlib>
  11. #include <cstdint>
  12. #include <optional>
  13. #include <set>
  14.  
  15. const uint32_t WIDTH = 800;
  16. const uint32_t HEIGHT = 600;
  17.  
  18. const int MAX_FRAMES_IN_FLIGHT = 2;
  19.  
  20. const std::vector<const char*> validationLayers = {
  21.     "VK_LAYER_KHRONOS_validation"
  22. };
  23.  
  24. const std::vector<const char*> deviceExtensions = {
  25.     VK_KHR_SWAPCHAIN_EXTENSION_NAME
  26. };
  27.  
  28. #ifdef NDEBUG
  29. const bool enableValidationLayers = false;
  30. #else
  31. const bool enableValidationLayers = true;
  32. #endif
  33.  
  34. VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
  35.     auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
  36.     if (func != nullptr) {
  37.         return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
  38.     }
  39.     else {
  40.         return VK_ERROR_EXTENSION_NOT_PRESENT;
  41.     }
  42. }
  43.  
  44. void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) {
  45.     auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
  46.     if (func != nullptr) {
  47.         func(instance, debugMessenger, pAllocator);
  48.     }
  49. }
  50.  
  51. struct QueueFamilyIndices {
  52.     std::optional<uint32_t> computeFamily;
  53.     std::optional<uint32_t> presentFamily;
  54.  
  55.     bool isComplete() {
  56.         return computeFamily.has_value() && presentFamily.has_value();
  57.     }
  58. };
  59.  
  60. struct SwapChainSupportDetails {
  61.     VkSurfaceCapabilitiesKHR capabilities;
  62.     std::vector<VkSurfaceFormatKHR> formats;
  63.     std::vector<VkPresentModeKHR> presentModes;
  64. };
  65.  
  66. class HelloTriangleApplication {
  67. public:
  68.     void run() {
  69.         initWindow();
  70.         initVulkan();
  71.         mainLoop();
  72.         cleanup();
  73.     }
  74.  
  75. private:
  76.     GLFWwindow* window;
  77.  
  78.     VkInstance instance;
  79.     VkDebugUtilsMessengerEXT debugMessenger;
  80.     VkSurfaceKHR surface;
  81.  
  82.     VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
  83.     VkDevice device;
  84.  
  85.     VkQueue computeQueue;
  86.     VkQueue presentQueue;
  87.  
  88.     VkSwapchainKHR swapChain;
  89.     std::vector<VkImage> swapChainImages;
  90.     //std::vector<VkImage> renderTargetImages;
  91.     std::vector<VkImageView> renderTargetImageViews;
  92.     VkDeviceMemory renderTargetDeviceMemory;
  93.     VkFormat swapChainImageFormat;
  94.     VkExtent2D swapChainExtent;
  95.     std::vector<VkImageView> swapChainImageViews;
  96.  
  97.     VkPipelineLayout pipelineLayout;
  98.     VkPipeline pipeline;
  99.  
  100.     VkCommandPool commandPool;
  101.     std::vector<VkCommandBuffer> commandBuffers;
  102.  
  103.     std::vector<VkSemaphore> imageAvailableSemaphores;
  104.     std::vector<VkSemaphore> renderFinishedSemaphores;
  105.     std::vector<VkFence> inFlightFences;
  106.     std::vector<VkFence> imagesInFlight;
  107.     size_t currentFrame = 0;
  108.  
  109.     VkDescriptorSetLayout descriptorSetLayout;
  110.     std::vector<VkDescriptorSet> descriptorSets;
  111.     VkDescriptorPool descriptorPool;
  112.  
  113.     VkSampler imageSampler;
  114.  
  115.     bool framebufferResized = false;
  116.  
  117.     void initWindow() {
  118.         glfwInit();
  119.  
  120.         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
  121.  
  122.         window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
  123.         glfwSetWindowUserPointer(window, this);
  124.         glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
  125.     }
  126.  
  127.     static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
  128.         auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
  129.         app->framebufferResized = true;
  130.     }
  131.  
  132.     void initVulkan() {
  133.         createInstance();
  134.         setupDebugMessenger();
  135.         createSurface();
  136.         pickPhysicalDevice();
  137.         createLogicalDevice();
  138.  
  139.         createSwapChain();
  140.         createImageViews();
  141.  
  142.         createDescriptorSetLayout();
  143.         createComputePipeline();
  144.        
  145.         createCommandPool();
  146.         createDescriptorPool();
  147.         createDescriptorSets();
  148.         createCommandBuffers();
  149.        
  150.         createSyncObjects();
  151.     }
  152.  
  153.     void mainLoop() {
  154.         while (!glfwWindowShouldClose(window)) {
  155.             glfwPollEvents();
  156.             drawFrame();
  157.         }
  158.  
  159.         vkDeviceWaitIdle(device);
  160.     }
  161.  
  162.     void cleanupSwapChain() {
  163.  
  164.         vkFreeMemory(device, renderTargetDeviceMemory, nullptr);
  165.         for (auto imageView : renderTargetImageViews) {
  166.             vkDestroyImageView(device, imageView, nullptr);
  167.         }
  168.         //for (auto image : renderTargetImages) {
  169.         //    vkDestroyImage(device, image, nullptr);
  170.         //}
  171.         vkDestroySampler(device, imageSampler, nullptr);
  172.  
  173.         vkDestroyDescriptorPool(device, descriptorPool, nullptr);
  174.  
  175.         vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
  176.  
  177.         vkDestroyPipeline(device, pipeline, nullptr);
  178.         vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
  179.  
  180.         for (auto imageView : swapChainImageViews) {
  181.             vkDestroyImageView(device, imageView, nullptr);
  182.         }
  183.  
  184.         vkDestroySwapchainKHR(device, swapChain, nullptr);
  185.     }
  186.  
  187.     void cleanup() {
  188.         cleanupSwapChain();
  189.  
  190.         vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
  191.  
  192.         for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
  193.             vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
  194.             vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
  195.             vkDestroyFence(device, inFlightFences[i], nullptr);
  196.         }
  197.  
  198.         vkDestroyCommandPool(device, commandPool, nullptr);
  199.  
  200.         vkDestroyDevice(device, nullptr);
  201.  
  202.         if (enableValidationLayers) {
  203.             DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
  204.         }
  205.  
  206.         vkDestroySurfaceKHR(instance, surface, nullptr);
  207.         vkDestroyInstance(instance, nullptr);
  208.  
  209.         glfwDestroyWindow(window);
  210.  
  211.         glfwTerminate();
  212.     }
  213.  
  214.     void recreateSwapChain() {
  215.         int width = 0, height = 0;
  216.         glfwGetFramebufferSize(window, &width, &height);
  217.         while (width == 0 || height == 0) {
  218.             glfwGetFramebufferSize(window, &width, &height);
  219.             glfwWaitEvents();
  220.         }
  221.  
  222.         vkDeviceWaitIdle(device);
  223.  
  224.         cleanupSwapChain();
  225.  
  226.         createSwapChain();
  227.         createImageViews();
  228.         createDescriptorPool();
  229.         createDescriptorSets();
  230.         createComputePipeline();
  231.         createCommandBuffers();
  232.        
  233.     }
  234.  
  235.     void createInstance() {
  236.         if (enableValidationLayers && !checkValidationLayerSupport()) {
  237.             throw std::runtime_error("validation layers requested, but not available!");
  238.         }
  239.  
  240.         VkApplicationInfo appInfo{};
  241.         appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  242.         appInfo.pApplicationName = "Hello Triangle";
  243.         appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
  244.         appInfo.pEngineName = "No Engine";
  245.         appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
  246.         appInfo.apiVersion = VK_API_VERSION_1_0;
  247.  
  248.         VkInstanceCreateInfo createInfo{};
  249.         createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  250.         createInfo.pApplicationInfo = &appInfo;
  251.  
  252.         auto extensions = getRequiredExtensions();
  253.         createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
  254.         createInfo.ppEnabledExtensionNames = extensions.data();
  255.  
  256.         VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
  257.         if (enableValidationLayers) {
  258.             createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
  259.             createInfo.ppEnabledLayerNames = validationLayers.data();
  260.  
  261.             populateDebugMessengerCreateInfo(debugCreateInfo);
  262.             createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
  263.         }
  264.         else {
  265.             createInfo.enabledLayerCount = 0;
  266.  
  267.             createInfo.pNext = nullptr;
  268.         }
  269.  
  270.         if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
  271.             throw std::runtime_error("failed to create instance!");
  272.         }
  273.     }
  274.  
  275.     void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
  276.         createInfo = {};
  277.         createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
  278.         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;
  279.         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;
  280.         createInfo.pfnUserCallback = debugCallback;
  281.     }
  282.  
  283.     void setupDebugMessenger() {
  284.         if (!enableValidationLayers) return;
  285.  
  286.         VkDebugUtilsMessengerCreateInfoEXT createInfo;
  287.         populateDebugMessengerCreateInfo(createInfo);
  288.  
  289.         if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
  290.             throw std::runtime_error("failed to set up debug messenger!");
  291.         }
  292.     }
  293.  
  294.     void createSurface() {
  295.         if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
  296.             throw std::runtime_error("failed to create window surface!");
  297.         }
  298.     }
  299.  
  300.     void pickPhysicalDevice() {
  301.         uint32_t deviceCount = 0;
  302.         vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
  303.  
  304.         if (deviceCount == 0) {
  305.             throw std::runtime_error("failed to find GPUs with Vulkan support!");
  306.         }
  307.  
  308.         std::vector<VkPhysicalDevice> devices(deviceCount);
  309.         vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
  310.  
  311.         for (const auto& device : devices) {
  312.             if (isDeviceSuitable(device)) {
  313.                 physicalDevice = device;
  314.                 break;
  315.             }
  316.         }
  317.  
  318.         if (physicalDevice == VK_NULL_HANDLE) {
  319.             throw std::runtime_error("failed to find a suitable GPU!");
  320.         }
  321.     }
  322.  
  323.     void createLogicalDevice() {
  324.         QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
  325.  
  326.         std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
  327.         std::set<uint32_t> uniqueQueueFamilies = { indices.computeFamily.value(), indices.presentFamily.value() };
  328.  
  329.         float queuePriority = 1.0f;
  330.         for (uint32_t queueFamily : uniqueQueueFamilies) {
  331.             VkDeviceQueueCreateInfo queueCreateInfo{};
  332.             queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  333.             queueCreateInfo.queueFamilyIndex = queueFamily;
  334.             queueCreateInfo.queueCount = 1;
  335.             queueCreateInfo.pQueuePriorities = &queuePriority;
  336.             queueCreateInfos.push_back(queueCreateInfo);
  337.         }
  338.  
  339.         VkPhysicalDeviceFeatures deviceFeatures{};
  340.         VkDeviceCreateInfo createInfo{};
  341.         createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  342.  
  343.         createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
  344.         createInfo.pQueueCreateInfos = queueCreateInfos.data();
  345.  
  346.         createInfo.pEnabledFeatures = &deviceFeatures;
  347.  
  348.         createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
  349.         createInfo.ppEnabledExtensionNames = deviceExtensions.data();
  350.  
  351.         if (enableValidationLayers) {
  352.             createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
  353.             createInfo.ppEnabledLayerNames = validationLayers.data();
  354.         }
  355.         else {
  356.             createInfo.enabledLayerCount = 0;
  357.         }
  358.  
  359.         if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
  360.             throw std::runtime_error("failed to create logical device!");
  361.         }
  362.  
  363.         vkGetDeviceQueue(device, indices.computeFamily.value(), 0, &computeQueue);
  364.         vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
  365.     }
  366.  
  367.     uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
  368.         VkPhysicalDeviceMemoryProperties memProperties;
  369.         vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
  370.  
  371.         for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
  372.             if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
  373.                 return i;
  374.             }
  375.         }
  376.  
  377.         throw std::runtime_error("failed to find suitable memory type!");
  378.     }
  379.  
  380.     void createSwapChain() {
  381.         SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
  382.  
  383.         VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
  384.         VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
  385.         VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
  386.  
  387.         uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
  388.         if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
  389.             imageCount = swapChainSupport.capabilities.maxImageCount;
  390.         }
  391.  
  392.         VkSwapchainCreateInfoKHR createInfo{};
  393.         createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  394.         createInfo.surface = surface;
  395.  
  396.         createInfo.minImageCount = imageCount;
  397.         for (auto& format : swapChainSupport.formats) {
  398.  
  399.             if (CheckFormatSupport(physicalDevice, format.format,
  400.                 VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
  401.                 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
  402.                 surfaceFormat.format = format.format;
  403.                 break;
  404.             }
  405.         }
  406.  
  407.  
  408.         createInfo.imageFormat = surfaceFormat.format;
  409.         createInfo.imageColorSpace = surfaceFormat.colorSpace;
  410.         createInfo.imageExtent = extent;
  411.         createInfo.imageArrayLayers = 1;
  412.         createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
  413.  
  414.         QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
  415.         uint32_t queueFamilyIndices[] = { indices.computeFamily.value(), indices.presentFamily.value() };
  416.  
  417.         if (indices.computeFamily != indices.presentFamily) {
  418.             createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
  419.             createInfo.queueFamilyIndexCount = 2;
  420.             createInfo.pQueueFamilyIndices = queueFamilyIndices;
  421.         }
  422.         else {
  423.             createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  424.         }
  425.  
  426.         createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
  427.         createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  428.         createInfo.presentMode = presentMode;
  429.         createInfo.clipped = VK_TRUE;
  430.         if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
  431.             throw std::runtime_error("failed to create swap chain!");
  432.         }
  433.  
  434.         vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
  435.         swapChainImages.resize(imageCount);
  436.         vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
  437.  
  438.  
  439.         swapChainImageFormat = surfaceFormat.format;
  440.         swapChainExtent = extent;
  441.  
  442.         //renderTargetImages.resize(swapChainImages.size());
  443.        /*renderTargetImageViews.resize(swapChainImages.size());
  444.         std::vector<VkMemoryRequirements> memRequirements(swapChainImages.size());
  445.         VkFormat computeFormat{};
  446.         for (auto& format : swapChainSupport.formats) {
  447.  
  448.                 if (CheckFormatSupport(physicalDevice, format.format,
  449.                     VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
  450.                     VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
  451.                     computeFormat = format.format;
  452.                     break;
  453.                 }
  454.             }
  455.         /*for (int i = 0; i < swapChainImages.size(); i++) {
  456.             VkImageCreateInfo imageCreateInfo{};
  457.             imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  458.             imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
  459.             imageCreateInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT| VK_IMAGE_USAGE_SAMPLED_BIT;
  460.             imageCreateInfo.flags = 0;
  461.             imageCreateInfo.mipLevels = 1;
  462.             imageCreateInfo.arrayLayers = 1;
  463.             VkExtent3D imageExtent{};
  464.             imageExtent.depth = 1;
  465.             imageExtent.width = extent.width;
  466.             imageExtent.height = extent.height;
  467.             imageCreateInfo.extent = imageExtent;
  468.             imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  469.  
  470.             uint32_t families[] { indices.computeFamily.value(),indices.presentFamily.value() };
  471.             imageCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;
  472.             if (indices.computeFamily.value() == indices.presentFamily.value()) {
  473.                 imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  474.             }
  475.             imageCreateInfo.pQueueFamilyIndices = families;
  476.             imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
  477.            
  478.             imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
  479.             imageCreateInfo.format = computeFormat;
  480.  
  481.            // if (vkCreateImage(device, &imageCreateInfo, nullptr, &renderTargetImages[i]) != VK_SUCCESS) {
  482.              //   throw std::runtime_error("failed to create image views!");
  483.             //}
  484.            
  485.             //VkMemoryRequirements requirements;
  486.             //vkGetImageMemoryRequirements(device, renderTargetImages[0], &memRequirements[i]);
  487.         }
  488.  
  489.        
  490.  
  491.         /*VkMemoryAllocateInfo allocInfo{};
  492.         VkDeviceSize deviceSize = 0;
  493.         for (int i = 0; i < renderTargetImages.size(); i++) {
  494.             deviceSize += memRequirements[i].size;
  495.         }
  496.         allocInfo.allocationSize = deviceSize;
  497.         allocInfo.memoryTypeIndex = findMemoryType(memRequirements[1].memoryTypeBits,
  498.             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  499.         allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  500.  
  501.         vkAllocateMemory(device, &allocInfo, nullptr, &renderTargetDeviceMemory);
  502.         uint32_t offset = 0;
  503.         for (int i = 0; i < renderTargetImages.size(); i++) {
  504.  
  505.  
  506.             vkBindImageMemory(device, renderTargetImages[i], renderTargetDeviceMemory, offset);
  507.             offset += memRequirements[i].size;
  508.  
  509.             VkImageViewCreateInfo imageViewInfo{};
  510.             imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  511.             imageViewInfo.image = renderTargetImages[i];
  512.             imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
  513.             imageViewInfo.format = computeFormat;
  514.             imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
  515.             imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
  516.             imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
  517.             imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
  518.             imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  519.             imageViewInfo.subresourceRange.baseMipLevel = 0;
  520.             imageViewInfo.subresourceRange.levelCount = 1;
  521.             imageViewInfo.subresourceRange.baseArrayLayer = 0;
  522.             imageViewInfo.subresourceRange.layerCount = 1;
  523.  
  524.             if (vkCreateImageView(device, &imageViewInfo, nullptr, &renderTargetImageViews[i]) != VK_SUCCESS) {
  525.                 throw std::runtime_error("failed to create image views!");
  526.             }
  527.         }*/
  528.     }
  529.  
  530.     void createImageViews() {
  531.         swapChainImageViews.resize(swapChainImages.size());
  532.  
  533.         for (size_t i = 0; i < swapChainImages.size(); i++) {
  534.             VkImageViewCreateInfo createInfo{};
  535.             createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  536.             createInfo.image = swapChainImages[i];
  537.             createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
  538.             createInfo.format = swapChainImageFormat;
  539.             createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
  540.             createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
  541.             createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
  542.             createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
  543.             createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  544.             createInfo.subresourceRange.baseMipLevel = 0;
  545.             createInfo.subresourceRange.levelCount = 1;
  546.             createInfo.subresourceRange.baseArrayLayer = 0;
  547.             createInfo.subresourceRange.layerCount = 1;
  548.  
  549.  
  550.             if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
  551.                 throw std::runtime_error("failed to create image views!");
  552.             }
  553.         }
  554.     }
  555.  
  556.     void createComputePipeline() {
  557.         auto shader = readFile("shaders/comp.spv");
  558.         VkShaderModule shaderModule = createShaderModule(shader);
  559.  
  560.         VkPipelineShaderStageCreateInfo shaderStageInfo{};
  561.         shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  562.         shaderStageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
  563.         shaderStageInfo.module = shaderModule;
  564.         shaderStageInfo.pName = "main";
  565.  
  566.         VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
  567.         pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  568.         pipelineLayoutInfo.setLayoutCount = 1; // Optional
  569.         pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; // Optional
  570.         pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional
  571.         pipelineLayoutInfo.pPushConstantRanges = nullptr; // Optional
  572.  
  573.         if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
  574.             throw std::runtime_error("failed to create pipeline layout!");
  575.         }
  576.  
  577.         VkComputePipelineCreateInfo info{};
  578.         info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
  579.         info.layout = pipelineLayout;
  580.         info.basePipelineIndex = -1;
  581.         info.basePipelineHandle = VK_NULL_HANDLE;
  582.         info.stage = shaderStageInfo;
  583.    
  584.  
  585.         if (vkCreateComputePipelines(device,VK_NULL_HANDLE,1,&info,nullptr,&pipeline) != VK_SUCCESS) {
  586.             throw std::runtime_error("compute shader");
  587.         }
  588.  
  589.         vkDestroyShaderModule(device, shaderModule, nullptr);
  590.     }
  591.  
  592.     void createCommandPool() {
  593.         QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
  594.  
  595.         VkCommandPoolCreateInfo poolInfo{};
  596.         poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  597.         poolInfo.queueFamilyIndex = queueFamilyIndices.computeFamily.value();
  598.  
  599.         if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
  600.             throw std::runtime_error("failed to create command pool!");
  601.         }
  602.     }
  603.  
  604.     void recordImageBarrier(VkCommandBuffer buffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout,
  605.         VkAccessFlags scrAccess, VkAccessFlags dstAccess, VkPipelineStageFlags srcBind, VkPipelineStageFlags dstBind) {
  606.         VkImageMemoryBarrier barrier{};
  607.         barrier.image = image;
  608.         barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  609.         barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  610.         barrier.oldLayout = oldLayout;
  611.         barrier.newLayout = newLayout;
  612.         barrier.srcAccessMask = scrAccess;
  613.         barrier.dstAccessMask = dstAccess;
  614.         barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  615.         VkImageSubresourceRange sub{};
  616.         sub.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  617.         sub.baseArrayLayer = 0;
  618.         sub.baseMipLevel = 0;
  619.         sub.layerCount = VK_REMAINING_MIP_LEVELS;
  620.         sub.levelCount = VK_REMAINING_MIP_LEVELS;
  621.         barrier.subresourceRange = sub;
  622.  
  623.         vkCmdPipelineBarrier(buffer, srcBind, dstBind,
  624.             0, 0, nullptr, 0, nullptr, 1, &barrier);
  625.     }
  626.  
  627.     void createCommandBuffers() {
  628.         commandBuffers.resize(swapChainImages.size());
  629.  
  630.         VkCommandBufferAllocateInfo allocInfo{};
  631.         allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  632.         allocInfo.commandPool = commandPool;
  633.         allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  634.         allocInfo.commandBufferCount = (uint32_t)commandBuffers.size();
  635.  
  636.         if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
  637.             throw std::runtime_error("failed to allocate command buffers!");
  638.         }
  639.  
  640.         for (size_t i = 0; i < commandBuffers.size(); i++) {
  641.             VkCommandBufferBeginInfo beginInfo{};
  642.             beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  643.  
  644.             if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
  645.                 throw std::runtime_error("failed to begin recording command buffer!");
  646.             }
  647.  
  648.  
  649.             recordImageBarrier(commandBuffers[i], swapChainImages[i],
  650.                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
  651.                 VK_ACCESS_MEMORY_WRITE_BIT,VK_ACCESS_SHADER_WRITE_BIT,
  652.                 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
  653.            
  654.             vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
  655.             vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
  656.             vkCmdDispatch(commandBuffers[i], 255, 255, 0);
  657.          
  658.             recordImageBarrier(commandBuffers[i], swapChainImages[i],
  659.                 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  660.                 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
  661.                 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  662.  
  663.            /* VkImageCopy copy{};
  664.             copy.dstOffset = { 0,0,0 };
  665.             copy.extent = { swapChainExtent.width, swapChainExtent.height,1};
  666.             copy.srcOffset = { 0,0,0 };
  667.  
  668.             VkImageSubresourceLayers subresource{};
  669.             subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  670.             subresource.baseArrayLayer = 0;
  671.             subresource.layerCount = 1;
  672.             subresource.mipLevel = 0;
  673.             copy.srcSubresource = subresource;
  674.             copy.dstSubresource = subresource;
  675.  
  676.             recordImageBarrier(commandBuffers[i], swapChainImages[i],
  677.                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
  678.                 VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_MEMORY_WRITE_BIT,
  679.                 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_HOST_BIT);
  680.  
  681.             vkCmdCopyImage(commandBuffers[i], renderTargetImages[i], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  682.                 swapChainImages[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,1,&copy);
  683.  
  684.             recordImageBarrier(commandBuffers[i], swapChainImages[i],
  685.                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  686.                 VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT,
  687.                 VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
  688.  
  689.                 */
  690.             if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
  691.                 throw std::runtime_error("failed to record command buffer!");
  692.             }
  693.         }
  694.     }
  695.  
  696.     void createSyncObjects() {
  697.         imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
  698.         renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
  699.         inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
  700.         imagesInFlight.resize(swapChainImages.size(), VK_NULL_HANDLE);
  701.  
  702.         VkSemaphoreCreateInfo semaphoreInfo{};
  703.         semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  704.  
  705.         VkFenceCreateInfo fenceInfo{};
  706.         fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
  707.         fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
  708.  
  709.         for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
  710.             if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
  711.                 vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
  712.                 vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
  713.                 throw std::runtime_error("failed to create synchronization objects for a frame!");
  714.             }
  715.         }
  716.     }
  717.  
  718.     void createDescriptorSetLayout() {
  719.         VkDescriptorSetLayoutBinding uboLayoutBinding{};
  720.         uboLayoutBinding.binding = 0;
  721.         uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  722.         uboLayoutBinding.descriptorCount = 1;
  723.         uboLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
  724.         uboLayoutBinding.pImmutableSamplers = &imageSampler;
  725.  
  726.         VkDescriptorSetLayoutCreateInfo layoutInfo{};
  727.         layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  728.         layoutInfo.bindingCount = 1;
  729.         layoutInfo.pBindings = &uboLayoutBinding;
  730.  
  731.         if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
  732.             throw std::runtime_error("failed to create descriptor set layout!");
  733.         }
  734.     }
  735.  
  736.     void createDescriptorPool() {
  737.         VkDescriptorPoolSize poolSize{};
  738.         poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  739.         poolSize.descriptorCount = static_cast<uint32_t>(swapChainImages.size());
  740.  
  741.         VkDescriptorPoolCreateInfo poolInfo{};
  742.         poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
  743.         poolInfo.poolSizeCount = 1;
  744.         poolInfo.pPoolSizes = &poolSize;
  745.         poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
  746.         if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
  747.             throw std::runtime_error("failed to create descriptor pool!");
  748.         }
  749.     }
  750.  
  751.     void createDescriptorSets() {
  752.         std::vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), descriptorSetLayout);
  753.         VkDescriptorSetAllocateInfo allocInfo{};
  754.         allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  755.         allocInfo.descriptorPool = descriptorPool;
  756.         allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
  757.         allocInfo.pSetLayouts = layouts.data();
  758.  
  759.         descriptorSets.resize(swapChainImages.size());
  760.         if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
  761.             throw std::runtime_error("failed to allocate descriptor sets!");
  762.         }
  763.        
  764.         VkSamplerCreateInfo samplerInfo{};
  765.         samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
  766.         samplerInfo.magFilter = VK_FILTER_LINEAR;
  767.         samplerInfo.minFilter = VK_FILTER_LINEAR;
  768.         samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
  769.         samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
  770.         samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
  771.         samplerInfo.anisotropyEnable = VK_FALSE;
  772.         samplerInfo.maxAnisotropy = 16.0f;
  773.         samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
  774.         samplerInfo.unnormalizedCoordinates = VK_FALSE;
  775.         samplerInfo.compareEnable = VK_FALSE;
  776.         samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
  777.         samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
  778.         samplerInfo.mipLodBias = 0.0f;
  779.         samplerInfo.minLod = 0.0f;
  780.         samplerInfo.maxLod = 0.0f;
  781.  
  782.         vkCreateSampler(device, &samplerInfo, nullptr, &imageSampler);
  783.  
  784.         for (size_t i = 0; i < swapChainImages.size(); i++) {
  785.             VkDescriptorImageInfo info{};
  786.             info.imageView = swapChainImageViews[i];
  787.             info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
  788.             info.sampler = imageSampler;
  789.  
  790.             VkWriteDescriptorSet descriptorWrite{};
  791.             descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  792.             descriptorWrite.dstSet = descriptorSets[i];
  793.             descriptorWrite.dstBinding = 0;
  794.             descriptorWrite.dstArrayElement = 0;
  795.             descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  796.             descriptorWrite.descriptorCount = 1;
  797.             descriptorWrite.pImageInfo = &info;
  798.  
  799.             vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
  800.          
  801.         }
  802.     }
  803.  
  804.     void drawFrame() {
  805.         vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
  806.  
  807.         uint32_t imageIndex;
  808.         VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
  809.  
  810.         if (result == VK_ERROR_OUT_OF_DATE_KHR) {
  811.             recreateSwapChain();
  812.             return;
  813.         }
  814.         else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
  815.             throw std::runtime_error("failed to acquire swap chain image!");
  816.         }
  817.  
  818.         if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
  819.             vkWaitForFences(device, 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);
  820.         }
  821.         imagesInFlight[imageIndex] = inFlightFences[currentFrame];
  822.  
  823.         VkSubmitInfo submitInfo{};
  824.         submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  825.  
  826.         VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
  827.         VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
  828.         submitInfo.waitSemaphoreCount = 1;
  829.         submitInfo.pWaitSemaphores = waitSemaphores;
  830.         submitInfo.pWaitDstStageMask = waitStages;
  831.  
  832.         submitInfo.commandBufferCount = 1;
  833.         submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
  834.  
  835.         VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };
  836.         submitInfo.signalSemaphoreCount = 1;
  837.         submitInfo.pSignalSemaphores = signalSemaphores;
  838.  
  839.         vkResetFences(device, 1, &inFlightFences[currentFrame]);
  840.  
  841.         if (vkQueueSubmit(computeQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
  842.             throw std::runtime_error("failed to submit draw command buffer!");
  843.         }
  844.  
  845.         VkPresentInfoKHR presentInfo{};
  846.         presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  847.  
  848.         presentInfo.waitSemaphoreCount = 1;
  849.         presentInfo.pWaitSemaphores = signalSemaphores;
  850.  
  851.         VkSwapchainKHR swapChains[] = { swapChain };
  852.         presentInfo.swapchainCount = 1;
  853.         presentInfo.pSwapchains = swapChains;
  854.  
  855.         presentInfo.pImageIndices = &imageIndex;
  856.  
  857.         result = vkQueuePresentKHR(presentQueue, &presentInfo);
  858.  
  859.         if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
  860.             framebufferResized = false;
  861.             recreateSwapChain();
  862.         }
  863.         else if (result != VK_SUCCESS) {
  864.             throw std::runtime_error("failed to present swap chain image!");
  865.         }
  866.  
  867.         currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
  868.     }
  869.  
  870.     VkShaderModule createShaderModule(const std::vector<char>& code) {
  871.         VkShaderModuleCreateInfo createInfo{};
  872.         createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
  873.         createInfo.codeSize = code.size();
  874.         createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
  875.  
  876.         VkShaderModule shaderModule;
  877.         if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
  878.             throw std::runtime_error("failed to create shader module!");
  879.         }
  880.  
  881.         return shaderModule;
  882.     }
  883.  
  884.     bool CheckFormatSupport(VkPhysicalDevice gpu, VkFormat format, VkFormatFeatureFlags requestedSupport) {
  885.         VkFormatProperties vkFormatProperties;
  886.         vkGetPhysicalDeviceFormatProperties(gpu, format, &vkFormatProperties);
  887.         return (vkFormatProperties.optimalTilingFeatures & requestedSupport) == requestedSupport;
  888.     }
  889.  
  890.     VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
  891.         for (const auto& availableFormat : availableFormats) {
  892.             if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
  893.                 return availableFormat;
  894.             }
  895.         }
  896.  
  897.         return availableFormats[0];
  898.     }
  899.  
  900.     VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
  901.         for (const auto& availablePresentMode : availablePresentModes) {
  902.             if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
  903.                 return availablePresentMode;
  904.             }
  905.         }
  906.  
  907.         return VK_PRESENT_MODE_FIFO_KHR;
  908.     }
  909.  
  910.     VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
  911.         if (capabilities.currentExtent.width != UINT32_MAX) {
  912.             return capabilities.currentExtent;
  913.         }
  914.         else {
  915.             int width, height;
  916.             glfwGetFramebufferSize(window, &width, &height);
  917.  
  918.             VkExtent2D actualExtent = {
  919.                 static_cast<uint32_t>(width),
  920.                 static_cast<uint32_t>(height)
  921.             };
  922.  
  923.             actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
  924.             actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
  925.  
  926.             return actualExtent;
  927.         }
  928.     }
  929.  
  930.     SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
  931.         SwapChainSupportDetails details;
  932.  
  933.         vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
  934.  
  935.         uint32_t formatCount;
  936.         vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
  937.  
  938.         if (formatCount != 0) {
  939.             details.formats.resize(formatCount);
  940.             vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
  941.         }
  942.  
  943.         uint32_t presentModeCount;
  944.         vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
  945.        
  946.         if (presentModeCount != 0) {
  947.             details.presentModes.resize(presentModeCount);
  948.             vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
  949.         }
  950.  
  951.         return details;
  952.     }
  953.  
  954.     bool isDeviceSuitable(VkPhysicalDevice device) {
  955.         QueueFamilyIndices indices = findQueueFamilies(device);
  956.  
  957.         bool extensionsSupported = checkDeviceExtensionSupport(device);
  958.  
  959.         bool swapChainAdequate = false;
  960.         if (extensionsSupported) {
  961.             SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
  962.             swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
  963.         }
  964.  
  965.         return indices.isComplete() && extensionsSupported && swapChainAdequate;
  966.     }
  967.  
  968.     bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
  969.         uint32_t extensionCount;
  970.         vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
  971.  
  972.         std::vector<VkExtensionProperties> availableExtensions(extensionCount);
  973.         vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
  974.  
  975.         std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
  976.  
  977.         for (const auto& extension : availableExtensions) {
  978.             requiredExtensions.erase(extension.extensionName);
  979.         }
  980.  
  981.         return requiredExtensions.empty();
  982.     }
  983.  
  984.     QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
  985.         QueueFamilyIndices indices;
  986.  
  987.         uint32_t queueFamilyCount = 0;
  988.         vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
  989.  
  990.         std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
  991.         vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
  992.  
  993.         int i = 0;
  994.         for (const auto& queueFamily : queueFamilies) {
  995.             if (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT) {
  996.                 indices.computeFamily = i;
  997.             }
  998.  
  999.             VkBool32 presentSupport = false;
  1000.             vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
  1001.  
  1002.             if (presentSupport) {
  1003.                 indices.presentFamily = i;
  1004.             }
  1005.  
  1006.             if (indices.isComplete()) {
  1007.                 break;
  1008.             }
  1009.  
  1010.             i++;
  1011.         }
  1012.  
  1013.         return indices;
  1014.     }
  1015.  
  1016.     std::vector<const char*> getRequiredExtensions() {
  1017.         uint32_t glfwExtensionCount = 0;
  1018.         const char** glfwExtensions;
  1019.         glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
  1020.  
  1021.         std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
  1022.  
  1023.         if (enableValidationLayers) {
  1024.             extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
  1025.         }
  1026.  
  1027.         return extensions;
  1028.     }
  1029.  
  1030.     bool checkValidationLayerSupport() {
  1031.         uint32_t layerCount;
  1032.         vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
  1033.  
  1034.         std::vector<VkLayerProperties> availableLayers(layerCount);
  1035.         vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
  1036.  
  1037.         for (const char* layerName : validationLayers) {
  1038.             bool layerFound = false;
  1039.  
  1040.             for (const auto& layerProperties : availableLayers) {
  1041.                 if (strcmp(layerName, layerProperties.layerName) == 0) {
  1042.                     layerFound = true;
  1043.                     break;
  1044.                 }
  1045.             }
  1046.  
  1047.             if (!layerFound) {
  1048.                 return false;
  1049.             }
  1050.         }
  1051.  
  1052.         return true;
  1053.     }
  1054.  
  1055.     static std::vector<char> readFile(const std::string& filename) {
  1056.         std::ifstream file(filename, std::ios::ate | std::ios::binary);
  1057.  
  1058.         if (!file.is_open()) {
  1059.             throw std::runtime_error("failed to open file!");
  1060.         }
  1061.  
  1062.         size_t fileSize = (size_t)file.tellg();
  1063.         std::vector<char> buffer(fileSize);
  1064.  
  1065.         file.seekg(0);
  1066.         file.read(buffer.data(), fileSize);
  1067.  
  1068.         file.close();
  1069.  
  1070.         return buffer;
  1071.     }
  1072.  
  1073.     static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
  1074.         std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
  1075.  
  1076.         return VK_FALSE;
  1077.     }
  1078. };
  1079.  
  1080. int main() {
  1081.     HelloTriangleApplication app;
  1082.  
  1083.     try {
  1084.         app.run();
  1085.     }
  1086.     catch (const std::exception& e) {
  1087.         std::cerr << e.what() << std::endl;
  1088.         return EXIT_FAILURE;
  1089.     }
  1090.  
  1091.     return EXIT_SUCCESS;
  1092. }