diff --git a/.gitignore b/.gitignore index e257658..dd4c5db 100644 --- a/.gitignore +++ b/.gitignore @@ -12,21 +12,10 @@ *.gch *.pch -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - # Fortran module files *.mod *.smod -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - # Executables *.exe *.out diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..47ba8c3 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "some_name", + "includePath": [ + "${workspaceFolder}/include", + "C:/VulkanSDK/1.2.189.2/Include", + "${workspaceFolder}/../dependencies/GLFW/include" + ], + "compilerPath": "C:/MinGW/bin/g++.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x86" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0e1b4a0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,46 @@ +{ + "files.associations": { + "vector": "cpp", + "array": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "cstring": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..bb37bab --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,40 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++.exe сборка активного файла", + "command": "C:/MinGW/bin/g++.exe", + "args": [ + "-fdiagnostics-color=always", + "${workspaceRoot}/src/*.cpp", + + "-I${workspaceRoot}/include", + + "--std=c++11", + + "-IC:/VulkanSDK/1.2.189.2/Include", + "-LC:/VulkanSDK/1.2.189.2/Lib32", + + "-I${workspaceRoot}/../dependencies/GLFW/include", + "-L${workspaceRoot}/../dependencies/GLFW/lib-mingw", + "-static", + "-lvulkan-1", + "-lglfw3dll", + "-o", + "${workspaceRoot}/${workspaceFolderBasename}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Задача создана отладчиком." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/glfw3.dll b/glfw3.dll new file mode 100644 index 0000000..f0f4e36 Binary files /dev/null and b/glfw3.dll differ diff --git a/include/PhysicalDevice.h b/include/PhysicalDevice.h new file mode 100644 index 0000000..48f51bd --- /dev/null +++ b/include/PhysicalDevice.h @@ -0,0 +1,17 @@ +#ifndef PHYSICALDEVICE_H +#define PHYSICALDEVICE_H + +#include + +#include + +typedef struct _PhysicalDevice +{ + VkPhysicalDevice device; // устройство + VkPhysicalDeviceProperties properties; // параметры + VkPhysicalDeviceFeatures features; // функции + VkPhysicalDeviceMemoryProperties memory; // память + std::vector queueFamilyProperties; // семейства очередей +} PhysicalDevice; + +#endif // PHYSICALDEVICE_H diff --git a/include/Queue.h b/include/Queue.h new file mode 100644 index 0000000..59b6e6f --- /dev/null +++ b/include/Queue.h @@ -0,0 +1,13 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include + +typedef struct _Queue +{ + uint32_t index; + VkQueue descriptor; + VkQueueFamilyProperties properties; +} Queue; + +#endif // QUEUE_H diff --git a/include/Surface.h b/include/Surface.h new file mode 100644 index 0000000..1946e48 --- /dev/null +++ b/include/Surface.h @@ -0,0 +1,21 @@ +#ifndef SURFACE_H +#define SURFACE_H + +#include + +#include + +typedef struct _Surface +{ + VkSurfaceKHR surface; // Поверхность окна + VkSurfaceCapabilitiesKHR capabilities; // общая информация + std::vector formats; // формат поверхности + std::vector presentModes; // режим показа + // Данные о списке показа + VkSurfaceFormatKHR selectedFormat; // выбранный формат поверхности + VkPresentModeKHR selectedPresentMode; // выбранный режим показа + VkExtent2D selectedExtent; // выбранное разрешение + uint32_t imageCount; // количество изображений +} Surface; + +#endif // SURFACE_H \ No newline at end of file diff --git a/include/macroses.h b/include/macroses.h new file mode 100644 index 0000000..70bd360 --- /dev/null +++ b/include/macroses.h @@ -0,0 +1 @@ +#define CLAMP(min, value, max) (value > min) ? min : (max < value) ? max : value; \ No newline at end of file diff --git a/include/vk.h b/include/vk.h new file mode 100644 index 0000000..e09ae03 --- /dev/null +++ b/include/vk.h @@ -0,0 +1,41 @@ +#ifndef VK_H +#define VK_H + +#include +#include + +#include "PhysicalDevice.h" +#include "Surface.h" +#include "Queue.h" + +class Vulkan +{ + public: + void init(GLFWwindow* window); // инициализация + void destroy(); // завершение работы + private: + VkInstance instance; // Экземпляр Vulkan + PhysicalDevice physicalDevice; // Физическое устройство + VkDevice logicalDevice; // логическое устройство + Queue queue; // очередь + Surface surface; // Поверхность окна + VkSwapchainKHR swapChain; // Список показа + std::vector swapChainImages; // Изображения из списка показа + std::vector swapChainImageViews; // Информация об изображениях из списка показа + + // Структура для хранения флагов + struct + { + const bool VALIDATION = true; // Использование слоев проверки + } states; + + + void createInstance(); // Создание экземпяра Vulkan + void selectPhysicalDevice(std::vector &deviceExtensions); // Выбор физического устройства + void pickQueues(); // Выбор очередей + void createLogicalDevice(std::vector &deviceExtensions); // Создание логического устройства + void createWindowSurface(GLFWwindow* window); // Создание поверхности окна + void createSwapchain(GLFWwindow* window); // Создание цепочки показа +}; + +#endif // VK_H \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..846b86d --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,53 @@ +#include "vk.h" + + +#include + +void vkInit(); + +int main(int argc, char* argv[]) { + + // Инициализация GLFW + glfwInit(); + + // Проверка доступности Vulkan + if (glfwVulkanSupported()) + { + // объект класса-обертки Vulkan API + Vulkan vulkan; + + // Отключим создание контекста + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + // Отключим возможность изменения размеров окна + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + // Создание окна + GLFWwindow* window = glfwCreateWindow(800, 600, "Vulkan window", nullptr, nullptr); + + // Инициализация Vulkan API + vulkan.init(window); + + // Жизненный цикл + while(!glfwWindowShouldClose(window)) { + // Обработка событий + glfwPollEvents(); + } + + // Уничтожение окна + glfwDestroyWindow(window); + + // Завершение работы с Vulkan + vulkan.destroy(); + } + else + std::cout << "There is no Vulkan Supported\n"; + + // Завершение работы с GLFW + glfwTerminate(); + + return 0; +} + + + + + diff --git a/src/vk.cpp b/src/vk.cpp new file mode 100644 index 0000000..e939c8c --- /dev/null +++ b/src/vk.cpp @@ -0,0 +1,462 @@ +#include "vk.h" + +#include +#include +#include + +#include "macroses.h" + +// инициализация +void Vulkan::init(GLFWwindow* window) +{ + createInstance(); // Создание экземпяра + createWindowSurface(window); // Создание поверхности + // Расширения для устройства: имена задаются внутри фигурных скобок в кавычках + std::vector deviceExtensions({"VK_KHR_swapchain"}); + selectPhysicalDevice(deviceExtensions); // Выбор физического устройства + createLogicalDevice(deviceExtensions); // Создание физического устройства + createSwapchain(window); // Создание списка показа +} + +// завершение работы +void Vulkan::destroy() +{ + // Уничтожение информации о изображениях списка показа + for (auto & imageView : swapChainImageViews) + { + vkDestroyImageView(logicalDevice, imageView, nullptr); + } + + vkDestroySwapchainKHR(logicalDevice, swapChain, nullptr); // уничтожение цепочки показа + vkDestroySurfaceKHR(instance, surface.surface, nullptr); // уничтожение поверхности + vkDestroyDevice(logicalDevice, nullptr); // Уничтожение логического устройства + vkDestroyInstance(instance, nullptr); // Уничтожение экземпляра Vulkan +} + +#include +// Проверка слоев на доступность. Возвращает true, если все слои доступны +// по ссылке заполняет вектор недоступных слоев +bool checkValidationLayerSupport(std::vector requestedLayers, std::vector & unavailableLayers) +{ + bool layerAvailable; // флаг доступности слоя для цикла + + // Первым вызовом определим кол-во доступных слоев + uint32_t layerCount; + vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + + // Вторым вызовом запишем в вектор доступные слои + std::vector availableLayers(layerCount); + vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); + + // Цикл по запрошенным слоям + for (const char* layerName : requestedLayers) + { + layerAvailable = false; + + // Цикл по доступным слоям + for (const auto& layerProperties : availableLayers) + { + // Сравнение строк + if (strcmp(layerName, layerProperties.layerName) == 0) + { + layerAvailable = true; + break; + } + } + + // Если слой не найден то заносим в массив недоступных + if (!layerAvailable) { + unavailableLayers.push_back(layerName); + } + } + + return unavailableLayers.size() == 0; +} + +// Проверка слоев устройства на доступность. Возвращает true, если все слои доступны +// по ссылке заполняет вектор недоступных слоев +bool checkDeviceLayerSupport(VkPhysicalDevice physicalDevice, std::vector requestedLayers, std::vector & unavailableLayers) +{ + bool layerAvailable; // флаг доступности слоя для цикла + + // Первым вызовом определим кол-во доступных слоев + uint32_t layerCount; + vkEnumerateDeviceLayerProperties(physicalDevice, &layerCount, nullptr); + + // Вторым вызовом запишем в вектор доступные слои + std::vector availableLayers(layerCount); + vkEnumerateDeviceLayerProperties(physicalDevice, &layerCount, availableLayers.data()); + + // Цикл по запрошенным слоям + for (const char* layerName : requestedLayers) + { + layerAvailable = false; + + // Цикл по доступным слоям + for (const auto& layerProperties : availableLayers) + { + // Сравнение строк + if (strcmp(layerName, layerProperties.layerName) == 0) + { + layerAvailable = true; + break; + } + } + + // Если слой не найден то заносим в массив недоступных + if (!layerAvailable) { + unavailableLayers.push_back(layerName); + } + } + + return unavailableLayers.size() == 0; +} + +void Vulkan::createInstance() +{ + // Структура с данными о приложении + VkApplicationInfo appInfo{}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "Vulkan Notes"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "No Engine"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = VK_API_VERSION_1_0; + + // Структура с данными + VkInstanceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + + // Расширения для glfw + uint32_t glfwExtensionCount = 0; + const char** glfwExtensions; + glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + // Инициализируем вектор расширений тем, что требуется для glfw + std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); + + // Подключение других расширений + // extensions.push_back(ИМЯ_РАСШИРЕНИЯ); + + // Запишем данные об используемых расширениях в структуру + createInfo.enabledExtensionCount = static_cast(extensions.size()); + createInfo.ppEnabledExtensionNames = extensions.data(); + + // Подключение слоев + std::vector validationLayers = { + "VK_LAYER_KHRONOS_validation" + }; + + if (states.VALIDATION) + { + createInfo.enabledLayerCount = static_cast(validationLayers.size()); + createInfo.ppEnabledLayerNames = validationLayers.data(); + } + + // Проверим доступность слоев + std::vector unavailableLayers; + if (!checkValidationLayerSupport(validationLayers, unavailableLayers)) + { + std::cout << "Запрошены недоступные слои:\n"; + // Цикл по недоступным слоям + for (const char* layer : unavailableLayers) + std::cout << layer << "\n"; + // Отправим исключение об отсутствующем слое + throw std::runtime_error("Requested layer unavailable"); + } + + // Создание экземпляра Vulkan + VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); + if (result != VK_SUCCESS) + { // Отправим исключение в случае ошибок создания экземпляра + throw std::runtime_error("Instance create error"); + } +} + +#include +// Выбор физического устройства на основании требований +PhysicalDevice selectPhysicalDeviceByProperties(std::vector & devices, Surface & surface, std::vector &requestedExtensions) +{ + int i; + PhysicalDevice result; // физическое устройство (PhysicalDevice.h) + for (const auto& device : devices) + { + // Запомним устройство + result.device = device; + // Получаем данные + vkGetPhysicalDeviceProperties(device, &result.properties); + vkGetPhysicalDeviceFeatures(device, &result.features); + vkGetPhysicalDeviceMemoryProperties(device, &result.memory); + + // Данные по семействам очередей + uint32_t queueFamilyPropertiesCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyPropertiesCount, nullptr); + result.queueFamilyProperties.resize(queueFamilyPropertiesCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyPropertiesCount, result.queueFamilyProperties.data()); + + // Данные по расширениям + uint32_t extensionsCount = 0; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionsCount, nullptr); + std::vector extensions(extensionsCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionsCount, extensions.data()); + + int availableExtensionsCount = 0; + // подсчитаем совпадающие расширения + for (auto extension1 : requestedExtensions) + for (auto extension2 : extensions) + if (strcmp(extension1, extension2.extensionName) == 0) + { + availableExtensionsCount++; + break; + } + + // Получение информации о поверхности + VkSurfaceCapabilitiesKHR capabilities; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface.surface, &capabilities); + + // Получение форматов поверхности + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface.surface, &formatCount, nullptr); + std::vector formats(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface.surface, &formatCount, formats.data()); + + // Получение данных о поддерживаемых режимах показа + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface.surface, &presentModeCount, nullptr); + std::vector presentModes(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface.surface, &presentModeCount, presentModes.data()); + + // Если есть форматы и режимы показа, то на данном устройстве можно создать список показа + bool swapchainSupport = formatCount && presentModeCount; + + // Производим оценку + if (availableExtensionsCount == requestedExtensions.size() + && result.features.geometryShader + && 4000 < result.memory.memoryHeaps[0].size / 1000 / 1000 + && swapchainSupport) + { + // Заполним данные о поверхности + surface.capabilities = capabilities; + surface.formats = formats; + surface.presentModes = presentModes; + // Вернем устройство + return result; + } + } + // Если устройство не найдено - вернем пустую структуру + return PhysicalDevice(); +} + +// Выбор физического устройства +void Vulkan::selectPhysicalDevice(std::vector &deviceExtensions) +{ + // Узнаем количество доступных устройств + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); + + // Проверка на отсутствие физических устройств + if (deviceCount == 0) + { + throw std::runtime_error("Unable to find physical devices"); + } + + // Создадим вектор нужного размера и заполним его данными + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); + + // Выбор физического устройства на основании требований + physicalDevice = selectPhysicalDeviceByProperties(devices, surface, deviceExtensions); + + // Если не удалось выбрать подходящее требованием устройство - выдадим исключение + if (!physicalDevice.device) + { + throw std::runtime_error("failed to find a suitable GPU!"); + } +} + +// Выбор очередей +void Vulkan::pickQueues() +{ + queue.index = -1; + + for (int i = 0; i < physicalDevice.queueFamilyProperties.size(); i++) + { + // Проверка возможности вывода + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.device, i, surface.surface, &presentSupport); + // Проверка поддержки очередью графических операций + if (physicalDevice.queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT + && presentSupport) + { + queue.index = i; + queue.properties = physicalDevice.queueFamilyProperties[i]; + break; + } + } +} + +// Создание логического устройства +void Vulkan::createLogicalDevice(std::vector &deviceExtensions) +{ + // Выберем очереди + pickQueues(); + + // Приоритеты очередей + float priority[1] = {1}; + // Данные о необходимых очередях + VkDeviceQueueCreateInfo queueCreateInfo{}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = queue.index; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = priority; + + // слои для логического устройства + std::vector layers; + // Подключение других слоев + // layers.push_back(ИМЯ_СЛОЯ); + + // Проверим доступность слоев + std::vector unavailableLayers; + if (!checkDeviceLayerSupport(physicalDevice.device, layers, unavailableLayers)) + { + std::cout << "Запрошены недоступные слои:\n"; + // Цикл по недоступным слоям + for (const char* layer : unavailableLayers) + std::cout << layer << "\n"; + // Отправим исключение об отсутствующем слое + throw std::runtime_error("Requested layer unavailable"); + } + + // Данные о создаваемом логическом устройстве + VkDeviceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.pQueueCreateInfos = &queueCreateInfo; + createInfo.queueCreateInfoCount = 1; + createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + createInfo.enabledLayerCount = layers.size(); + createInfo.ppEnabledLayerNames = layers.data(); + createInfo.pEnabledFeatures = nullptr;//&physicalDevice.features; + + // Создание логического устройства + if (vkCreateDevice(physicalDevice.device, &createInfo, nullptr, &logicalDevice) != VK_SUCCESS) + { + // Отправим исключение в случае ошибок создания лог. устройства + throw std::runtime_error("failed to create logical device!"); + } + + // Получим дескриптор очереди логического устройства + vkGetDeviceQueue(logicalDevice, queueCreateInfo.queueFamilyIndex, 0, &queue.descriptor); +} + +// Создание поверхности окна +void Vulkan::createWindowSurface(GLFWwindow* window) +{ + if (glfwCreateWindowSurface(instance, window, nullptr, &surface.surface) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create window surface"); + } +} + +// Создание цепочки показа +void Vulkan::createSwapchain(GLFWwindow* window) +{ + // Выбор формата + surface.selectedFormat = surface.formats[0]; + for (auto& format : surface.formats) + { + if (format.format == VK_FORMAT_B8G8R8A8_SRGB + && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + surface.selectedFormat = format; + break; + } + } + + // Выбор режима показа + surface.selectedPresentMode = VK_PRESENT_MODE_FIFO_KHR; + for (auto& presentMode : surface.presentModes) + { + if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR) + { + surface.selectedPresentMode = presentMode; + break; + } + } + + // Выбор разрешения изображений + // Разрешение окна + int width, height; + glfwGetFramebufferSize(window, &width, &height); + // Выберем разрешение исходя из ограничений физического устройства + surface.selectedExtent.width = CLAMP( surface.capabilities.minImageExtent.width + , width + , surface.capabilities.maxImageExtent.width + ); + surface.selectedExtent.height = CLAMP( surface.capabilities.minImageExtent.height + , height + , surface.capabilities.maxImageExtent.height + ); + + // Выбор количества изображений в списке показа + surface.imageCount = surface.capabilities.minImageCount + 1; + // Если есть ограничение по максимуму изображений - применим его + if (surface.capabilities.maxImageCount) + surface.imageCount %= surface.capabilities.maxImageCount; + + // Заполнение данных о создаваемом списке показа + VkSwapchainCreateInfoKHR createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = surface.surface; + createInfo.minImageCount = surface.imageCount; + createInfo.imageFormat = surface.selectedFormat.format; + createInfo.imageColorSpace = surface.selectedFormat.colorSpace; + createInfo.imageExtent = surface.selectedExtent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.preTransform = surface.capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = surface.selectedPresentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; + + // Создание списка показа + if (vkCreateSwapchainKHR(logicalDevice, &createInfo, nullptr, &swapChain) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create swap chain"); + } + + // Получение изображений списка показа + vkGetSwapchainImagesKHR(logicalDevice, swapChain, &surface.imageCount, nullptr); + swapChainImages.resize(surface.imageCount); + vkGetSwapchainImagesKHR(logicalDevice, swapChain, &surface.imageCount, swapChainImages.data()); + + // Зададим размер массива в соответствии с количеством изображений + swapChainImageViews.resize(swapChainImages.size()); + // Для каждого изображения из списка показа + for (int i = 0; i < swapChainImages.size(); i++) + { + // Заполним данные о создаваемом объекте VkImageView + VkImageViewCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = swapChainImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = surface.selectedFormat.format; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + + // Создание VkImageView + if (vkCreateImageView(logicalDevice, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create image views"); + } + } +}