Целью Vulkan-HPP является предоставление привязки только C ++ для C ++ для улучшения опыта разработчиков Vulkan без введения стоимости выполнения CPU. Он добавляет такие функции, как безопасность типа для перечислений и битовых полей, поддержка контейнеров STL, исключения и простые перечисления.
| Платформа | Статус сборки |
|---|---|
| Linux |
Vulkan-HPP является частью Lunarg Vulkan SDK с версии 1.0.24. Просто #include <vulkan/vulkan.hpp> и вы готовы использовать привязки C ++. Если вы используете версию Vulkan, еще не поддерживаемую Vulkan SDK, вы можете найти последнюю версию заголовков здесь.
Для компиляции Vulkan-HPP требуется компилятор C ++ 11. Известно, что следующие компиляторы работают:
Для создания локальных образцов и тестов вам придется клонировать этот репозиторий и запустить CMAKE, чтобы создать необходимые файлы сборки
Установить зависимости.
Откройте оболочку, которая обеспечивает git и клонирует хранилище с помощью:
git clone --recurse-submodules https://github.com/KhronosGroup/Vulkan-Hpp.git
Измените текущий каталог на недавно созданный каталог Vulkan-HPP.
Создайте среду сборки с Cmake:
cmake -DVULKAN_HPP_SAMPLES_BUILD=ON -DVULKAN_HPP_SAMPLES_BUILD_WITH_LOCAL_VULKAN_HPP=ON -DVULKAN_HPP_TESTS_BUILD=ON -DVULKAN_HPP_TESTS_BUILD_WITH_LOCAL_VULKAN_HPP=ON -B build
Возможно, вам потребуется указать генератор через -G , для полного списка генераторов выполнить cmake -G .
vulkan.hpp из файла реестра vk.xml xml, добавьте -DVULKAN_HPP_RUN_GENERATOR=ON опцию в командную строку Cmake. Либо откройте сгенерированный проект с помощью IDE, например, Visual Studio, либо запустите процесс сборки с помощью cmake --build build --parallel .
Необязательно: обновить Vulkan-HPP и его подмодули выполняют git pull --recurse-submodules .
Вы можете скачать и установить Vulkan-HPP, используя VCPKG DevingDency Manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install vulkan-headersПорт Vulkan-HPP в VCPKG обновляется членами команды Microsoft и участниками сообщества. Если версия установлена на устаре, пожалуйста, создайте проблему или запрос на вытягивание в репозитории VCPKG.
Если программа Clang-формат найден CMAKE, определяется CLANG_FORMAT_EXECUTABLE , соответственно. В этом случае сгенерированный vulkan.hpp отформатируется с использованием файла .clang-format расположенного в корневом каталоге этого проекта. В противном случае он отформатирован как жесткий кодировку в генераторе.
File VulkanHpp.natvis предоставляет пользовательское представление на vk::Flags для Visual Studio. Если вы добавите этот файл в каталог NATVIS, специфичный для пользователя вашей установки Visual Studio (%UserProfile% Documents Visual Studio 2022 Визуализаторы), вы получаете vk::Flags хорошо отформатированы в своем отладчике со всеми вашими проектами Visual Studio.
Чтобы избежать столкновений имен с Vulkan C API, привязки C ++ находятся в пространстве имен vk . Следующие правила применяются к новому именованию:
Vk . В дополнение к этому первая буква функций является более низким.vkCreateInstance можно получить как vk::createInstance .VkImageTiling можно получить как vk::ImageTiling .VkImageCreateInfo можно получить как vk::ImageCreateInfo .VK_ и введите инфикс. Если тип перечисления является расширением, суффикс расширения был удален из значений перечисления.Во всех других случаях суффикс удлинения не был удален.
VK_IMAGETYPE_2D теперь vk::ImageType::e2D .VK_COLOR_SPACE_SRGB_NONLINEAR_KHR теперь vk::ColorSpaceKHR::eSrgbNonlinear .VK_STRUCTURE_TYPE_PRESENT_INFO_KHR теперь vk::StructureType::ePresentInfoKHR ._BIT также был удален. В некоторых случаях может потребоваться переместить Vulkan-HPP в пользовательское пространство имен. Это может быть достигнуто путем определения VULKAN_HPP_NAMESPACE прежде чем включить Vulkan-HPP.
Vulkan-HPP объявляет класс для всех ручек, чтобы обеспечить безопасность полного типа и добавить поддержку функций участников на ручках. Функция элемента была добавлена в класс Руководства для каждой функции, которая принимает соответствующий дескриптор в качестве первого параметра. Вместо vkBindBufferMemory(device, ...) можно написать device.bindBufferMemory(...) или vk::bindBufferMemory(device, ...) .
Существует дополнительный заголовок по имени vulkan_raii.hpp . Этот заголовок содержит классы обертки, соответствующие RAII, для типов ручки. То есть, например, тип ручки VkInstance , есть Raii-совместимая обертка vk::raii::Instance . Пожалуйста, посмотрите на образцы, используя эти классы в каталоге raii_samples.
На 64-битных платформах Vulkan-HPP поддерживает неявные преобразования между ручками C ++ Vulkan и ручками Culkan. На 32-разрядных платформах все неразличимые ручки определяются как uint64_t , что предотвращает проверки конверсии типа во время компиляции, которые могут застрять между несовместимыми типами ручки. Из-за того, что Vulkan-HPP не включает неявное преобразование для 32-разрядных платформ по умолчанию, и рекомендуется использовать static_cast для преобразования, подобного следующему: VkImage = static_cast<VkImage>(cppImage) чтобы предотвратить преобразование некоторого произвольного int в ручку или наоборот. Если вы разрабатываете свой код на 64-разрядной платформе, но хотите собрать свой код для 32-разрядной платформы, не добавляя явные листы, вы можете определить VULKAN_HPP_TYPESAFE_CONVERSION до 1 в вашей системе сборки или перед включением vulkan.hpp . На 64-битных платформах это определение по умолчанию установлено на 1 и может быть установлен на 0 для отключения неявных преобразований.
Функция Enum Scoped добавляет безопасность типа к флагам, но также предотвращает использование битов флагов в качестве входных данных для битовых операций, таких как & и | Полем
Как решение Vulkan-HPP предоставляет шаблон класса vk::Flags , который приносит стандартные операции, такие как &= , |= , & , и | к нашему общепьению. За исключением инициализации с 0 этот класс ведет себя точно так же, как обычная битмаска с улучшением, что невозможно установить биты, не указанные в соответствующем переводе в результате случайного. Вот несколько примеров для обработки Bitmask:
vk::ImageUsageFlags iu1; // initialize a bitmask with no bit set
vk::ImageUsageFlags iu2 = {}; // initialize a bitmask with no bit set
vk::ImageUsageFlags iu3 = vk::ImageUsageFlagBits::eColorAttachment; // initialize with a single value
vk::ImageUsageFlags iu4 = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage; // or two bits to get a bitmask
PipelineShaderStageCreateInfo ci ({} /* pass a flag without any bits set */ , ...); При построении ручки в Vulkan обычно должен создавать какую -то структуру CreateInfo , которая описывает новую ручку. Это может привести к довольно длительному коду, как можно увидеть в следующем примере Vulkan C:
VkImageCreateInfo ci;
ci. sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
ci.pNext = nullptr ;
ci.flags = ...some flags...;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_R8G8B8A8_UNORM;
ci.extent = VkExtent3D { width, height, 1 };
ci.mipLevels = 1 ;
ci.arrayLayers = 1 ;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ci.queueFamilyIndexCount = 0 ;
ci.pQueueFamilyIndices = 0 ;
ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vkCreateImage (device, &ci, allocator, &image); Есть две типичные проблемы, которые сталкиваются с Vulkan, которые сталкиваются при заполнении поля CreateInfo Struct By Field:
sType неверен.Особенно первого трудно обнаружить.
Vulkan-HPP предоставляет конструкторы для всех объектов CreateInfo , которые принимают один параметр для каждой переменной элемента. Таким образом, компилятор бросает ошибку компилятора, если значение было забыто. В дополнение к этому sType автоматически заполняется правильным значением, а pNext устанавливается на nullptr по умолчанию. Вот как выглядит тот же код с конструктором:
vk::ImageCreateInfo ci ({}, vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
{ width, height, 1 },
1 , 1 , vk::SampleCountFlagBits:: e1 ,
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive, 0 , nullptr , vk::ImageLayout::eUndefined);
vk::Image image = device.createImage(ci); С конструкторами для структур CreateInfo можно также перенести временные функции вульковских функциях, подобных этим:
vk::Image image = device.createImage({{}, vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
{ width, height, 1 },
1 , 1 , vk::SampleCountFlagBits:: e1 ,
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive, 0 , nullptr , vk::ImageLayout::eUndefined}); Начиная с C ++ 20, C ++ поддерживает назначенные инициализаторы. Поскольку эта функция требует, чтобы не иметь каких-либо издевательных или унаследованных конструкторов, вы должны #define VULKAN_HPP_NO_CONSTRUCTORS , которые удаляют все структуры и конструкторы союза из vulkan.hpp . Вместо этого вы можете использовать агрегатную инициализацию. Первые несколько линий VK в вашем источнике могут выглядеть как:
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo{ . pApplicationName = AppName,
. applicationVersion = 1 ,
. pEngineName = EngineName,
. engineVersion = 1 ,
. apiVersion = VK_API_VERSION_1_1 };
// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo{ . pApplicationInfo = &applicationInfo };вместо
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo (AppName, 1 , EngineName, 1 , VK_API_VERSION_1_1);
// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo ({}, &applicationInfo); Обратите внимание, что заказ обозначения должен соответствовать заказу объявления. Примечание также, что теперь вы можете явно установить член sType Structures. Это не необходимо (так как они правильно инициализированы по умолчанию) и не рекомендуются.
API Vulkan имеет несколько мест, которые требуют (Count, Pointer) в качестве двух функциональных аргументов, а C ++ имеет несколько контейнеров, которые идеально сочетаются с этой парой. Чтобы упростить разработку, привязки Vulkan-HPP заменили эти пары аргументов на шаблон класса vk::ArrayProxy , который принимает пустые массивы и одно значение, а также контейнеры STL std::initializer_list , std::array и std::vector как аргумент для строительства. Таким образом, одна сгенерированная версия Вулкана может принять различные входы без комбинаторного взрыва, который будет происходить при создании функции для каждого типа контейнера.
Вот несколько образцов кода о том, как использовать vk::ArrayProxy :
vk::CommandBuffer c;
// pass an empty array
c.setScissor( 0 , nullptr );
// pass a single value. Value is passed as reference
vk::Rect2D scissorRect = { { 0 , 0 }, { 640 , 480 } };
c.setScissor( 0 , scissorRect);
// pass a temporary value.
c.setScissor( 0 , { { 0 , 0 }, { 640 , 480 } });
// pass a fixed size array
vk::Rect2D scissorRects[ 2 ] = { { { 0 , 0 }, { 320 , 240 } }, { { 320 , 240 }, { 320 , 240 } } };
c.setScissor( 0 , scissorRects);
// generate a std::initializer_list using two rectangles from the stack. This might generate a copy of the rectangles.
vk::Rect2D scissorRect1 = { { 0 , 0 }, { 320 , 240 } };
vk::Rect2D scissorRect2 = { { 320 , 240 }, { 320 , 240 } };
c.setScissor( 0 , { scissorRect, scissorRect2 });
// construct a std::initializer_list using two temporary rectangles.
c.setScissor( 0 , { { { 0 , 0 }, { 320 , 240 } },
{ { 320 , 240 }, { 320 , 240 } } });
// pass a std::array
std::array<vk::Rect2D, 2 > arr{ scissorRect1, scissorRect2 };
c.setScissor( 0 , arr);
// pass a std::vector of dynamic size
std::vector<vk::Rect2D> vec;
vec.push_back(scissorRect1);
vec.push_back(scissorRect2);
c.setScissor( 0 , vec); Vulkan-HPP генерирует ссылки на указатели на структуры. Это преобразование позволяет передавать временные структуры функциям, которые могут привести к более короткому коду. В случае, если вход является необязательным и, таким образом, принимает нулевый указатель, тип параметра будет vk::Optional<T> const& . Этот тип принимает либо ссылку на T , либо nullptr в качестве входного и, таким образом, позволяет дополнительные временные структуры.
// C
VkImageSubresource subResource;
subResource.aspectMask = 0 ;
subResource.mipLevel = 0 ;
subResource.arrayLayer = 0 ;
VkSubresourceLayout layout;
vkGetImageSubresourceLayout (device, image, &subresource, &layout);
// C++
auto layout = device.getImageSubresourceLayout(image, { {} /* flags */ , 0 /* miplevel */ , 0 /* arrayLayer */ }); Vulkan позволяет цепорить структуры через указатель pNext . Vulkan-HPP имеет шаблон варидового класса, который позволяет построить такие структурные цепочки с минимальными усилиями. В дополнение к этому он проверяет во время компиляции, если спецификация позволяет построить такую цепь pNext .
// This will compile successfully.
vk::StructureChain<vk::MemoryAllocateInfo, vk::ImportMemoryFdInfoKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>();
// This will fail compilation since it's not valid according to the spec.
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedRequirementsKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>(); Vulkan-HPP предоставляет конструктор для этих цепей, аналогичных объектам CreateInfo , который принимает список всех структур, часть цепи. Поле pNext автоматически устанавливается на правильное значение:
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedAllocateInfo> c = {
vk::MemoryAllocateInfo (size, type),
vk::MemoryDedicatedAllocateInfo (image)
}; Если одна из структур структурного оборудования должна быть удалена, возможно, из -за некоторых дополнительных настройков, вы можете использовать функцию vk::StructureChain::unlink<ClassType>() . Он изменяет структуру так, чтобы указанная структура больше не была частью PNEXT-Chain. Обратите внимание, что фактическая компоновка памяти структуры не изменяется этой функцией. В случае, если эта та же самая структура должна быть снова вновь добавлена в структуру, используйте vk::StructureChain::relink<ClassType>() .
Иногда пользователь должен передать предварительную цепочку структуры, чтобы запросить информацию. Для этих случаев есть две соответствующие функции Getter. Один с вариальным шаблоном, генерирующим структурную цепь не менее двух элементов, чтобы построить возвратное значение:
// Query vk::MemoryRequirements2HR and vk::MemoryDedicatedRequirementsKHR when calling Device::getBufferMemoryRequirements2KHR:
auto result = device.getBufferMemoryRequirements2KHR<vk::MemoryRequirements2KHR, vk::MemoryDedicatedRequirementsKHR>({});
vk::MemoryRequirements2KHR &memReqs = result.get<vk::MemoryRequirements2KHR>();
vk::MemoryDedicatedRequirementsKHR &dedMemReqs = result.get<vk::MemoryDedicatedRequirementsKHR>();Чтобы получить только базовую структуру, без цепочки, другая предоставленная функция Getter не нуждается в аргументе шаблона для структуры, чтобы получить:
// Query just vk::MemoryRequirements2KHR
vk::MemoryRequirements2KHR memoryRequirements = device.getBufferMemoryRequirements2KHR({}); По умолчанию Vulkan-HPP имеет исключения. Это означает, что Vulkan-HPP проверяет код возврата каждого вызова функции, который возвращает vk::Result . Если vk::Result - это сбой, std::runtime_error будет брошен. Поскольку больше нет необходимости возвращать код ошибки, привязки C ++ теперь могут вернуть фактическое желаемое возвратное значение, т.е. ручка Vulkan. В этих случаях vk::ResultValue<SomeType>::type определяется как возвращенный тип.
Чтобы создать устройство, теперь вы можете просто написать:
vk::Device device = physicalDevice.createDevice(createInfo); Некоторые функции допускают больше, чем просто vk::Result::eSuccess , рассматриваться как код успеха. Для этих функций мы всегда возвращаем vk::ResultValue<SomeType> . Примером является acquireNextImage2KHR , который можно использовать так:
vk::ResultValue< uint32_t > result = device-> acquireNextImage2KHR (acquireNextImageInfo);
switch (result.result)
{
case vk::Result::eSuccess:
currentBuffer = result. value ;
break ;
case vk::Result::eTimeout:
case vk::Result::eNotReady:
case vk::Result::eSuboptimalKHR:
// do something meaningful
break ;
default :
// should not happen, as other return codes are considered to be an error and throw an exception
break ;
} Со временем некоторые функции Vulkan могут измениться, так что они начинают поддерживать больше кодов результатов, чем vk::Result::eSuccess в качестве кода успеха. Это логическое изменение не было бы видно в API C, но в API C ++, так как такая функция теперь вернет vk::ResultValue<SomeType> вместо того, чтобы SomeType . В таких (редких) случаях вам придется скорректировать свои результаты CPP, чтобы отразить это изменение API.
Если обработка исключений отключена путем определения VULKAN_HPP_NO_EXCEPTIONS Тип vk::ResultValue<SomeType>::type - это структура, удерживающая vk::Result и SomeType . Эта структура поддерживает распаковку возвращаемых значений с помощью std::tie .
Если вы не хотите использовать преобразование vk::ArrayProxy и возвращаемого значения, вы все равно можете вызвать обычную функцию C-стиля. Ниже приведены три примера, показывающие 3 способа использования API:
Первый фрагмент показывает, как использовать API без исключений и преобразования возвращаемого значения:
// No exceptions, no return value transformation
vk::ShaderModuleCreateInfo createInfo (...);
vk::ShaderModule shader1;
vk::Result result = device.createShaderModule(&createInfo, allocator, &shader1);
if (result.result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}
vk::ShaderModule shader2;
vk::Result result = device.createShaderModule(&createInfo, allocator, &shader2);
if (result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}Второй фрагмент показывает, как использовать API с использованием преобразования возвращаемого значения, но без исключений. Это уже немного короче, чем оригинальный код:
vk::ResultValue<ShaderModule> shaderResult1 = device.createShaderModule({...} /* createInfo temporary */ );
if (shaderResult1.result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}
// std::tie support.
vk::Result result;
vk::ShaderModule shaderModule2;
std::tie (result, shaderModule2) = device.createShaderModule({...} /* createInfo temporary */ );
if (result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}Более приятный способ распаковки результата - это использование структурированных привязков в C ++ 17. Они позволят нам получить результат с одной строкой кода:
auto [result, shaderModule2] = device.createShaderModule({...} /* createInfo temporary */ );Наконец, последним примером кода является использование исключений и преобразования возвращаемого значения. Это режим по умолчанию API.
vk::ShaderModule shader1;
vk::ShaderModule shader2;
try
{
shader1 = device. createShaderModule ({...});
shader2 = device. createShaderModule ({...});
}
catch (std:: exception const &e)
{
// handle error and free resources
}Важный
Вулкан ручки в vk -namespace не поддерживают raii, поэтому вам нужно очистить свои ресурсы в обработчике ошибок! Вместо этого вы можете использовать классы обертки ручки в vk::raii -namespace.
С C ++ 17 и выше, некоторые функции приписываются [[nodiscard]] , что приводит к предупреждению, если вы не используете возвратное значение каким -либо образом. Вы можете отключить эти предупреждения, определив VULKAN_HPP_NO_NODISCARD_WARNINGS .
Для преобразования возврата значения есть один специальный класс возвращаемых значений, которые требуют специальной обработки: перечисления. Для перечислений вам обычно приходится писать код таким образом:
std::vector<LayerProperties, Allocator> properties;
uint32_t propertyCount;
vk::Result result;
do
{
// determine number of elements to query
result = static_cast <vk::Result>( vk::enumerateDeviceLayerProperties (m_physicalDevice, &propertyCount, nullptr ));
if ((result == vk::Result::eSuccess) && propertyCount)
{
// allocate memory & query again
properties. resize (propertyCount);
result = static_cast <vk::Result>( vk::enumerateDeviceLayerProperties (m_physicalDevice, &propertyCount, reinterpret_cast
<VkLayerProperties*>(properties. data ())));
}
} while (result == vk::Result::eIncomplete);
// it's possible that the count has changed, start again if properties was not big enough
properties.resize(propertyCount);Поскольку написание этой петли снова и снова утомительно и склонна к ошибкам, привязка C ++ заботится о перечислении, чтобы вы могли просто написать:
std::vector<LayerProperties> properties = physicalDevice.enumerateDeviceLayerProperties(); Vulkan-HPP предоставляет интерфейс vk::UniqueHandle<Type, Deleter> . Для каждого вулканского ручки типа vk::Type есть уникальная ручка vk::UniqueType , который удалит базовый ресурс Vulkan после разрушения, например, vk::UniqueBuffer - это уникальная ручка для vk::Buffer .
Для каждой функции, которая создает вулканский ручку типа vk::Type Vulkan-HPP предоставляет вторую версию, которая возвращает vk::UniqueType . Например, для vk::Device::createBuffer есть vk::Device::createBufferUnique , а для vk::allocateCommandBuffers есть vk::allocateCommandBuffersUnique .
Обратите внимание, что использование vk::UniqueHandle стоит стоимостью, поскольку большинству удалений приходится хранить vk::AllocationCallbacks и родительскую ручку, используемую для строительства, потому что они необходимы для автоматического разрушения.
Vulkan-HPP предоставляет интерфейс vk::SharedHandle<Type> . Для каждого вулканского ручки типа vk::Type есть общая ручка vk::SharedType , который удалит базовый ресурс Vulkan после разрушения, например, vk::SharedBuffer - общая ручка для vk::Buffer .
В отличие от vk::UniqueHandle , vk::SharedHandle берет на себя общее владение ресурсом, а также своего родителя. Это означает, что родительская ручка не будет разрушена до тех пор, пока все дочерние ресурсы не будут удалены. Это полезно для ресурсов, которые разделены между несколькими потоками или объектами.
Этот механизм обеспечивает правильный порядок разрушения, даже если родительский vk::SharedHandle разрушен до его работы с детьми. В противном случае ручка ведет себя как std::shared_ptr . vk::SharedInstance или любой из его дочернего объекта должен быть последним, чтобы удалить (сначала создан, сначала в классе декларации).
Нет никаких функций, которые еще не возвращают vk::SharedHandle напрямую. Вместо этого вы можете построить vk::SharedHandle из vk::Handle :
vk::Buffer buffer = device.createBuffer(...);
vk::SharedBuffer sharedBuffer (buffer, device); // sharedBuffer now owns the buffer Есть несколько специализаций vk::SharedHandle для разных типов ручки. Например, vk::SharedImage может принять дополнительный аргумент, чтобы указать, принадлежит ли изображение Swapchain:
vk::Image image = swapchain.getImages(...)[ 0 ]; // get the first image from the swapchain
vk::SharedImage sharedImage (image, device, SwapChainOwns::yes); // sharedImage now owns the image, but won't destroy it Существует также специализация для vk::SwapchainKHR , которая требует дополнительного аргумента, чтобы указать поверхность:
vk::SwapchainKHR swapchain = device.createSwapchainKHR(...);
vk::SharedSwapchainKHR sharedSwapchain (swapchain, device, surface); // sharedSwapchain now owns the swapchain and surface Вы можете создать перегрузку vk::SharedHandle для собственного типа ручки или собственных общих ручек, предоставив несколько шаблонов аргументов для SharedHandleBase :
При этом предоставьте пользовательскую функцию статического разрушения internalDestroy , которая принимает ручку для родителей и ручку для уничтожения. Не забудьте добавить декларацию друга для базового класса.
// Example of a custom shared device, that takes in an instance as a parent
class shared_handle <VkDevice> : public vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>
{
using base = vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>;
friend base;
public:
shared_handle () = default ;
explicit shared_handle (VkDevice handle, vk::SharedInstance parent) noexcept
: base(handle, std::move(parent)) {}
const auto & getParent () const noexcept
{
return getHeader ();
}
protected:
static void internalDestroy ( const vk::SharedInstance& /* control */ , VkDevice handle) noexcept
{
kDestroyDevice (handle);
}
};API будет расширен для обеспечения функций создания в будущем.
В дополнение к vk::UniqueHandles и vk::SharedHandles , есть набор классов обертки для всех типов ручки, которые следуют за raii-paradigm (приобретение ресурса является инициализацией), предусмотренным в пространстве имен vk::raii .
В то время как vk::UniqueHandle имитирует ручку, завернутую std::unique_ptr , а vk::SharedHandle имитирует ручку, обернутую std::shared_ptr , включая родительскую информацию, vk::raii::Handle -это просто класс, который приобретает базовый vk-handle в его конструкторе и религирует его в его уничтожителе. Таким образом, вы можете использовать их в качестве значений или обернуть их с помощью Smart Pointer.
Помимо vk::Handles , все эти классы обработки должны хранить дополнительные данные, и, следовательно, не являются бинарными идентичны вулканских C-Handles.
Поскольку vk::UniqueHandles и vk::SharedHandles используют тот же диспетчер, что и vk::Handles их можно легко смешать и сопоставить. vk::raii::Handles используют несколько разных диспетчеров и, следовательно, не совместимы с другими ручками! То есть, для vk-Handles , vk::UniqueHandles и vk::SharedHandles вам необходимо создать глобальный диспетчер, как описано в https://github.com/kronosgroup/vulkan-hpp#extensions-per-device-coinders. Для vk::raii-Handles это не нужно, поскольку они поддерживают своих собственных диспетчеров. Большое преимущество здесь-когда у вас есть несколько устройств: функции, вызванные через vk::raii-Handles всегда вызывают функции конкретных устройств.
Иногда необходимо использовать std::vector с пользовательскими распределителями. Vulkan-HPP поддерживает векторы с пользовательскими распределителями в качестве входных данных для vk::ArrayProxy и для функций, которые возвращают вектор. Для последнего случая добавьте свой любимый пользовательский распределитель в качестве аргумента шаблона в функцию Call, как это:
std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>(); Вы также можете использовать государственный пользовательский распределитель, предоставив его в качестве аргумента для этих функций. К сожалению, чтобы сделать компиляторы счастливыми, вам также необходимо явно установить аргумент отправки. Чтобы получить по умолчанию, было бы достаточно простого {} :
MyStatefulCustomAllocator allocator;
std::vector<LayerProperties, MyStatefulCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties(allocator, {}); По всему vulkan.hpp есть несколько вызовов на функцию утверждения. Определяя VULKAN_HPP_ASSERT , вы можете вместо этого определить свою собственную функцию Assert.
По умолчанию VULKAN_HPP_ASSERT_ON_RESULT будет использоваться для проверки результатов, когда будет определена VULKAN_HPP_NO_EXCEPTIONS . Если вы хотите обработать ошибки самостоятельно, вы можете отключить/настроить их так же, как VULKAN_HPP_ASSERT .
Существует несколько статических утверждений для каждого класса рукоятки и каждого структуры в файле vulkan_static_assertions.hpp . Вы можете включить этот файл по крайней мере в одном из ваших исходных файлов. Определяя VULKAN_HPP_STATIC_ASSERT , вы можете указать свое собственное статическое утверждение, которое будет использоваться для этих случаев. То есть, определяя это как NOP, вы можете немного сократить время компиляции.
Погрузчик Vulkan раскрывает только функции Vulkan Core и ограниченное количество расширений. Чтобы использовать Vulkan-HPP с расширениями, необходимо иметь либо библиотеку, которая предоставляет заглушки для всех используемых функций Vulkan, либо для того, чтобы Vulkan-HPP отправлять эти указатели. Vulkan-HPP обеспечивает механизм отправки для функции, принимая класс отправки в качестве последнего параметра в каждом вызове функции. Класс диспетчеры должен предоставить выставленный тип для каждой используемой функции Вулкана. Vulkan-HPP предоставляет одну реализацию, DispatchLoaderDynamic , которая получает все указатели функций, известные библиотеке.
// Providing a function pointer resolving vkGetInstanceProcAddr, just the few functions not depending an an instance or a device are fetched
vk::DispatchLoaderDynamic dld (getInstanceProcAddr);
// Providing an already created VkInstance and a function pointer resolving vkGetInstanceProcAddr, all functions are fetched
vk::DispatchLoaderDynamic dldi (instance, getInstanceProcAddr);
// Providing also an already created VkDevice and optionally a function pointer resolving vkGetDeviceProcAddr, all functions are fetched as well, but now device-specific functions are fetched via vkDeviceGetProcAddr.
vk::DispatchLoaderDynamic dldid ( nstance, getInstanceProcAddr, device);
// Pass dispatch class to function call as last parameter
device.getQueue(graphics_queue_family_index, 0 , &graphics_queue, dldid); Для использования vk::DispatchLoaderDynamic в качестве диспетчера по умолчанию (означает: вам не нужно явно добавлять его в каждый вызов функции), вам нужно #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 и иметь Macro vulkan_hpp_default_dispatch_loader_dynamic 1 и иметь Macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE 1 и иметь Macro vulkan_hpp_default_dispatch_loader_dynamic. Затем вы можете использовать его с помощью Macro VULKAN_HPP_DEFAULT_DISPATCHER , как это показано в фрагментах кода ниже. Создание полного избранного vk::DispatchLoaderDynamic это два-трехэтапный процесс, где у вас есть три варианта для первого шага:
vk::DynamicLoader : VULKAN_HPP_DEFAULT_DISPATCHER.init();getProcAddress (сравните с vk::DynamicLoader в vulkan.hpp ): YourDynamicLoader ydl;
VULKAN_HPP_DEFAULT_DISPATCHER.init(ydl);Примечание
Вы должны сохранить этот объект динамического загрузчика живым до последнего вызова функции Vulkan в вашей программе. Например, сделав его статичным или сохраняя его во всем мире.
PFN_vkGetInstanceProcAddr : PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = your_own_function_pointer_getter();
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);vk::Instance чтобы получить все другие указатели функций: vk::Instance instance = vk::createInstance({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);vk::Device для получения указателей функций, специфичных для устройства, std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
assert (!physicalDevices.empty());
vk::Device device = physicalDevices[ 0 ].createDevice({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);После второго шага выше, диспетчер полностью функционален. Добавление третьего шага может привести к более эффективному коду. Но если вы намереваетесь использовать несколько устройств, вы можете просто опустить этот третий шаг и позволить драйверу выполнять распределение устройств.
В некоторых случаях хранилище для DispatchLoaderDynamic должно быть встроено в DLL. Для этих случаев вам необходимо определить VULKAN_HPP_STORAGE_SHARED , чтобы сказать Vulkan-HPP, что хранилище находится в DLL. При составлении DLL с хранением также необходимо определить VULKAN_HPP_STORAGE_SHARED_EXPORT для экспорта необходимых символов.
Для всех функций, что VULKAN_HPP_DEFAULT_DISPATCHER является по умолчанию для последнего аргумента этой функции. Если вы хотите явно предоставить диспетчеру для каждого вызова функции (например, когда у вас есть несколько диспетчеров для разных устройств), и вы хотите убедиться, что вы не случайно пропустите какой -либо вызов функции, вы можете определить VULKAN_HPP_NO_DEFAULT_DISPATCHER прежде чем вы включите vulkan.hpp , чтобы удалить этот аргумент по умолчанию.
vulkan.hpp предоставляет пару типовых признаков, облегчающее шаблон метапрограммирование:
template <typename EnumType, EnumType value> struct CppType maps IndexType значения ( IndexType::eUint16 , IndexType::eUint32 , ...) к соответствующему типу ( uint16_t , uint32_t , ...) от Type члена типа; Карты ObjectType значения ( ObjectType::eInstance , ObjectType::eDevice , ...) для соответствующего типа ( vk::Instance , vk::Device , ...) Type типа члена; Maps DebugReportObjectType значения ( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice , ...) к соответствующему типу ( vk::Instance , vk::Device , ...) от Type участника;template <typename T> struct IndexTypeValue Карты скалярных типов ( uint16_t , uint32_t , ...) к соответствующему значению IndexType ( IndexType::eUint16 , IndexType::eUint32 , ...).template <typename T> struct isVulkanHandleType отображает тип true , если и только тогда, когда это класс handle ( vk::Instance , vk::Device , ...) по статическому value члена.HandleClass::CType отображает класс ручки ( vk::Instance , vk::Device , ...) для соответствующего C-типа ( VkInstance , VkDevice , ...) от типа члена CType .HandleClass::objectType отображает класс ручки ( vk::Instance , vk::Device , ...) к соответствующему значению ObjectType ( ObjectType::eInstance , ObjectType::eDevice , ...) от статического члена objectType .HandleClass::debugReportObjectType Карты класса Handle ( vk::Instance , vk::Device , ...) для соответствующего значения DebugReportObjectTypeEXT ( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice , ...) от STATIC debugReportObjectType . С дополнительным заголовком vulkan_format_traits.hpp , представлена пара функций черты в vk::Format . При C ++ 14 и выше все эти функции отмечены как constexpr , то есть с соответствующими аргументами, они разрешаются во время компиляции.
uin8_t blockSize( vk::Format format ); Получает размер блока Texel этого формата в байтах.uint8_t texelsPerBlock( vk::Format format ); Получает количество Texels в блоке Texel.std::array<uint8_t, 3> blockExtent( vk::Format format ); Получает трехмерную протяженность блоков Texel.char const * compressionScheme( vk::Format format ); Получает текстовое описание схемы сжатия этого формата или пустого текста, если он не сжат.bool isCompressed( vk::Format format ); Правда, если формат является сжатым форматом, в противном случае неверно.uint8_t packed( vk::Format format ); Получает количество битов, в которые упакован формат. Один элемент изображения в этом формате может быть сохранен в том же пространстве, что и скалярный тип этой ширины бита.uint8_t componentCount( vk::Format format ); Получает количество компонентов этого формата.bool componentsAreCompressed( vk::Format format ); Правда, если компоненты этого формата сжаты, в противном случае неверно.uint8_t componentBits( vk::Format format, uint8_t component ); Получает количество битов в этом компоненте, если не сжат, в противном случае 0.char const * componentName( vk::Format format, uint8_t component ); Получает название этого компонента в качестве C-String.char const * componentNumericFormat( vk::Format format, uint8_t component ); Получает числовой формат этого компонента в качестве C-строки.uint8_t componentPlaneIndex( vk::Format format, uint8_t component ); Получает индекс плоскости, этот компонент находится в.uint8_t planeCount( vk::Format format ); Получает количество плоскостей изображения этого формата.vk::Format planeCompatibleFormat( vk::Format format, uint8_t plane ); Получает формат с одной плоскостью, совместимый с этой плоскостью.uint8_t planeHeightDivisor( vk::Format format, uint8_t plane ); Получает относительную высоту этой плоскости. Значение k означает, что эта плоскость составляет 1/k высоту общего формата.uint8_t planeWidthDivisor( vk::Format format, uint8_t plane ); Получает относительную ширину этой плоскости. Значение K означает, что эта плоскость составляет 1/k ширину общего формата. С дополнительным заголовком vulkan_hash.hpp , вы получаете специализацию std::hash для классов обертки ручки и, с C ++ 14, для обертков структуры. С помощью VULKAN_HPP_HASH_COMBINE вы можете определить свой собственный алгоритм сочетания хэша для элементов структуры.
С помощью дополнительного заголовка vulkan_extension_inspection.hpp предоставляются некоторые функции для проверки расширений. При C ++ 20 и выше некоторые из этих функций отмечены как constexpr , то есть с соответствующими аргументами, они разрешаются во время компиляции. Каждое расширение идентифицируется строкой, удерживающей его имя. Обратите внимание, что существует определение с этим именем для каждого расширения. Некоторые функции могут предоставить информацию, которая зависит от версии Vulkan. Поскольку все функции здесь работают исключительно на строках, версии Vulkan кодируются строкой, начинающейся с «vk_version_», за которой следует основная версия и второстепенная версия, разделенная подмозрием, например: «vk_version_1_0».
std::set<std::string> const & getDeviceExtensions(); Получает все расширения устройства, указанные для текущей платформы. Обратите внимание, что не все из них могут быть поддержаны реальными устройствами.std::set<std::string> const & getInstanceExtensions(); Получает все расширения экземпляра, указанные для текущей платформы. Обратите внимание, что не все из них могут быть поддержаны фактическими случаями.std::map<std::string, std::string> const & getDeprecatedExtensions(); Получает карту всех устаревших расширений на расширение или версию Vulkan, которая должна заменить эту функциональность.std::map<std::string, std::vector<std::vector<std::string>>> const & getExtensionDepends( std::string const & extension ); Некоторые расширения зависят от других расширений. Эти зависимости могут отличаться для разных версий Вулкана, и могут быть разные наборы зависимостей для одной и той же версии Вулкана. Эта функция получает вектор векторов расширений на версию Vulkan, от которой зависит данное расширение.std::pair<bool, std::vector<std::vector<std::string>> const &> getExtensionDepends( std::string const & version, std::string const & extension ); first член возвращаемой std::pair TRUE, если указанное расширение указано для данной Вульканской версии, в противном случае false . second член возвращаемой std::pair - вектор векторов расширений, перечисляя отдельные наборы расширений.std::map<std::string, std::string> const & getObsoletedExtensions(); Получает карту всех устаревших расширений до удлинения или версии Vulkan, которая установила это расширение.std::map<std::string, std::string> const & getPromotedExtensions(); Получает карту всех расширений, которые были повышены до другого расширения, или к версии Vulkan к этому расширению версии Vulkan.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionDeprecatedBy( std::string const & extension ); Получает расширение или версию Vulkan. Данное расширение устанавливается.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionObsoletedBy( std::string const & extension ); Получает расширение или версию Vulkan. Данное расширение устанавливается.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionPromotedTo( std::string const & extension ); Получает расширение или версию Vulkan. Повышенное расширение.VULKAN_HPP_CONSTEXPR_20 bool isDeprecatedExtension( std::string const & extension ); Возвращает true если заданное расширение устарело от какой -либо другой версии расширения или Vulkan.VULKAN_HPP_CONSTEXPR_20 bool isDeviceExtension( std::string const & extension ); Возвращает true , если заданное расширение является расширением устройства.VULKAN_HPP_CONSTEXPR_20 bool isInstanceExtension( std::string const & extension ); Возвращает true если заданное расширение является расширением экземпляра.VULKAN_HPP_CONSTEXPR_20 bool isObsoletedExtension( std::string const & extension ); Возвращает true если заданное расширение устарело каким -то другим расширением или Vulkan версией.VULKAN_HPP_CONSTEXPR_20 bool isPromotedExtension( std::string const & extension ); Возвращает true если заданное расширение повышается в какой -либо другой расширении или Vulkan версии.Предупреждение
Текущая версия Microsoft Visual Studio 2022 не может обрабатывать модуль Vulkan.cppm. Подана ошибка (https://developercommunity.visualstudio.com/t/on-building-a-c20-module:-fatal-error/10469799#t-nd10485943). Вы можете, по крайней мере, использовать эту функцию, если вам не нужна или вы хотите использовать vk::UniqueHandle или vk::SharedHandle , определив VULKAN_HPP_NO_SMART_HANDLE .
Vulkan-HPP предоставляет C ++ с именем модуля, vulkan_hpp в vulkan.cppm . Модули C ++ предназначены для замены файлов заголовков. Модули имеют потенциал для кардинального улучшения времени компиляции для крупных проектов, так как объявления и определения могут быть легко распространены между единицами перевода без неоднократного разбора заголовков. Vulkan-HPP имеет несколько чрезвычайно длинных заголовков (например, vulkan_structs.hpp ), и модуль C ++, вероятно, сократит время компиляции для проектов, использующих в настоящее время.
Эта функция требует недавнего компилятора с полной поддержкой C ++ 20:
cl.exe 19.28 или более поздней версии)Если вы намереваетесь использовать поддержку модуля Cmake C ++ (и, возможно, ниндзя), то требуются более поздние инструменты:
cl.exe 19.34 или более поздней версии)Предупреждение
Названный модуль Vulkan-HPP C ++ все еще экспериментальный. Some suggested ways to use it in your projects are below. The long-term goal is to submit patches to the CMake FindVulkan module so that users may transparently configure the named module, without needing to declare it as an additional library in consumer CMake code.
CMake is recommended for use with the Vulkan-Hpp named module, as it provides a convenient platform-agnostic way to configure your project. CMake version 3.28 or later is required to support C++ modules. Refer to the CMake documentation on the topic.
CMake provides the FindVulkan module, which may be used to source the Vulkan SDK and Vulkan headers on your system.
# find Vulkan SDK
find_package ( Vulkan REQUIRED )
# Require Vulkan version ≥ 1.3.256 (earliest version when the Vulkan module was available)
if ( ${Vulkan_VERSION} VERSION_LESS "1.3.256" )
message ( FATAL_ERROR "Minimum required Vulkan version for C++ modules is 1.3.256. "
"Found ${Vulkan_VERSION} ."
)
endif ()
# set up Vulkan C++ module as a library
add_library ( VulkanHppModule )
target_sources ( VulkanHppModule PRIVATE
FILE_SET CXX_MODULES
BASE_DIRS ${Vulkan_INCLUDE_DIR}
FILES ${Vulkan_INCLUDE_DIR} /vulkan/vulkan.cppm
)
target_compile_features ( VulkanHppModule PUBLIC cxx_std_20 )
target_link_libraries ( VulkanHppModule PUBLIC Vulkan::Vulkan )
# link Vulkan C++ module into your project
add_executable ( YourProject main.cpp )
target_link_libraries ( YourProject PRIVATE VulkanHppModule ) Configuring the named module is straightforward; add any required Vulkan-Hpp feature macros (listed in Configuration Options) to target_compile_definitions . Например:
# Disable exceptions, disable smart handles, disable constructors
target_compile_definitions ( VulkanHppModule PRIVATE
VULKAN_HPP_NO_EXCEPTIONS
VULKAN_HPP_NO_SMART_HANDLE
VULKAN_HPP_NO_CONSTRUCTORS
) It is important to have VULKAN_HPP_DISPATCH_LOADER_DYNAMIC defined equally for both the module and an importing project. To use the dynamic dispatcher, set it to 1 ; otherwise, leave it undefined or set it to 0 . In CMake, do this in a single line with target_compile_definitions and the PUBLIC scope:
target_compile_definitions ( VulkanHppModule PUBLIC
VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1
)
# ...
target_link_libraries ( YourProject PRIVATE VulkanHppModule ) Furthermore, you may also prefer linking VulkanHppModule to just the Vulkan::Headers target with the PUBLIC scope instead of Vulkan::Vulkan , so that the vulkan-1 library is not linked in, and the Vulkan headers are available to your consuming project, as detailed further below.
target_link_libraries ( VulkanHppModule PUBLIC Vulkan::Headers ) Finally, supply the macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE exactly once in your source code, just as in the non-module case. In order to have that macro available, include vulkan_hpp_macros.hpp , a lightweight header providing all Vulkan-Hpp related macros and defines. And as explained above, you need to initialize that dispatcher in two or three steps:
import vulkan_hpp;
# include < vulkan/vulkan_hpp_macros.hpp >
# if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
# endif
auto main ( int argc, char * const argv[]) -> int
{
# if ( VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 )
// initialize minimal set of function pointers
VULKAN_HPP_DEFAULT_DISPATCHER. init ();
# endif
auto appInfo = vk::ApplicationInfo ( " My App " , 1 , " My Engine " , 1 , vk::makeApiVersion ( 1 , 0 , 0 , 0 ));
// ...
} An example is provided in tests/Cpp20Modules/Cpp20Modules.cpp .
Finally, you can configure and build your project as usual. Note that CMake currently only supports the Ninja and Visual Studio generators for C++ modules.
If you want to use the Vulkan-Hpp C++ module without CMake, you must first pre-compile it, and then import it into your project. You will also need to define any macros that control various features of Vulkan-Hpp, such as VULKAN_HPP_NO_EXCEPTIONS and VULKAN_HPP_NO_SMART_HANDLE . Different compilers have different command-lines for module pre-compilation; however, for initial use, some examples are provided below, assuming the same main.cpp consumer as above.
For MSVC, source vcvars64.bat or use a Developer Command Prompt/Developer PowerShell instance, and run the following:
cl.exe /std:c++20 /interface /TP < path-to-vulkan-hpp > vulkan.cppm
cl.exe /std:c++20 /reference vulkan=vulkan.ifc main.cpp vulkan.obj
.main.exeFor Clang, run the following:
clang++ -std=c++20 < path-to-vulkan-hpp > /vulkan.cppm -precompile -o vulkan.pcm
clang++ -std=c++20 -fprebuilt-module-path=. main.cpp vulkan.pcm -o main
./mainMore information about module compilation may be found at the respective compiler's documentation:
When you configure your project using CMake, you can enable SAMPLES_BUILD to add some sample projects to your solution. Most of them are ports from the LunarG samples, but there are some more, like CreateDebugUtilsMessenger, InstanceVersion, PhysicalDeviceDisplayProperties, PhysicalDeviceExtensions, PhysicalDeviceFeatures, PhysicalDeviceGroups, PhysicalDeviceMemoryProperties, PhysicalDeviceProperties, PhysicalDeviceQueueFamilyProperties, and RayTracing. All those samples should just compile and run. When you configure your project using CMake, you can enable TESTS_BUILD to add some test projects to your solution. Those tests are just compilation tests and are not required to run.
As vulkan.hpp is pretty big, some compilers might need some time to digest all that stuff. In order to potentially reduce the time needed to compile that header, a couple of defines will be introduced, that allow you to hide certain features. Whenever you don't need that corresponding feature, defining that value might improve your compile time. Currently, there are just a couple of such defines:
VULKAN_HPP_NO_SPACESHIP_OPERATOR , which removes the spaceship operator on structures (available with C++20)VULKAN_HPP_NO_TO_STRING , which removes the various vk::to_string functions on enums and bitmasks.VULKAN_HPP_USE_REFLECT , this one needs to be defined to use the reflection function on structures. It's very slow to compile, though! As Vulkan-Hpp often needs to switch between C++ vk-types and corresponding bit-identical C-types, using reinterpret_cast , it is highly recommended to use the compile option -fno-strict-aliasing to prevent potentially breaking compile optimizations.
There are a couple of defines you can use to control the feature set and behaviour of vulkan.hpp :
At various places in vulkan.hpp an assertion statement is used. By default, the standard assert funtions from <cassert> is called. By defining VULKAN_HPP_ASSERT before including vulkan.hpp , you can change that to any function with the very same interface.
If there are no exceptions enabled (see VULKAN_HPP_NO_EXCEPTIONS ), an assertion statement checks for a valid success code returned from every vulkan call. By default, this is the very same assert function as defined by VULKAN_HPP_ASSERT , but by defining VULKAN_HPP_ASSERT_ON_RESULT you can replace just those assertions with your own function, using the very same interface.
Every vk-function gets a Dispatcher as its very last argument, which defaults to VULKAN_HPP_DEFAULT_DISPATCHER . If VULKAN_HPP_DISPATCH_LOADER_DYNAMIC is defined to be 1 , it is defaultDispatchLoaderDynamic . This in turn is the dispatcher instance, which is defined by VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE , which has to be used exactly once in your sources. If, on the other hand, VULKAN_HPP_DISPATCH_LOADER_DYNAMIC is defined to something different from 1 , VULKAN_HPP_DEFAULT_DISPATCHER is set to be DispatchLoaderStatic() . You can use your own default dispatcher by setting VULKAN_HPP_DEFAULT_DISPATCHER to an object that provides the same API. If you explicitly set VULKAN_HPP_DEFAULT_DISPATCHER , you need to set VULKAN_HPP_DEFAULT_DISPATCHER_TYPE accordingly as well.
This names the default dispatcher type, as specified by VULKAN_HPP_DEFAULT_DISPATCHER . Per default, it is DispatchLoaderDynamic or DispatchLoaderStatic, depending on VULKAN_HPP_DISPATCH_LOADER_DYNAMIC being 1 or not 1 , respectively. If you explicitly set VULKAN_HPP_DEFAULT_DISPATCHER , you need to set VULKAN_HPP_DEFAULT_DISPATCHER_TYPE accordingly as well.
If you have not defined your own VULKAN_HPP_DEFAULT_DISPATCHER , and have VULKAN_HPP_DISPATCH_LOADER_DYNAMIC defined to be 1 (the default), you need to have the macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE exactly once in any of your source files to provide storage for that default dispatcher. VULKAN_HPP_STORAGE_API then controls the import/export status of that default dispatcher.
When this is defined before including vulkan.hpp , you essentially disable all enhanced functionality. All you then get is:
vk::Flags for bitmasks;vk::StructureChain for compile-time construction of structure chains.If this is not defined, you additionally get:
vk::ArrayProxy<> ), simplifying handling of array data; returning requested data; throwing exceptions on errors (as long as VULKAN_HPP_NO_EXCEPTIONS is not defined);VULKAN_HPP_NO_STRUCT_CONSTRUCTORS is not defined) (consuming vk::ArrayProxyNoTemporaries<> );vk::ArrayProxyNoTemporaries<> );vk::ArrayProxy<> and vk::ArrayProxyNoTemporaries<>vulkan_raii.hpp This either selects the dynamic (when it's 1 ) or the static (when it's not 1 ) DispatchLoader as the default one, as long as it's not explicitly specified by VULKAN_HPP_DEFAULT_DISPATCHER . By default, this is defined to be 1 if VK_NO_PROTOTYPES is defined, otherwise 0 .
By default, a little helper class DynamicLoader is used to dynamically load the vulkan library. If you set it to something different than 1 before including vulkan.hpp , this helper is not available, and you need to explicitly provide your own loader type for the function DispatchLoaderDynamic::init() .
When this is not externally defined and VULKAN_HPP_CPP_VERSION is at least 23 , VULKAN_HPP_EXPECTED is defined to be std::expected , and VULKAN_HPP_UNEXPECTED is defined to be std::unexpected .
By default, the member m_mask of the Flags class template is private. This is to prevent accidentally setting a Flags with some inappropriate value. But it also prevents using a Flags , or a structure holding a Flags , to be used as a non-type template parameter. If you really need that functionality, and accept the reduced security, you can use this define to change the access specifier for m_mask from private to public, which allows using a Flags as a non-type template parameter.
This define can be used to enable m_handle = exchange( rhs.m_handle, {} ) in move constructors of Vulkan-Hpp handles, which default-initializes the rhs underlying value. By default Vulkan-Hpp handles behave like trivial types -- move constructors copying value.
This define can be used to specify your own hash combiner function. In order to determine the hash of a vk-structure, the hashes of the members of that struct are to be combined. This is done by this define, which by default is identical to what the function boost::hash_combine() does. It gets the type of the to-be-combined value, the seed, which is the combined value up to that point, and finally the to-be-combined value. This hash calculation determines a "shallow" hash, as it takes the hashes of any pointer in a structure, and not the hash of a pointed-to value.
This is set to be the compiler-dependent attribute used to mark functions as inline. If your compiler happens to need some different attribute, you can set this define accordingly before including vulkan.hpp .
By default, the namespace used with vulkan.hpp is vk . By defining VULKAN_HPP_NAMESPACE before including vulkan.hpp , you can adjust this.
By default, the file vulkan_to_string.hpp is included by vulkan.hpp and provides functions vk::to_string for enums and bitmasks. If you don't need those functions, you can define VULKAN_HPP_NO_TO_STRING to prevent that inclusion. If you have certain files where you want to use those functions nevertheless, you can explicitly include vulkan_to_string.hpp there.
With C++20, designated initializers are available. Their use requires the absence of any user-defined constructors. Define VULKAN_HPP_NO_CONSTRUCTORS to remove constructors from structs and unions.
When a vulkan function returns an error code that is not specified to be a success code, an exception is thrown unless VULKAN_HPP_NO_EXCEPTIONS is defined before including vulkan.hpp .
With C++17, all vk-functions returning something are declared with the attribute [[nodiscard]] . This can be removed by defining VULKAN_HPP_NO_NODISCARD_WARNINGS before including vulkan.hpp .
By defining VULKAN_HPP_NO_SETTERS before including vulkan.hpp , setter member functions will not be available within structs and unions. Modifying their data members will then only be possible via direct assignment.
By defining VULKAN_HPP_NO_SMART_HANDLE before including vulkan.hpp , the helper class vk::UniqueHandle and all the unique handle types are not available.
With C++20, the so-called spaceship-operator <=> is introduced. If that operator is supported, all the structs and classes in vulkan.hpp use the default implementation of it. As currently some implementations of this operator are very slow, and others seem to be incomplete, by defining VULKAN_HPP_NO_SPACESHIP_OPERATOR before including vulkan.hpp you can remove that operator from those structs and classes.
By default, if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL is enabled on Win32, vulkan.hpp declares HINSTANCE , LoadLibraryA , and other required symbols. It could cause conflicts with the Windows.h alternatives, such as WindowsHModular . With this define, you can disable these declarations, but you will have to declare them before the vulkan.hpp is included.
If both, VULKAN_HPP_NO_EXCEPTIONS and VULKAN_HPP_EXPECTED are defined, the vk::raii-classes don't throw exceptions. That is, the actual constructors are not available, but the creation-functions must be used. For more details have a look at the vk_raii_ProgrammingGuide.md .
Even though vk::UniqueHandle and vk::SharedHandle are semantically close to pointers, an implicit cast operator to the underlying vk::Handle might be handy. You can add that implicit cast operator by defining VULKAN_HPP_SMART_HANDLE_IMPLICIT_CAST .
With this define you can specify whether the DispatchLoaderDynamic is imported or exported (see VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE ). If VULKAN_HPP_STORAGE_API is not defined externally, and VULKAN_HPP_STORAGE_SHARED is defined, depending on the VULKAN_HPP_STORAGE_SHARED_EXPORT being defined, VULKAN_HPP_STORAGE_API is either set to __declspec( dllexport ) (for MSVC) / __attribute__( ( visibility( "default" ) ) ) (for gcc or clang) or __declspec( dllimport ) (for MSVC), respectively. For other compilers, you might specify the corresponding storage by defining VULKAN_HPP_STORAGE_API on your own.
32-bit vulkan is not typesafe for non-dispatchable handles, so we don't allow copy constructors on this platform by default. To enable this feature on 32-bit platforms, #define VULKAN_HPP_TYPESAFE_CONVERSION 1 . To disable this feature on 64-bit platforms, #define VULKAN_HPP_TYPESAFE_CONVERSION 0 .
See VULKAN_HPP_EXPECTED .
With this define you can include a reflection mechanism on the vk-structures. It adds a function reflect that returns a tuple-version of the structure. That tuple then could easily be iterated. But at least for now, that feature takes lots of compile-time resources, so currently it is recommended to enable that feature only if you're willing to pay that price.
Feel free to submit a PR to add to this list.
Copyright 2015-2020 The Khronos Group Inc.
Лицензировано по лицензии Apache, версия 2.0 («Лицензия»); Вы не можете использовать этот файл, кроме как в соответствии с лицензией. Вы можете получить копию лицензии на
http://www.apache.org/licenses/LICENSE-2.0
Если не требуется применимый закон или не согласен в письменной форме, программное обеспечение, распространяемое по лицензии, распределяется по основам «как есть», без каких -либо гарантий или условий, явных или подразумеваемых. См. Лицензию для конкретного языка, регулирующих разрешения и ограничения по лицензии.