Vulkan-HPP的目标是仅向Vulkan C API提供C ++绑定,以改善开发人员Vulkan的体验,而无需引入CPU运行时成本。它添加了诸如枚举和比特菲尔德的类型安全性,STL容器支持,异常和简单枚举之类的功能。
| 平台 | 建立状态 |
|---|---|
| Linux |
自版本1.0.24以来,Vulkan-HPP是Lunarg Vulkan SDK的一部分。只需#include <vulkan/vulkan.hpp> ,就可以使用C ++绑定。如果您使用的是Vulkan SDK尚未支持的Vulkan版本,则可以在此处找到最新版本的标题。
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 。
vk.xml xml注册文件重新构建vulkan.hpp ,请添加-DVULKAN_HPP_RUN_GENERATOR=ON选项到cmake命令行。使用IDE,例如Visual Studio打开生成的项目,或使用cmake --build build --parallel启动构建过程。
可选:更新Vulkan-HPP及其子模块执行git pull --recurse-submodules 。
您可以使用VCPKG依赖项管理器下载并安装Vulkan-HPP:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install vulkan-headersMicrosoft团队成员和社区贡献者保持最新的VCPKG港口港口。如果该版本已过时,请在VCPKG存储库上创建问题或拉出请求。
如果CMAKE找到程序clang-Format,则相应设置Define CLANG_FORMAT_EXECUTABLE 。在这种情况下,使用位于该项目的根目录中的.clang-format文件格式化了生成的vulkan.hpp 。否则,将其格式化为发电机中的硬编码。
文件VulkanHpp.natvis在Visual Studio的vk::Flags上提供了自定义视图。如果将此文件添加到Visual Studio安装的用户特定的NATVIS目录中(%userProfile% Documents Visual Studio 2022 Visualizers),则可以通过所有Visual Studio Projects在调试器中可以很好地格式化vk::Flags 。
为了避免使用Vulkan C API碰撞,C ++绑定位于vk名称空间中。以下规则适用于新命名:
Vk前缀。除此之外,第一个功能信件是较低的情况。vkCreateInstance可以作为vk::createInstance访问。VkImageTiling可以作为vk::ImageTiling访问。VkImageCreateInfo可以作为vk::ImageCreateInfo访问。VK_前缀和类型的infix。如果枚举类型是扩展名,则将扩展后缀从枚举值中删除。在所有其他情况下,扩展后缀均未被删除。
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之前定义VULKAN_HPP_NAMESPACE来实现。
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手柄和C Vulkan手柄之间的隐式转换。在32位平台上,所有不可添加的手柄均定义为uint64_t ,从而防止在编译时间进行类型转换检查,这将在不兼容的手柄类型之间捕获作业。因此,默认情况下,Vulkan-HPP不能对32位平台进行隐式转换,建议使用static_cast进行这样的转换: VkImage = static_cast<VkImage>(cppImage)防止将任意的int转换为handle或vice vice vice或vice vice。如果您要在64位平台上开发代码,但希望在不添加显式铸件的情况下编译32位平台的代码,则可以将VULKAN_HPP_TYPESAFE_CONVERSION定义为构建系统中的1或包含vulkan.hpp的1个。在64位平台上,该定义设置为默认设置为1 ,并且可以设置为0以禁用隐式转换。
范围的枚举功能为标志增加了类型的安全性,但也可以防止使用标志位作为诸如& |等位操作的输入。 。
作为解决方案,Vulkan-HPP提供了类模板vk::Flags ,它带来了标准操作,例如&= , |= , & as |到我们的范围。除了使用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);通过字段填充CreateInfo结构时,Vulkan开发人员遇到了两个典型问题:
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结构的构造函数,也可以将临时工传递到这样的Vulkan函数:
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);请注意,指定订单需要匹配声明顺序。还要注意,现在您可以明确设置VK结构的sType成员。这既不是必要的(默认情况下是正确初始化的)也不建议。
Vulkan API有几个需要(计数,指针)作为两个函数参数,C ++具有一些完美映射到这对的容器。为了简化开发,Vulkan-HPP绑定已用vk::ArrayProxy类模板代替了这些参数对,该模板接受了空数组,单个值以及STL容器std::initializer_list , std::array and std::vector作为构造的参数。这样,单个生成的Vulkan版本就可以接受各种输入,而无需组合爆炸,这在为每种容器类型创建功能时会发生。
以下是有关如何使用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链的一部分。请注意,该功能未修改结构的实际存储器布局。如果必须再次将相同的结构重新添加到结构中,请使用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作为成功代码的结果代码。在C API中看不可见,但是在C ++ API中将不可见,因为这样一个函数现在将返回vk::ResultValue<SomeType>而不仅仅是SomeType 。在这种(罕见的)情况下,您必须调整CPP源以反映API的变化。
如果通过定义VULKAN_HPP_NO_EXCEPTIONS vk::ResultValue<SomeType>::type类型是一个结构是一个contem是一个持有vk::Result and there SomeType ,则禁用了异常处理。该结构支持使用std::tie解开返回值的包装。
如果您不想使用vk::ArrayProxy并返回值转换,则仍然可以调用普通的C型函数。以下是三种使用API的方法的三个示例:
第一个片段显示了如何使用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
}重要的
VLKAN在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>接口。对于每个Vulkan句柄类型vk::Type都有一个唯一的句柄vk::UniqueType ,它将在破坏时删除基础的Vulkan资源,例如vk::UniqueBuffer是vk::Buffer的唯一手柄。
对于构造vk::Type类型Vulkan-HPP的Vulkan句柄的每个函数,Vulkan-HPP提供了第二个版本,该版本返回vk::UniqueType 。例如,对于vk::Device::createBuffer ,有vk::Device::createBufferUnique和vk::allocateCommandBuffers有vk::allocateCommandBuffersUnique 。
请注意,使用vk::UniqueHandle是有代价的,因为大多数删除器都必须存储vk::AllocationCallbacks和用于施工的父手柄,因为它们是自动销毁所必需的。
Vulkan-HPP提供了vk::SharedHandle<Type>接口。对于每个Vulkan句柄类型vk::Type都有一个共享的句柄vk::SharedType ,它将在破坏时删除基本的Vulkan资源,例如vk::SharedBuffer是vk::Buffer的共享句柄。
与vk::UniqueHandle不同, vk::SharedHandle拥有对资源及其父母的共享所有权。这意味着在所有子资源被删除之前,父母的手柄将不会被销毁。这对于在多个线程或对象之间共享的资源很有用。
即使父级vk::SharedHandle在孩子的手柄之前被销毁,这种机制也可以确保正确的破坏命令。否则,手柄的行为就像std::shared_ptr 。 vk::SharedInstance或其任何子对象都应最后删除(首先创建,在类声明中首次创建)。
尚无返回vk::SharedHandle功能。 vk::Handle而vk::SharedHandle
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您可以通过向SharedHandleBase提供多个模板参数来为自己的句柄类型或自己的共享手柄创建vk::SharedHandle :
这样,提供了一个自定义的静态破坏功能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 namespace中提供。
虽然vk::UniqueHandle模仿了一个用std::unique_ptr包裹的手柄,而vk::SharedHandle模仿了一个由std::shared_ptr包裹的句柄,包括父级信息,包括父级信息, vk::raii::Handle只是一个类,可以在其构造者和稳定的命运者中获得底层的vk andles and the and and tit int istructor int and destructor。因此,您可以自由地将它们用作值或用一些智能指针包装它们。
除了vk::Handles外,所有这些处理包装类别都需要保存其他数据,因此与Vulkan C Handles并不相同。
当vk::UniqueHandles和vk::SharedHandles使用与vk::Handles相同的调度程序时,它们可以很容易地混合和匹配。 vk::raii::Handles使用一些略有不同的调度程序,因此与另一个处理器不兼容!也就是说,对于vk-Handles , vk::UniqueHandles和vk::SharedHandles ,您需要按照https://github.com/khronosgroup/vulkan-hpp#extensions-- per-per-device-unction-function-function-function-pointers实例化全局调度程序。对于vk::raii-Handles ,这是不需要的,因为他们保持自己的调度员。这里的最大优势是,当您拥有多个设备:通过vk::raii-Handles调用的功能总是调用设备特定功能。
有时,必须将std::vector与自定义分配器一起使用。 Vulkan-HPP支持使用自定义分配器的向量作为vk::ArrayProxy的输入以及确实返回向量的功能。对于后一种情况,将您喜欢的自定义分配器作为模板参数添加到函数调用中:
std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>();您也可以通过将其作为对这些功能的参数提供来使用状态自定义分配器。不幸的是,要使编译器开心,您还需要明确设置调度参数。要在此处默认,一个简单的{}就足够了:
MyStatefulCustomAllocator allocator;
std::vector<LayerProperties, MyStatefulCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties(allocator, {});在整个vulkan.hpp上,都有几个呼叫声明功能。通过定义VULKAN_HPP_ASSERT ,您可以指定自己的自定义自定义函数要被调用。
默认情况下,当定义VULKAN_HPP_NO_EXCEPTIONS时, VULKAN_HPP_ASSERT_ON_RESULT将用于检查结果。如果您想自己处理错误,则可以像VULKAN_HPP_ASSERT一样禁用/自定义。
每个句柄类别都有几个静态断言,并且在文件vulkan_static_assertions.hpp中的每个结构中都有几个静态断言。您可能至少将该文件包含在您的一个源文件中。通过定义VULKAN_HPP_STATIC_ASSERT ,您可以指定自己的自定义静态断言,以用于这些情况。也就是说,通过将其定义为NOP,您可以稍微减少汇编时间。
Vulkan加载器仅公开Vulkan Core功能和有限数量的扩展名。要使用带有扩展名的Vulkan-HPP,必须拥有一个为所有使用的Vulkan功能提供存根的库,或者告诉Vulkan-HPP派遣这些功能指针。 Vulkan-HPP通过接受调度类作为每个函数调用中的最后一个参数,提供了每功能调度机制。调度类必须为每个使用过的Vulkan功能提供可可的类型。 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); To use the vk::DispatchLoaderDynamic as the default dispatcher (means: you don't need to explicitly add it to every function call), you need to #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 , and have the macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE exactly once in your source code to provide storage for that default dispatcher.然后,您可以通过Macro VULKAN_HPP_DEFAULT_DISPATCHER使用它,如下所示。创建一个完整的vk::DispatchLoaderDynamic是一个两到三步的过程,在其中您有三个选择的第一步:
vk::DynamicLoader来完成所有工作: VULKAN_HPP_DEFAULT_DISPATCHER.init();getProcAddress (与vulkan.hpp中的vk::DynamicLoader进行比较): 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映射IndexType值( IndexType::eUint16 , IndexType::eUint32 ,...)to相应类型( uint16_t , uint32_t ,...)由成员Type ;映射ObjectType values( ObjectType::eInstance vk::Instance ObjectType::eDevice vk::Device ...)通过成员Type ;映射DebugReportObjectType值( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice ,...)to相应类型( 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 ,并且仅当它是thate Class( vk::Instance , vk::Device ,...)通过静态成员value映射到true。HandleClass::CType映射一个句柄类( vk::Instance , vk::Device ,...)到相应的c-type( VkInstance ,vkkdevice, VkDevice ,...),由成员类型CType 。HandleClass::objectType将句柄类( vk::Instance , vk::Device ,...)映射到相应的ObjectType value( ObjectType::eInstance ,objectType, ObjectType::eDevice ,...)由static member objectType 。HandleClass::debugReportObjectType将句柄类( vk::Instance , vk::Device ,...)映射到相应的DebugReportObjectTypeEXT value( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice edevice :: debugReportObjectType ,...使用其他标题vulkan_format_traits.hpp ,提供了vk::Format上的几个性状函数。使用C ++ 14及以上,所有这些函数都标记为constexpr ,即具有适当的参数,它们在编译时解决。
uin8_t blockSize( vk::Format format );在字节中获取此格式的Texel块大小。uint8_t texelsPerBlock( vk::Format format );在Texel街区获取Texels的数量。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 );是的,如果该格式的组件被压缩,则为false。uint8_t componentBits( vk::Format format, uint8_t component );获取此组件中的位数(如果不压缩的话),否则为0。char const * componentName( vk::Format format, uint8_t component );将此组件的名称作为C弦。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则可以使用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版本可能会有所不同,并且对于非常相同的Vulkan版本可能会有不同的依赖关系。此函数获得了给定扩展名取决于的每个Vulkan版本的扩展名的向量。std::pair<bool, std::vector<std::vector<std::string>> const &> getExtensionDepends( std::string const & version, std::string const & extension );返回的std::pair的first成员是正确的,如果给定的Vulkan版本指定给定扩展名,则为false 。返回的std::pair的second成员是扩展名的向量,列出了给定的扩展名取决于给定的Vulkan版本的单独的扩展程序集。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 );如果给定的扩展名是由其他一些扩展名或Vulkan版本弃用的,则返回为true 。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 );如果给定的扩展名被一些其他扩展名或Vulkan版本淘汰,则返回为true 。VULKAN_HPP_CONSTEXPR_20 bool isPromotedExtension( std::string const & extension );如果将给定扩展名晋升为其他扩展名或Vulkan版本,则返回为true 。警告
Microsoft Visual Studio 2022的当前版本无法处理Vulkan.CPPM模块。提交一个错误(https://developercommunity.visualstudio.com/t/on-building-a-c20-module:fatal--error/10469799#t-nd10485943)。 vk::SharedHandle您不需要或不需要使用vk::UniqueHandle VULKAN_HPP_NO_SMART_HANDLE则至少可以使用此功能。
Vulkan-HPP在vulkan.cppm中提供了一个名为vulkan_hpp的C ++。 C ++模块旨在取代标头文件。模块有可能大幅度改善大型项目的汇编时间,因为声明和定义很容易在翻译单元中很容易共享,而无需反复解析标题。 Vulkan-HPP具有一些非常长的标题(例如vulkan_structs.hpp ),并且C ++模块可能会缩短当前使用的项目的编译时间。
此功能需要一个具有完整C ++ 20支持的编译器:
cl.exe 19.28或更高版本)如果您打算使用CMAKE的C ++模块支持(可能是Ninja),则需要更多的工具:
cl.exe 19.34或更高版本)警告
名为模块的Vulkan-HPP C ++仍然是实验性的。在您的项目中使用一些建议使用它的方法如下。 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
除非适用法律要求或以书面形式同意,否则根据许可证分配的软件是按照“原样”分发的,没有任何明示或暗示的保证或条件。请参阅许可证,以获取执行许可条款和限制的特定语言。