Расширения позволяют подключить различную дополнительную функциональность в приложении. Например, поскольку Vulkan — это API, который не зависит от конкретной платформы, то нам нужны расширения для взаимодействия с оконной системой. Для различных задач в Vulkan API есть свои расширения. Вообще расширения представляют структуру , которая имеет два поля:
typedef struct VkExtensionProperties {
char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; // имя расширения
uint32_t specVersion; // версия расширения
} VkExtensionProperties;
Чтобы получить список поддерживаемых расширений перед созданием объекта VKInstance, можно использовать функцию vkEnumerateInstanceExtensionProperties():
VkResult vkEnumerateInstanceExtensionProperties(
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
Эта функция принимает следующие параметры:
pLayerName: указатель на строку с имем слоя, из которого нужно извлечь расширения. Может быть NULL
pPropertyCount: количество расширений
pProperties: массив VkExtensionProperties для хранения сведений о расширениях. Может быть NULL
Например, получим все доступные расширения:
#include <vulkan/vulkan.h>
#include <iostream>
#include <vector>
int main() {
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
std::cout << "Available extensions:\n";
for (const auto& extension : extensions) {
std::cout << extension.extensionName << std::endl;
}
return 0;
}
Разберем код. Вначале получаем количество расширений, оставив все остальные параметры пустыми:
uint32_t extensionCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
Далее выделяем вектор для хранения данных расширения (для этого требуется подключить <vector>):
std::vector<VkExtensionProperties> extensions(extensionCount);
Затем мы можем запросить данные расширения:
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
Каждая структура VkExtensionProperties содержит имя и версию расширения. Мы можем перебрать их с помощью цикла:
std::cout << "Available extensions:\n";
for (const auto& extension : extensions) {
std::cout << extension.extensionName << std::endl;
}
В итоге у нас получится вывод типа следующего:
Available extensions: VK_KHR_device_group_creation VK_KHR_display VK_KHR_external_fence_capabilities VK_KHR_external_memory_capabilities VK_KHR_external_semaphore_capabilities VK_KHR_get_display_properties2 VK_KHR_get_physical_device_properties2 VK_KHR_get_surface_capabilities2 VK_KHR_surface VK_KHR_swapchain VK_KHR_wayland_surface VK_KHR_xcb_surface VK_KHR_xlib_surface VK_EXT_acquire_drm_display VK_EXT_acquire_xlib_display VK_EXT_debug_report VK_EXT_debug_utils VK_EXT_direct_mode_display VK_EXT_display_surface_counter VK_EXT_headless_surface VK_EXT_surface_maintenance1 VK_EXT_swapchain_colorspace VK_KHR_portability_enumeration VK_LUNARG_direct_driver_loading
При создании объекта VkInstance можно установить необходимые расширения и их количество. В данном случае мы пока не взаимодействуем ни с какой оконнной системой.
Но ради примера приведу работу с библиотекой GLFW для создания оконных приложений, которая имеет удобную встроенную функцию glfwGetRequiredInstanceExtensions(). Эта функция
возвращает расширения, необходимые для взаимодействия Vulkan с оконной системой GLFW. Пример установки подобных расширений:
#define GLFW_INCLUDE_VULKAN
// #include <vulkan/vulkan.h> // макрос GLFW_INCLUDE_VULKAN уже подключает Vulkan
#include <GLFW/glfw3.h>
#include <iostream>
int main() {
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
// 1) получаем расширения библиотеки GLFW для Vulkan
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
VkInstance instance; // объект, который надо создать
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
// 2) устанавливаем расширения
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
// создаем объект VkInstance
if(vkCreateInstance(&createInfo, nullptr, &instance)!= VK_SUCCESS){
std::cout << "Unable to create VKInstance" << std::endl;
return 1;
}
else(vkCreateInstance(&createInfo, nullptr, &instance)!= VK_SUCCESS){
std::cout << "VKInstance created" << std::endl;
}
// удаление VKInstance
vkDestroyInstance(instance, nullptr);
return 0;
}
Следует отметить, что если расширение по тем или иным причинам не поддерживается, то функция vkCreateInstance возвратит значение VK_ERROR_EXTENSION_NOT_PRESENT.