#include "vk.h" #include #include #include // инициализация void Vulkan::init() { createInstance(); // Создание экземпяра // Расширения для устройства: имена задаются внутри фигурных скобок в кавычках std::vector deviceExtensions({}); selectPhysicalDevice(deviceExtensions); // Выбор физического устройства createLogicalDevice(deviceExtensions); // Создание физического устройства } // завершение работы void Vulkan::destroy() { 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, 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; } // Производим оценку if (availableExtensionsCount == requestedExtensions.size() && result.features.geometryShader && 4000 < result.memory.memoryHeaps[0].size / 1000 / 1000) 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, deviceExtensions); // Если не удалось выбрать подходящее требованием устройство - выдадим исключение if (!physicalDevice.device) { throw std::runtime_error("failed to find a suitable GPU!"); } } void Vulkan::createLogicalDevice(std::vector &deviceExtensions) { // Приоритеты очередей float priority[1] = {1}; // Данные о необходимых очередях VkDeviceQueueCreateInfo queueCreateInfo{}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = physicalDevice.pickQueueFamily(VK_QUEUE_GRAPHICS_BIT); 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, &graphicalQueue); }