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 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 ++仍然是實驗性的。在您的項目中使用一些建議使用它的方法如下。長期目標是向CMAKE FindVulkan模塊提交補丁程序,以便用戶可以透明地配置命名模塊,而無需將其聲明為消費者CMAKE代碼中的附加庫。
建議將Cmake與名為模塊的Vulkan-HPP一起使用,因為它提供了一種配置項目的方便平台 - 不可能的方法。 CMAKE版本3.28或更高版本以支持C ++模塊。請參閱有關該主題的CMAKE文檔。
Cmake提供了FindVulkan模塊,該模塊可用於在您的系統上採購Vulkan SDK和Vulkan標頭。
# 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 )配置命名模塊很簡單;將任何必需的Vulkan-HPP功能宏(在配置選項中列出)添加到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
)重要的是要讓VULKAN_HPP_DISPATCH_LOADER_DYNAMIC在模塊和導入項目中平均定義。要使用動態調度程序,請將其設置為1 ;否則,將其保留不確定或將其設置為0 。在Cmake中,使用target_compile_definitions和PUBLIC範圍進行單行執行此操作:
target_compile_definitions ( VulkanHppModule PUBLIC
VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1
)
# ...
target_link_libraries ( YourProject PRIVATE VulkanHppModule )此外,您可能還更喜歡將VulkanHppModule鏈接到Vulkan::Headers與PUBLIC範圍而不是Vulkan::Vulkan的目標,以便在下面詳細介紹vulkan-1庫鏈接到您的消費項目中,並且Vulkan標頭可用於您的消費項目。
target_link_libraries ( VulkanHppModule PUBLIC Vulkan::Headers )最後,提供宏VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE恰好在源代碼中,就像在非模塊情況下一樣。為了擁有該宏,包括vulkan_hpp_macros.hpp ,這是一個輕巧的標頭,可提供所有相關的vulkan-HPP相關宏並定義。如上所述,您需要以兩個或三個步驟初始化該調度員:
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 ));
// ...
}在tests/Cpp20Modules/Cpp20Modules.cpp中提供了一個示例。
最後,您可以照常配置和構建項目。請注意,Cmake當前僅支持C ++模塊的忍者和Visual Studio Generators。
如果您想在沒有CMAKE的情況下使用Vulkan-HPP C ++模塊,則必須首先預編譯它,然後將其導入您的項目。您還需要定義控制Vulkan-HPP各種功能的任何宏,例如VULKAN_HPP_NO_EXCEPTIONS和VULKAN_HPP_NO_SMART_HANDLE 。不同的編譯器具有不同的命令線來進行模塊預譯。但是,為了初次使用,下面提供了一些示例,假設與上述相同的main.cpp消費者。
對於MSVC,源vcvars64.bat或使用開發人員命令提示/開發人員PowerShell實例,並運行以下內容:
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.exe對於Clang,請運行以下內容:
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
./main有關模塊編譯的更多信息,請參見各自的編譯器文檔:
使用CMAKE配置項目時,您可以啟用Samples_build將一些示例項目添加到解決方案中。 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.所有這些樣本都應該只是編譯和運行。使用CMAKE配置項目時,您可以啟用Tests_build將一些測試項目添加到解決方案中。這些測試只是編譯測試,不需要運行。
由於vulkan.hpp很大,有些編譯器可能需要一些時間來消化所有這些東西。為了潛在地減少編譯該標頭所需的時間,將引入一些定義,從而可以隱藏某些功能。每當您不需要該相應的功能時,定義該值可能會改善您的編譯時間。目前,只有幾個定義:
VULKAN_HPP_NO_SPACESHIP_OPERATOR ,它可以在結構上刪除太空飛船運算符(C ++ 20)VULKAN_HPP_NO_TO_STRING ,它刪除了枚舉和位掩碼上的各種vk::to_string函數。VULKAN_HPP_USE_REFLECT ,需要定義此一個以在結構上使用反射功能。不過,編譯非常慢!由於Vulkan-HPP通常需要在C ++ VK型和相應的位相同的C型之間切換,因此強烈建議使用Compile option -fno-strict-aliasing來防止可能破壞編譯reinterpret_cast優化。
有幾個定義可以用來控制vulkan.hpp的功能集和行為:
在vulkan.hpp的各個地方使用主張聲明。默認情況下,調用了<cassert>的標準斷言功能。通過在包含vulkan.hpp之前定義VULKAN_HPP_ASSERT ,可以將其更改為具有相同接口的任何功能。
如果沒有啟用例外(請參閱VULKAN_HPP_NO_EXCEPTIONS ),則斷言語句檢查是否從每個Vulkan調用返回的有效的成功代碼。默認情況下,這是與VULKAN_HPP_ASSERT定義的確定函數,但是通過定義VULKAN_HPP_ASSERT_ON_RESULT ,您可以使用相同的接口將其用自己的函數替換為這些斷言。
每個VK功能都將調度程序作為其最後一個參數,默認為VULKAN_HPP_DEFAULT_DISPATCHER 。如果將VULKAN_HPP_DISPATCH_LOADER_DYNAMIC定義為1 ,則為defaultDispatchLoaderDynamic 。反過來,這是調度程序實例,該實例由VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE定義,該實例必須在您的來源中精確使用一次。另一方面,如果將VULKAN_HPP_DISPATCH_LOADER_DYNAMIC定義為與1不同的事物,則將VULKAN_HPP_DEFAULT_DISPATCHER設置為DispatchLoaderStatic() 。您可以通過將VULKAN_HPP_DEFAULT_DISPATCHER設置為提供相同API的對象來使用自己的默認調度程序。如果您明確設置VULKAN_HPP_DEFAULT_DISPATCHER ,則需要相應地設置VULKAN_HPP_DEFAULT_DISPATCHER_TYPE 。
該名稱為VULKAN_HPP_DEFAULT_DISPATCHER指定的默認調度程序類型。根據默認值,它是dispatchloaderdynamic或dispatchloaderstatic,具體取決於VULKAN_HPP_DISPATCH_LOADER_DYNAMIC分別為1或1 。如果您明確設置VULKAN_HPP_DEFAULT_DISPATCHER ,則需要相應地設置VULKAN_HPP_DEFAULT_DISPATCHER_TYPE 。
如果您尚未定義自己的VULKAN_HPP_DEFAULT_DISPATCHER ,並且具有定義為1 (默認值)的VULKAN_HPP_DISPATCH_LOADER_DYNAMIC ,您需要在任何源文件中提供宏觀VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE以便在任何源文件中提供一個forcepters in of源文件。然後, VULKAN_HPP_STORAGE_API控制該默認調度程序的導入/導出狀態。
在包含vulkan.hpp之前定義此之前,您基本上禁用所有增強功能。然後您得到的只是:
vk::Flags for BitMasks的使用;vk::StructureChain用於編譯結構鏈的構造。如果未定義,您還會得到:
vk::ArrayProxy<> ),簡化了對數組數據的處理;返回請求的數據;在錯誤上拋出例外(只要未定義VULKAN_HPP_NO_EXCEPTIONS );VULKAN_HPP_NO_STRUCT_CONSTRUCTORS )(消耗vk::ArrayProxyNoTemporaries<> );vk::ArrayProxyNoTemporaries<> )上;vk::ArrayProxy<>和vk::ArrayProxyNoTemporaries<>vulkan_raii.hpp中的所有raii-stuff 這要么選擇動態(當它是1 )或靜態(當它不是1 )dispatchloader作為默認一個,只要它未由VULKAN_HPP_DEFAULT_DISPATCHER明確指定。默認情況下,如果定義了VK_NO_PROTOTYPES ,則將其定義為1 ,否則為0 。
默認情況下,使用一個小幫手類DynamicLoader用於動態加載Vulkan庫。如果將其設置為與vulkan.hpp在內的1不同的東西,則該助手不可用,並且您需要明確提供自己的加載程序類型,以供函數DispatchLoaderDynamic::init() 。
當它不是外部定義的,而VULKAN_HPP_CPP_VERSION至少為23 ,則將VULKAN_HPP_EXPECTED定義為std::expected ,而VULKAN_HPP_UNEXPECTED將其定義為std::unexpected 。
默認情況下, Flags類模板的m_mask成員是私有的。這是為了防止意外設置具有某些不適當價值的Flags 。但是,它還可以防止使用Flags或持有Flags的結構,以用作非類型模板參數。如果您確實需要該功能並接受降低的安全性,則可以使用此定義將m_mask的訪問說明器從私有到公共更改,該規範允許將Flags用作非類型模板參數。
該定義可用於在Vulkan-HPP句柄的移動構造函數中啟用m_handle = exchange( rhs.m_handle, {} ) ,該構造符默認initialialialdiale initialial intialing rhs基礎值。默認情況下,Vulkan-HPP手柄的行為就像瑣碎的類型 - 移動構造函數複製值。
該定義可用於指定您自己的哈希組合函數。為了確定VK結構的哈希,該結構的成員的哈希是要組合的。這是由此定義完成的,默認情況下,該定義與函數boost::hash_combine()所做的相同。它獲得了構成綜合的值的類型,即種子,這是直至該點的組合值,最後是結合的值。該哈希計算決定了“淺”哈希,因為它採用了結構中任何指針的哈希,而不是指向值的哈希。
這設置為用於將函數標記為內聯的編譯器依賴性屬性。如果您的編譯器碰巧需要一些不同的屬性,則可以在包含vulkan.hpp之前相應地設置此定義。
默認情況下,使用vulkan.hpp使用的名稱空間為vk 。通過在包含vulkan.hpp之前定義VULKAN_HPP_NAMESPACE ,您可以調整此功能。
默認情況下, vulkan_to_string.hpp的文件包含vulkan.hpp ,並提供函數vk::to_string用於枚舉和刻度。如果您不需要這些功能,則可以定義VULKAN_HPP_NO_TO_STRING ,以防止包含。如果您有某些要使用這些功能的文件,則可以在其中明確包含vulkan_to_string.hpp 。
使用C ++ 20,可以使用指定的初始化器。他們的使用需要沒有任何用戶定義的構造函數。定義VULKAN_HPP_NO_CONSTRUCTORS從結構和工會中刪除構造函數。
當Vulkan函數返回未指定為成功代碼的錯誤代碼時,除非在包含vulkan.hpp之前定義VULKAN_HPP_NO_EXCEPTIONS ,否則會拋出異常。
使用C ++ 17,所有VK命令都以屬性[[nodiscard]]聲明了一些返回某物。可以通過在包括vulkan.hpp之前定義VULKAN_HPP_NO_NODISCARD_WARNINGS來刪除這一點。
通過在包含vulkan.hpp之前定義VULKAN_HPP_NO_SETTERS ,setter成員函數將在結構和工會中不可用。然後,僅通過直接分配來修改其數據成員。
通過在包含vulkan.hpp之前定義VULKAN_HPP_NO_SMART_HANDLE ,helper class vk::UniqueHandle和所有唯一的手柄類型都不可用。
使用C ++ 20,引入了所謂的太空飛船<=> 。如果支持該操作員,則Vulkan.hpp中的所有結構和類都使用其默認實現。由於目前,該操作員的某些實現非常慢,而其他實現似乎是不完整的,在包含vulkan.hpp之前,通過定義VULKAN_HPP_NO_SPACESHIP_OPERATOR ,您可以從這些結構和類中刪除該操作員。
默認情況下,如果win32上啟用了VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL ,則vulkan.hpp聲明HINSTANCE , LoadLibraryA和其他所需的符號。它可能會引起Windows.h替代方案(例如WindowsHModular的衝突。有了這個定義,您可以禁用這些聲明,但是您必須在包括vulkan.hpp之前聲明它們。
如果兩者都定義了VULKAN_HPP_NO_EXCEPTIONS和VULKAN_HPP_EXPECTED ,則VK :: raii-classes不會引發異常。也就是說,實際的構造函數不可用,但是必須使用創建功能。有關更多詳細信息,請查看vk_raii_ProgrammingGuide.md 。
即使vk::UniqueHandle and vk::SharedHandle在語義上接近指針,但基礎vk::Handle的隱性鑄造操作員可能很方便。您可以通過定義VULKAN_HPP_SMART_HANDLE_IMPLICIT_CAST來添加隱式鑄造運算符。
通過此定義,您可以指定DispatchLoaderDynamic是導入還是導出(請參閱VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE )。如果未__attribute__( ( visibility( "default" ) ) )外部定義VULKAN_HPP_STORAGE_API ,並且定義了VULKAN_HPP_STORAGE_SHARED ,具體取決於定義__declspec( dllexport ) VULKAN_HPP_STORAGE_SHARED_EXPORT VULKAN_HPP_STORAGE_API (對於GCC或Clang)或__declspec( dllimport ) (對於MSVC)。對於其他編譯器,您可以通過自己定義VULKAN_HPP_STORAGE_API來指定相應的存儲。
32位VULKAN對於不可添加的手柄而言並不是類型,因此默認情況下,我們不允許在此平台上複製構造函數。要在32位平台上啟用此功能, #define VULKAN_HPP_TYPESAFE_CONVERSION 1 。要在64位平台上禁用此功能, #define VULKAN_HPP_TYPESAFE_CONVERSION 0 。
請參閱VULKAN_HPP_EXPECTED 。
通過此定義,您可以在VK結構上包含反射機制。它添加了一個reflect函數,該功能返回結構的元組轉換。然後很容易迭代該元組。但是至少目前,該功能需要大量的編譯時間資源,因此目前建議只有在您願意支付該價格的情況下才能啟用該功能。
隨時提交PR以添加到此列表中。
版權所有2015-2020 Khronos Group Inc.
根據Apache許可證(版本2.0(“許可”)獲得許可;除了符合許可外,您不得使用此文件。您可以在
http://www.apache.org/licenses/LICENSE-2.0
除非適用法律要求或以書面形式同意,否則根據許可證分配的軟件是按照“原樣”分發的,沒有任何明示或暗示的保證或條件。請參閱許可證,以獲取執行許可條款和限制的特定語言。