From 158f8c76df28d543796f883fee1931832f8516e8 Mon Sep 17 00:00:00 2001 From: "re.kovalev" Date: Mon, 14 Mar 2022 18:09:25 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BE=D0=BF=D0=B8=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=20=D1=81=20=D1=80=D0=B5=D0=BF?= =?UTF-8?q?=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D1=8F=2005?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 13 +- .vscode/c_cpp_properties.json | 18 + .vscode/settings.json | 50 ++ .vscode/tasks.json | 41 ++ glfw3.dll | Bin 0 -> 285696 bytes include/PhysicalDevice.h | 17 + include/Queue.h | 13 + include/Surface.h | 21 + include/Vertex.h | 12 + include/macroses.h | 1 + include/vk.h | 58 +++ shaders/shader.frag | 9 + shaders/shader.vert | 11 + src/main.cpp | 53 ++ src/vk.cpp | 922 ++++++++++++++++++++++++++++++++++ 15 files changed, 1228 insertions(+), 11 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 glfw3.dll create mode 100644 include/PhysicalDevice.h create mode 100644 include/Queue.h create mode 100644 include/Surface.h create mode 100644 include/Vertex.h create mode 100644 include/macroses.h create mode 100644 include/vk.h create mode 100644 shaders/shader.frag create mode 100644 shaders/shader.vert create mode 100644 src/main.cpp create mode 100644 src/vk.cpp diff --git a/.gitignore b/.gitignore index e257658..bf75e78 100644 --- a/.gitignore +++ b/.gitignore @@ -12,23 +12,14 @@ *.gch *.pch -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - # Fortran module files *.mod *.smod -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - # Executables *.exe *.out *.app +# SPIR-V shaders +*.spv \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..bc50ed2 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "some_name", + "includePath": [ + "${workspaceFolder}/include", + "C:/VulkanSDK/1.2.189.2/Include", + "${workspaceFolder}/../dependencies/GLFW/include", + "${workspaceFolder}/../dependencies/glm" + ], + "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..3513148 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,50 @@ +{ + "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", + "list": "cpp", + "unordered_set": "cpp", + "map": "cpp", + "set": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..82d8283 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "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", + "-I${workspaceRoot}/../dependencies/glm", + "-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 0000000000000000000000000000000000000000..f0f4e36689b6e5cf785dfe70c8a91a6a36bea959 GIT binary patch literal 285696 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 Ac>n+a literal 0 HcmV?d00001 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/Vertex.h b/include/Vertex.h new file mode 100644 index 0000000..fcc5205 --- /dev/null +++ b/include/Vertex.h @@ -0,0 +1,12 @@ +#ifndef VERTEX_H +#define VERTEX_H + +#include + +typedef struct _Vertex +{ + glm::vec2 position; + glm::vec3 color; +} Vertex; + +#endif // VERTEX_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..1119179 --- /dev/null +++ b/include/vk.h @@ -0,0 +1,58 @@ +#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; // Информация об изображениях из списка показа + VkRenderPass renderPass; // Проходы рендера + VkPipelineLayout pipelineLayout; // Раскладка конвейера + VkPipeline graphicsPipeline; // Графический конвейер + VkCommandPool commandPool; // Пул команд + std::vector commandBuffers; // Буферы команд + VkBuffer vertexBuffer; // Буфер вершин + VkDeviceMemory vertexBufferMemory; // Память буфера вершин + VkBuffer indexBuffer; // Буфер индексов + VkDeviceMemory indexBufferMemory; // Память буфера индексов + + // Структура для хранения флагов + 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); // Создание цепочки показа + void createRenderpass(); // Создание проходов рендера + VkShaderModule createShaderModule(const char * filename); // Создание шейдерного модуля + void createGraphicPipeline(); // Создание графического конвеера + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory); // Создание произвольного буфера данных + void createCommandPool(); // Создание пула команд + void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); // Копирование между буферами данных + void createVertexBuffer(); // Создание буфера вершин + void createIndexBuffer(); // Создание буфера индексов +}; + +#endif // VK_H \ No newline at end of file diff --git a/shaders/shader.frag b/shaders/shader.frag new file mode 100644 index 0000000..13009da --- /dev/null +++ b/shaders/shader.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/shaders/shader.vert b/shaders/shader.vert new file mode 100644 index 0000000..cb40e1e --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; + +layout(location = 0) out vec3 fragColor; + +void main() { + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; +} \ 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..e766e15 --- /dev/null +++ b/src/vk.cpp @@ -0,0 +1,922 @@ +#include "vk.h" +#include "Vertex.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); // Создание списка показа + createRenderpass(); // Создание проходов рендера + createGraphicPipeline(); // Создание графического конвейера + createCommandPool(); // Создание пула команд + createVertexBuffer(); // Создание буфера вершин + createIndexBuffer(); // Создание буфера индексов +} + +// завершение работы +void Vulkan::destroy() +{ + vkDestroyBuffer(logicalDevice, indexBuffer, nullptr); // Уничтожение буфера индексов + vkFreeMemory(logicalDevice, indexBufferMemory, nullptr); // Освобождение памяти буфера индексов + + vkDestroyBuffer(logicalDevice, vertexBuffer, nullptr); // Уничтожение буфера вершин + vkFreeMemory(logicalDevice, vertexBufferMemory, nullptr); // Освобождение памяти буфера вершин + + vkDestroyCommandPool(logicalDevice, commandPool, nullptr); // Уничтожение командного пула + + vkDestroyPipeline(logicalDevice, graphicsPipeline, nullptr); // Уничтожение графического конвейера + vkDestroyPipelineLayout(logicalDevice, pipelineLayout, nullptr); // Уничтожение раскладки графического конвейера + vkDestroyRenderPass(logicalDevice, renderPass, nullptr); // Уничтожение проходов рендера + + // Уничтожение информации о изображениях списка показа + 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"); + } + } +} + +// Создание проходов рендера +void Vulkan::createRenderpass() +{ + // Информация о прикреплении + VkAttachmentDescription colorAttachment{}; + colorAttachment.format = surface.selectedFormat.format; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + // Информация о выходном прикреплении + VkAttachmentReference colorAttachmentRef{}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // Информация о подпроходе + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + // Зависимости подпрохода + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + // Информация о создаваемом проходе рендера + VkRenderPassCreateInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + // Создание проходов рендера + if (vkCreateRenderPass(logicalDevice, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create render pass"); + } + +} + +#include +// Считывание бинарного файла, содержащего шейдер +void readFile(const char * filename, std::vector& buffer) +{ + // откроем файл как бинарный и установим курсор в конец файла + std::ifstream file(filename, std::ios::ate | std::ios::binary); + // если файл не открыт - генерируем исключение + if (!file.is_open()) + { + throw std::runtime_error("Can't open file"); + } + // определим размер файла + size_t fileSize = (size_t) file.tellg(); + // создадим буфер + buffer.resize(fileSize); + + // перенесем курсор в начало файла + file.seekg(0); + // считаем данные в буфер + file.read(buffer.data(), fileSize); + // закроем файл + file.close(); +} + +// Создание шейдерного модуля +VkShaderModule Vulkan::createShaderModule(const char * filename) +{ + // буфер для чтения из файла + std::vector buffer; + // считаем шейдер из файла + readFile(filename, buffer); + + // Информация о создаваемом шейдерном модуле + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = buffer.size(); + createInfo.pCode = reinterpret_cast(buffer.data()); + + // Создание шейдерного модуля + VkShaderModule shaderModule; + if (vkCreateShaderModule(logicalDevice, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { + throw std::runtime_error("Unable to create shader module"); + } + + return shaderModule; +} + +// Создание графического конвеера +void Vulkan::createGraphicPipeline() +{ + // Входные данные вершин + VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + + // Привязка + VkVertexInputBindingDescription bindingDescription{}; + bindingDescription.binding = 0; + bindingDescription.stride = sizeof(Vertex); + bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + // Описание атрибута + VkVertexInputAttributeDescription attributeDescriptions[2]; + + attributeDescriptions[0].binding = 0; + attributeDescriptions[0].location = 0; + attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + attributeDescriptions[0].offset = offsetof(Vertex, position); + + attributeDescriptions[1].binding = 0; + attributeDescriptions[1].location = 1; + attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attributeDescriptions[1].offset = offsetof(Vertex, color); + + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.vertexAttributeDescriptionCount = 2; + vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; + vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions; + + // Входной сборщик + VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + // Область просмотра + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = surface.selectedExtent.width; + viewport.height = surface.selectedExtent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + // Прямоугольник отсечения + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = surface.selectedExtent; + + // Состояние области просмотра + VkPipelineViewportStateCreateInfo viewportState{}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + // Растеризатор + VkPipelineRasterizationStateCreateInfo rasterizer{}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + + // Мультисэмплинг + VkPipelineMultisampleStateCreateInfo multisampling{}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + // Смешивание цветов для буфера + VkPipelineColorBlendAttachmentState colorBlendAttachment{}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.blendEnable = VK_FALSE; + + // Глобальные настройки смешивания цветов + VkPipelineColorBlendStateCreateInfo colorBlending{}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.blendConstants[0] = 0.0f; + colorBlending.blendConstants[1] = 0.0f; + colorBlending.blendConstants[2] = 0.0f; + colorBlending.blendConstants[3] = 0.0f; + + // раскладка конвейера + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 0; + pipelineLayoutInfo.pushConstantRangeCount = 0; + + if (vkCreatePipelineLayout(logicalDevice, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create pipeline layout"); + } + + // Создание шейдеров + VkShaderModule vertShaderModule = createShaderModule("shaders/vert.spv"); + VkShaderModule fragShaderModule = createShaderModule("shaders/frag.spv"); + + VkPipelineShaderStageCreateInfo vertShaderStageInfo{}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertShaderModule; + vertShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo fragShaderStageInfo{}; + fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = fragShaderModule; + fragShaderStageInfo.pName = "main"; + + // Шейдерные стадии + VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; + + + // Информация о создаваемом конвейере + VkGraphicsPipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.layout = pipelineLayout; + pipelineInfo.renderPass = renderPass; + pipelineInfo.subpass = 0; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + + // Создание графического конвейера + if (vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create graphics pipeline"); + } + + // Удаление шейдерных модулей + vkDestroyShaderModule(logicalDevice, fragShaderModule, nullptr); + vkDestroyShaderModule(logicalDevice, vertShaderModule, nullptr); +} + +// Создание произвольного буфера данных +void Vulkan::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) +{ + // Информация о создаваемом буфере + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + // Создание буфера + if (vkCreateBuffer(logicalDevice, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create buffer"); + } + + // Требования к памяти + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(logicalDevice, buffer, &memRequirements); + + // Поиск индекса типа подходящей памяти + uint32_t index_memory; + for (index_memory = 0; index_memory < physicalDevice.memory.memoryTypeCount; index_memory++) + { + if ((memRequirements.memoryTypeBits & (1 << index_memory)) + && (physicalDevice.memory.memoryTypes[index_memory].propertyFlags & properties) == properties) + { + break; + } + } + + // Если индекс равен размеру массива - поиск не удался и нужно выдать исключение + if (index_memory == physicalDevice.memory.memoryTypeCount) + throw std::runtime_error("Unable to find suitable memory type"); + + // Информация о выделяемой памяти + VkMemoryAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = index_memory; + + // Выделение памяти + if (vkAllocateMemory(logicalDevice, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) + { + throw std::runtime_error("Unable to allocate buffer memory"); + } + + // Привязка выделенной памяти к буферу + vkBindBufferMemory(logicalDevice, buffer, bufferMemory, 0); +} + +// Создание пула команд +void Vulkan::createCommandPool() +{ + // Информация о создаваемом командном пуле + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + poolInfo.queueFamilyIndex = queue.index; + + // Создание командного пула + if (vkCreateCommandPool(logicalDevice, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) + { + throw std::runtime_error("Unable to create graphics command pool"); + } + + // Выделим память под буферы команд + commandBuffers.resize(swapChainImages.size()); + + // Информация о выделяемых буферах + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = (uint32_t) commandBuffers.size(); + + // Выделение буферов команд из пула команд + if (vkAllocateCommandBuffers(logicalDevice, &allocInfo, commandBuffers.data()) != VK_SUCCESS) + { + throw std::runtime_error("Unable to allocate command buffers"); + } +} + +// Копирование между буферами данных +void Vulkan::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) +{ + // Информация о выделяемом буфере команд + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = commandPool; + allocInfo.commandBufferCount = 1; + + // Дескриптор и выделение буфера команд + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(logicalDevice, &allocInfo, &commandBuffer); + + // Начало записи команд + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + // Операция копирования + VkBufferCopy copyRegion{}; + copyRegion.size = size; + vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region); + + // Конец записи команд + vkEndCommandBuffer(commandBuffer); + + // Информация о запускаемых буферах команд + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + // Запуск командного буфера копирования и ожидание завершения + vkQueueSubmit(queue.descriptor, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(queue.descriptor); + + // Освобождение командного буфера копирования + vkFreeCommandBuffers(logicalDevice, commandPool, 1, &commandBuffer); +} + +// Создание вершинного буфера +void Vulkan::createVertexBuffer() +{ + //Вершины, записываемые в буфер + Vertex vertices[] = { + { {-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f} }, + { { 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f} }, + { { 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f} }, + { {-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f} } + }; + // Размер буфера в байтах + VkDeviceSize bufferSize = sizeof(Vertex) * 4; + + // Промежуточный буфер для переноса на устройство + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); + + // Отображение памяти буфера + void* data; + vkMapMemory(logicalDevice, stagingBufferMemory, 0, bufferSize, 0, &data); + // Копирование вершин в промежуточный буфер + memcpy(data, vertices, (size_t) bufferSize); + // Прекращение отображения памяти буфера + vkUnmapMemory(logicalDevice, stagingBufferMemory); + + // Создание буфера вершин + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); + // Копирование из промежуточного в буфер вершин + copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + // Освобождение памяти и уничтожение буферов + vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr); + vkFreeMemory(logicalDevice, stagingBufferMemory, nullptr); +} + +// Создание буфера индексов +void Vulkan::createIndexBuffer() +{ + // Индексы, записываемые в буфер + uint16_t indices[] = {0, 1, 2, 2, 3, 0}; + // Размер буфера в байтах + VkDeviceSize bufferSize = sizeof(uint16_t) * 6; + + // Промежуточный буфер для переноса на устройство + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); + + // Отображение памяти буфера + void* data; + vkMapMemory(logicalDevice, stagingBufferMemory, 0, bufferSize, 0, &data); + // Копирование вершин в промежуточный буфер + memcpy(data, indices, (size_t) bufferSize); + // Прекращение отображения памяти буфера + vkUnmapMemory(logicalDevice, stagingBufferMemory); + + // Создание буфера вершин + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); + // Копирование из промежуточного в буфер вершин + copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + // Освобождение памяти и уничтожение буферов + vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr); + vkFreeMemory(logicalDevice, stagingBufferMemory, nullptr); +}