Fix typo in README.md (#179)

This commit is contained in:
Olivier FAURE 2018-02-07 08:29:50 +01:00 committed by Andreas Süßenbach
parent 75cb7d14f1
commit bae68b49aa

722
README.md
View File

@ -1,364 +1,364 @@
# Vulkan-Hpp: C++ Bindings for Vulkan # Vulkan-Hpp: C++ Bindings for Vulkan
The goal of the Vulkan-Hpp is to provide header only C++ bindings for the Vulkan C API to improve the developers Vulkan experience without introducing CPU runtime cost. It adds features like type safety for enums and bitfields, STL container support, exceptions and simple enumerations. The goal of the Vulkan-Hpp is to provide header only C++ bindings for the Vulkan C API to improve the developers Vulkan experience without introducing CPU runtime cost. It adds features like type safety for enums and bitfields, STL container support, exceptions and simple enumerations.
| Platform | Build Status | | Platform | Build Status |
|:--------:|:------------:| |:--------:|:------------:|
| Linux | [![Build Status](https://travis-ci.org/KhronosGroup/Vulkan-Hpp.svg?branch=master)](https://travis-ci.org/KhronosGroup/Vulkan-Hpp) | | Linux | [![Build Status](https://travis-ci.org/KhronosGroup/Vulkan-Hpp.svg?branch=master)](https://travis-ci.org/KhronosGroup/Vulkan-Hpp) |
## Getting Started ## Getting Started
Vulkan-Hpp is part of the LunarG Vulkan SDK since version 1.0.24. Just `#include <vulkan/vulkan.hpp>` and you're ready to use the C++ bindings. If you're using a Vulkan version not yet supported by the Vulkan SDK you can find the latest version of the header [here](https://github.com/KhronosGroup/Vulkan-Hpp/blob/master/vulkan/vulkan.hpp). Vulkan-Hpp is part of the LunarG Vulkan SDK since version 1.0.24. Just `#include <vulkan/vulkan.hpp>` and you're ready to use the C++ bindings. If you're using a Vulkan version not yet supported by the Vulkan SDK you can find the latest version of the header [here](https://github.com/KhronosGroup/Vulkan-Hpp/blob/master/vulkan/vulkan.hpp).
### Minimum Requirements ### Minimum Requirements
Vulkan-Hpp requires a C++11 capable compiler to compile. The following compilers are known to work: Vulkan-Hpp requires a C++11 capable compiler to compile. The following compilers are known to work:
* Visual Studio >=2015 * Visual Studio >=2015
* GCC >= 4.8.2 (earlier version might work, but are untested) * GCC >= 4.8.2 (earlier version might work, but are untested)
* Clang >= 3.3 * Clang >= 3.3
## Usage ## Usage
### namespace vk ### namespace vk
To avoid name collisions with the Vulkan C API the C++ bindings reside in the vk namespace. The following rules apply to the new naming To avoid name collisions with the Vulkan C API the C++ bindings reside in the vk namespace. The following rules apply to the new naming
* All functions, enums, handles, and structs have the Vk prefix removed. In addition to this the first leter of functions is lower case. * All functions, enums, handles, and structs have the Vk prefix removed. In addition to this the first leter of functions is lower case.
* `vkCreateImage` can be accessed as `vk::createImage` * `vkCreateImage` can be accessed as `vk::createImage`
* `VkImageTiling` can be accessed as `vk::ImageTiling` * `VkImageTiling` can be accessed as `vk::ImageTiling`
* `VkImageCreateInfo` can be accessed as `vk::ImageCreateInfo` * `VkImageCreateInfo` can be accessed as `vk::ImageCreateInfo`
* Enums are mapped to scoped enums to provide compile time type safety. The names have been changed to 'e' + CamelCase with the VK_ prefix and type infix removed. In case the enum type is an extension the extension suffix has been removed from the enum values. * Enums are mapped to scoped enums to provide compile time type safety. The names have been changed to 'e' + CamelCase with the VK_ prefix and type infix removed. In case the enum type is an extension the extension suffix has been removed from the enum values.
In all other cases the extension suffix has not been removed. In all other cases the extension suffix has not been removed.
* `VK_IMAGETYPE_2D` is now `vk::ImageType::e2D`. * `VK_IMAGETYPE_2D` is now `vk::ImageType::e2D`.
* `VK_COLOR_SPACE_SRGB_NONLINEAR_KHR` is now `vk::ColorSpaceKHR::eSrgbNonlinear`. * `VK_COLOR_SPACE_SRGB_NONLINEAR_KHR` is now `vk::ColorSpaceKHR::eSrgbNonlinear`.
* `VK_STRUCTURE_TYPE_PRESENT_INFO_KHR` is now `vk::StructureType::ePresentInfoKHR`. * `VK_STRUCTURE_TYPE_PRESENT_INFO_KHR` is now `vk::StructureType::ePresentInfoKHR`.
* Flag bits are handled like scoped enums with the addition that the `_BIT` suffix has also been removed. * Flag bits are handled like scoped enums with the addition that the `_BIT` suffix has also been removed.
In some cases it might be necessary to move Vulkan-Hpp to a custom namespace. This can be achieved by defining VULKAN_HPP_NAMESPACE before including Vulkan-Hpp. In some cases it might be necessary to move Vulkan-Hpp to a custom namespace. This can be achieved by defining VULKAN_HPP_NAMESPACE before including Vulkan-Hpp.
### Handles ### Handles
Vulkan-Hpp declares a class for all handles to ensure full type safety and to add support for member functions on handles. A member function has been added to a handle class for each function which accepts the corresponding handle as first parameter. Instead of `vkBindBufferMemory(device, ...)` one can write `device.bindBufferMemory(...)` or `vk::bindBufferMemory(device, ...)`. Vulkan-Hpp declares a class for all handles to ensure full type safety and to add support for member functions on handles. A member function has been added to a handle class for each function which accepts the corresponding handle as first parameter. Instead of `vkBindBufferMemory(device, ...)` one can write `device.bindBufferMemory(...)` or `vk::bindBufferMemory(device, ...)`.
### C/C++ Interop for Handles ### C/C++ Interop for Handles
On 64-bit platforms Vulkan-Hpp supports implicit conversions between C++ Vulkan handles and C Vulkan handles. On 32-bit platforms all non-dispatchable handles are defined as `uint64_t`, thus preventing type-conversion checks at compile time which would catch assignments between incompatible handle types.. Due to that Vulkan-Hpp does not enable implicit conversion for 32-bit platforms by default and it is recommended to use a `static_cast` for the conversion like this: `VkDevice = static_cast<VkDevice>(cppDevice)` to prevent converting some arbitrary int to a handle or vice versa by accident. If you're developing your code on a 64-bit platform, but want compile your code for a 32-bit platform without adding the explicit casts you can define `VULKAN_HPP_TYPESAFE_CONVERSION` to 1 in your build system or before including `vulkan.hpp`. On 64-bit platforms this define is set to 1 by default and can be set to 0 to disable implicit conversions. On 64-bit platforms Vulkan-Hpp supports implicit conversions between C++ Vulkan handles and C Vulkan handles. On 32-bit platforms all non-dispatchable handles are defined as `uint64_t`, thus preventing type-conversion checks at compile time which would catch assignments between incompatible handle types.. Due to that Vulkan-Hpp does not enable implicit conversion for 32-bit platforms by default and it is recommended to use a `static_cast` for the conversion like this: `VkDevice = static_cast<VkDevice>(cppDevice)` to prevent converting some arbitrary int to a handle or vice versa by accident. If you're developing your code on a 64-bit platform, but want compile your code for a 32-bit platform without adding the explicit casts you can define `VULKAN_HPP_TYPESAFE_CONVERSION` to 1 in your build system or before including `vulkan.hpp`. On 64-bit platforms this define is set to 1 by default and can be set to 0 to disable implicit conversions.
### Flags ### Flags
The scoped enum feature adds type safety to the flags, but also prevents using the flag bits as input for bitwise operations like & and |. The scoped enum feature adds type safety to the flags, but also prevents using the flag bits as input for bitwise operations like & and |.
As solution Vulkan-Hpp provides a template class `vk::Flags` which brings the standard operations like `&=`, `|=`, `&` and `|` to our scoped enums. Except for the initialization with 0 this class behaves exactly like a normal bitmask with the improvement that it is impossible to set bits not specified by the corresponding enum by accident. Here are a few examples for the bitmask handling: As solution Vulkan-Hpp provides a template class `vk::Flags` which brings the standard operations like `&=`, `|=`, `&` and `|` to our scoped enums. Except for the initialization with 0 this class behaves exactly like a normal bitmask with the improvement that it is impossible to set bits not specified by the corresponding enum by accident. Here are a few examples for the bitmask handling:
```c++ ```c++
vk::ImageUsage iu1; // initialize a bitmask with no bit set vk::ImageUsage iu1; // initialize a bitmask with no bit set
vk::ImageUsage iu2 = {}; // initialize a bitmask with no bit set vk::ImageUsage iu2 = {}; // initialize a bitmask with no bit set
vk::ImageUsage iu3 = vk::ImageUsage::eColorAttachment; // initialize with a single value vk::ImageUsage iu3 = vk::ImageUsage::eColorAttachment; // initialize with a single value
vk::ImageUsage iu4 = vk::ImageUsage::eColorAttachment | vk::ImageUsage::eStorage; // or two bits to get a bitmask vk::ImageUsage iu4 = vk::ImageUsage::eColorAttachment | vk::ImageUsage::eStorage; // or two bits to get a bitmask
PipelineShaderStageCreateInfo ci( {} /* pass a flag without any bits set */, ...); PipelineShaderStageCreateInfo ci( {} /* pass a flag without any bits set */, ...);
``` ```
### CreateInfo structs ### CreateInfo structs
When constructing a handle in Vulkan one usually has to create some `CreateInfo` struct which describes the new handle. This can result in quite lengthy code as can be seen in the following Vulkan C example: When constructing a handle in Vulkan one usually has to create some `CreateInfo` struct which describes the new handle. This can result in quite lengthy code as can be seen in the following Vulkan C example:
```c++ ```c++
VkImageCreateInfo ci; VkImageCreateInfo ci;
ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
ci.pNext = nullptr; ci.pNext = nullptr;
ci.flags = ...some flags...; ci.flags = ...some flags...;
ci.imageType = VK_IMAGE_TYPE_2D; ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_R8G8B8A8_UNORM; ci.format = VK_FORMAT_R8G8B8A8_UNORM;
ci.extent = VkExtent3D { width, height, 1 }; ci.extent = VkExtent3D { width, height, 1 };
ci.mipLevels = 1; ci.mipLevels = 1;
ci.arrayLayers = 1; ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT; ci.samples = VK_SAMPLE_COUNT_1_BIT;
ci.tiling = VK_IMAGE_TILING_OPTIMAL; ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ci.queueFamilyIndexCount = 0; ci.queueFamilyIndexCount = 0;
ci.pQueueFamilyIndices = 0; ci.pQueueFamilyIndices = 0;
ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vkCreateImage(device, &ci, allocator, &image)); vkCreateImage(device, &ci, allocator, &image));
``` ```
There are two typical issues Vulkan developers encounter when filling out a CreateInfo struct field by field There are two typical issues Vulkan developers encounter when filling out a CreateInfo struct field by field
* One or more fields are left uninitialized. * One or more fields are left uninitialized.
* `sType` is incorrect. * `sType` is incorrect.
Especially the first one is hard to detect. Especially the first one is hard to detect.
Vulkan-Hpp provides constructors for all CreateInfo objects which accept one parameter for each member variable. This way the compiler throws a compiler error if a value has been forgotten. In addition to this `sType` is automatically filled with the correct value and `pNext` set to a `nullptr` by default. Here's how the same code looks with a constructor: Vulkan-Hpp provides constructors for all CreateInfo objects which accept one parameter for each member variable. This way the compiler throws a compiler error if a value has been forgotten. In addition to this `sType` is automatically filled with the correct value and `pNext` set to a `nullptr` by default. Here's how the same code looks with a constructor:
```c++ ```c++
vk::ImageCreateInfo ci({}, vk::ImageType::e2D, vk::format::eR8G8B8A8Unorm, vk::ImageCreateInfo ci({}, vk::ImageType::e2D, vk::format::eR8G8B8A8Unorm,
{ width, height, 1 }, { width, height, 1 },
1, 1, vk::SampleCount::e1, 1, 1, vk::SampleCount::e1,
vk::ImageTiling::eOptimal, vk::ImageUsage:eColorAttachment, vk::ImageTiling::eOptimal, vk::ImageUsage:eColorAttachment,
vk::SharingMode::eExclusive, 0, 0, vk::Imagelayout::eUndefined); vk::SharingMode::eExclusive, 0, 0, vk::Imagelayout::eUndefined);
``` ```
With constructors for CreateInfo structures one can also pass temporaries to Vulkan functions like this: With constructors for CreateInfo structures one can also pass temporaries to Vulkan functions like this:
```c++ ```c++
vk::Image image = device.createImage({{}, vk::ImageType::e2D, vk::format::eR8G8B8A8Unorm, vk::Image image = device.createImage({{}, vk::ImageType::e2D, vk::format::eR8G8B8A8Unorm,
{ width, height, 1 }, { width, height, 1 },
1, 1, vk::SampleCount::e1, 1, 1, vk::SampleCount::e1,
vk::ImageTiling::eOptimal, vk::ImageUsage:eColorAttachment, vk::ImageTiling::eOptimal, vk::ImageUsage:eColorAttachment,
vk::SharingMode::eExclusive, 0, 0, vk::Imagelayout::eUndefined}); vk::SharingMode::eExclusive, 0, 0, vk::Imagelayout::eUndefined});
``` ```
### Passing Arrays to Functions using ArrayProxy ### Passing Arrays to Functions using ArrayProxy
The Vulkan API has several places where which require (count,pointer) as two function arguments and C++ has a few containers which map perfectly to this pair. To simplify development the Vulkan-Hpp bindings have replaced those argument pairs with the `ArrayProxy` template class which accepts empty arrays and a single value as well as STL containers `std::initializer_list`, `std::array` and `std::vector` as argument for construction. This way a single generated Vulkan version can accept a variety of inputs without having the combinatoric explosion which would occur when creating a function for each container type. The Vulkan API has several places where which require (count,pointer) as two function arguments and C++ has a few containers which map perfectly to this pair. To simplify development the Vulkan-Hpp bindings have replaced those argument pairs with the `ArrayProxy` template class which accepts empty arrays and a single value as well as STL containers `std::initializer_list`, `std::array` and `std::vector` as argument for construction. This way a single generated Vulkan version can accept a variety of inputs without having the combinatoric explosion which would occur when creating a function for each container type.
Here are some code samples on how to use the ArrayProxy: Here are some code samples on how to use the ArrayProxy:
```c++ ```c++
vk::CommandBuffer c; vk::CommandBuffer c;
// pass an empty array // pass an empty array
c.setScissor(0, nullptr); c.setScissor(0, nullptr);
// pass a single value. Value is passed as reference // pass a single value. Value is passed as reference
vk::Rect2D scissorRect = { {0, 0}, {640, 480} }; vk::Rect2D scissorRect = { {0, 0}, {640, 480} };
c.setScissor(0, scissorRect); c.setScissor(0, scissorRect);
// pass a temporary value. // pass a temporary value.
c.setScissor(0, { { 0, 0 },{ 640, 480 } }); c.setScissor(0, { { 0, 0 },{ 640, 480 } });
// generate a std::initializer_list using two rectangles from the stack. This might generate a copy of the rectangles. // 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 scissorRect1 = { { 0, 0 },{ 320, 240 } };
vk::Rect2D scissorRect2 = { { 320, 240 },{ 320, 240 } }; vk::Rect2D scissorRect2 = { { 320, 240 },{ 320, 240 } };
c.setScissor(0, { scissorRect, scissorRect2 }); c.setScissor(0, { scissorRect, scissorRect2 });
// construct a std::initializer_list using two temporary rectangles. // construct a std::initializer_list using two temporary rectangles.
c.setScissor(0, { { { 0, 0 },{ 320, 240 } }, c.setScissor(0, { { { 0, 0 },{ 320, 240 } },
{ { 320, 240 },{ 320, 240 } } { { 320, 240 },{ 320, 240 } }
} }
); );
// pass a std::array // pass a std::array
std::array<vk::Rect2D, 2> arr{ scissorRect1, scissorRect2 }; std::array<vk::Rect2D, 2> arr{ scissorRect1, scissorRect2 };
c.setScissor(0, arr); c.setScissor(0, arr);
// pass a std::vector of dynamic size // pass a std::vector of dynamic size
std::vector<vk::Rect2D> vec; std::vector<vk::Rect2D> vec;
vec.push_back(scissorRect1); vec.push_back(scissorRect1);
vec.push_back(scissorRect2); vec.push_back(scissorRect2);
c.setScissor(0, vec); c.setScissor(0, vec);
``` ```
### Passing Structs to Functions ### Passing Structs to Functions
Vulkan-Hpp generates references for pointers to structs. This conversion allows passing temporary structs to functions which can result in shorter code. In case the input is optional and thus accepting a null pointer the parameter type will be a `vk::Optional<T> const&` type. This type accepts either a reference to `T` or nullptr as input and thus allows optional temporary structs. Vulkan-Hpp generates references for pointers to structs. This conversion allows passing temporary structs to functions which can result in shorter code. In case the input is optional and thus accepting a null pointer the parameter type will be a `vk::Optional<T> const&` type. This type accepts either a reference to `T` or nullptr as input and thus allows optional temporary structs.
```c++ ```c++
// C // C
ImageSubResource subResource; ImageSubResource subResource;
subResource.aspectMask = 0; subResource.aspectMask = 0;
subResource.mipLevel = 0; subResource.mipLevel = 0;
subResource.arrayLayer = 0; subResource.arrayLayer = 0;
vkSubresourceLayout layout = vkGetImageSubResourceLayout(image, subresource); vkSubresourceLayout layout = vkGetImageSubResourceLayout(image, subresource);
// C++ // C++
auto layout = device.getImageSubResourceLayout(image, { {} /* flags*/, 0 /* miplevel */, 0 /* layout */ }); auto layout = device.getImageSubResourceLayout(image, { {} /* flags*/, 0 /* miplevel */, 0 /* layout */ });
``` ```
### Structure Pointer Chains ### Structure Pointer Chains
Vulkan allows chaining of structures through the pNext pointer. Vulkan-Hpp has a variadic template class which allows constructing of such structure chains with minimal efforts. In addition to this it checks at compile time if the spec allows the construction of such a `pNext` chain. Vulkan allows chaining of structures through the pNext pointer. Vulkan-Hpp has a variadic template class which allows constructing of such structure chains with minimal efforts. In addition to this it checks at compile time if the spec allows the construction of such a `pNext` chain.
``` ```
// This will compile successfully. // This will compile successfully.
vk::StructureChain<vk::MemoryAllocateInfo, vk::ImportMemoryFdInfoKHR> c; vk::StructureChain<vk::MemoryAllocateInfo, vk::ImportMemoryFdInfoKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>(); vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>(); vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>();
// This will fail compilation since it's not valid according to the spec. // This will fail compilation since it's not valid according to the spec.
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedRequirementsKHR> c; vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedRequirementsKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>(); vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>(); vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>();
``` ```
Sometimes the user has to pass a preallocated structure chain to query information. In those cases the corresponding query functions are variadic templates and do accept a structure chain to construct the return value: Sometimes the user has to pass a preallocated structure chain to query information. In those cases the corresponding query functions are variadic templates and do accept a structure chain to construct the return value:
``` ```
// Query vk::MemoryRequirements2KHR and vk::MemoryDedicatedRequirementsKHR when calling Device::getBufferMemoryRequirements2KHR: // Query vk::MemoryRequirements2KHR and vk::MemoryDedicatedRequirementsKHR when calling Device::getBufferMemoryRequirements2KHR:
auto result = device.getBufferMemoryRequirements2KHR<vk::MemoryRequirements2KHR, vk::MemoryDedicatedRequirementsKHR>({}); auto result = device.getBufferMemoryRequirements2KHR<vk::MemoryRequirements2KHR, vk::MemoryDedicatedRequirementsKHR>({});
vk::MemoryRequirements2KHR &memReqs = result.get<vk::MemoryRequirements2KHR>(); vk::MemoryRequirements2KHR &memReqs = result.get<vk::MemoryRequirements2KHR>();
vk::MemoryDedicatedRequirementsKHR &dedMemReqs = result.get<vk::MemoryDedicatedRequirementsKHR>(); vk::MemoryDedicatedRequirementsKHR &dedMemReqs = result.get<vk::MemoryDedicatedRequirementsKHR>();
``` ```
### Return values, Error Codes & Exceptions ### Return values, Error Codes & Exceptions
By default Vulkan-Hpp has exceptions enabled. This means that Vulkan-Hpp checks the return code of each function call which returns a Vk::Result. If Vk::Result is a failure a std::runtime_error will be thrown. Since there is no need to return the error code anymore the C++ bindings can now return the actual desired return value, i.e. a vulkan handle. In those cases ResultValue <SomeType>::type is defined as the returned type. By default Vulkan-Hpp has exceptions enabled. This means that Vulkan-Hpp checks the return code of each function call which returns a Vk::Result. If Vk::Result is a failure a std::runtime_error will be thrown. Since there is no need to return the error code anymore the C++ bindings can now return the actual desired return value, i.e. a vulkan handle. In those cases ResultValue <SomeType>::type is defined as the returned type.
To create a device you can now just write: To create a device you can now just write:
```C++ ```C++
vk::Device device = physicalDevice.createDevice(createInfo); vk::Device device = physicalDevice.createDevice(createInfo);
``` ```
If exception handling is disabled by defining `VULKAN_HPP_NO_EXCEPTIONS` the type of `ResultValue<SomeType>::type` is a struct holding a `vk::Result` and a `SomeType`. This struct supports unpacking the return values by using `std::tie`. If exception handling is disabled by defining `VULKAN_HPP_NO_EXCEPTIONS` the type of `ResultValue<SomeType>::type` is a struct holding a `vk::Result` and a `SomeType`. This struct supports unpacking the return values by using `std::tie`.
In case you dont want to use the `vk::ArrayProxy` and return value transformation you can still call the plain C-style function. Below are three examples showing the 3 ways to use the API: In case you dont want to use the `vk::ArrayProxy` and return value transformation you can still call the plain C-style function. Below are three examples showing the 3 ways to use the API:
The first snippet shows how to use the API without exceptions and the return value transformation: The first snippet shows how to use the API without exceptions and the return value transformation:
```c++ ```c++
// No exceptions, no return value transformation // No exceptions, no return value transformation
ShaderModuleCreateInfo createInfo(...); ShaderModuleCreateInfo createInfo(...);
ShaderModule shader1; ShaderModule shader1;
Result result = device.createShaderModule(&createInfo, allocator, &shader1); Result result = device.createShaderModule(&createInfo, allocator, &shader1);
if (result.result != VK_SUCCESS) if (result.result != VK_SUCCESS)
{ {
handle error code; handle error code;
cleanup? cleanup?
return? return?
} }
ShaderModule shader2; ShaderModule shader2;
Result result = device.createShaderModule(&createInfo, allocator, &shader2); Result result = device.createShaderModule(&createInfo, allocator, &shader2);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
handle error code; handle error code;
cleanup? cleanup?
return? return?
} }
``` ```
The second snippet shows how to use the API using return value transformation, but without exceptions. Its already a little bit shorter than the original code: The second snippet shows how to use the API using return value transformation, but without exceptions. Its already a little bit shorter than the original code:
```c++ ```c++
ResultValue<ShaderModule> shaderResult1 = device.createShaderModule({...} /* createInfo temporary */); ResultValue<ShaderModule> shaderResult1 = device.createShaderModule({...} /* createInfo temporary */);
if (shaderResult1.result != VK_SUCCESS) if (shaderResult1.result != VK_SUCCESS)
{ {
handle error code; handle error code;
cleanup? cleanup?
return? return?
} }
// std::tie support. // std::tie support.
vk::Result result; vk::Result result;
vk::ShaderModule shaderModule2; vk::ShaderModule shaderModule2;
std::tie(result, shaderModule2) = device.createShaderModule({...} /* createInfo temporary */); std::tie(result, shaderModule2) = device.createShaderModule({...} /* createInfo temporary */);
if (shaderResult2.result != VK_SUCCESS) if (shaderResult2.result != VK_SUCCESS)
{ {
handle error code; handle error code;
cleanup? cleanup?
return? return?
} }
``` ```
A nicer way to unpack the result is provided by the structured bindings of C++17. They will allow us to get the result with a single line of code: A nicer way to unpack the result is provided by the structured bindings of C++17. They will allow us to get the result with a single line of code:
```c++ ```c++
auto [result, shaderModule2] = device.createShaderModule({...} /* createInfo temporary */); auto [result, shaderModule2] = device.createShaderModule({...} /* createInfo temporary */);
``` ```
Finally, the last code example is using exceptions and return value transformation. This is the default mode of the API. Finally, the last code example is using exceptions and return value transformation. This is the default mode of the API.
```c++ ```c++
ShaderModule shader1; ShaderModule shader1;
ShaderModule shader2; ShaderModule shader2;
try { try {
myHandle = device.createShaderModule({...}); myHandle = device.createShaderModule({...});
myHandle2 = device.createShaderModule({...}); myHandle2 = device.createShaderModule({...});
} catch(std::exception const &e) { } catch(std::exception const &e) {
// handle error and free resources // handle error and free resources
} }
``` ```
Keep in mind that Vulkan-Hpp does not support RAII style handles and that you have to cleanup your resources in the error handler! Keep in mind that Vulkan-Hpp does not support RAII style handles and that you have to cleanup your resources in the error handler!
### Enumerations ### Enumerations
For the return value transformation, there's one special class of return values which require special handling: Enumerations. For enumerations you usually have to write code like this: For the return value transformation, there's one special class of return values which require special handling: Enumerations. For enumerations you usually have to write code like this:
```c++ ```c++
std::vector<LayerProperties,Allocator> properties; std::vector<LayerProperties,Allocator> properties;
uint32_t propertyCount; uint32_t propertyCount;
Result result; Result result;
do do
{ {
// determine number of elements to query // determine number of elements to query
result = static_cast<Result>( vk::enumerateDeviceLayerProperties( m_physicalDevice, &propertyCount, nullptr ) ); result = static_cast<Result>( vk::enumerateDeviceLayerProperties( m_physicalDevice, &propertyCount, nullptr ) );
if ( ( result == Result::eSuccess ) && propertyCount ) if ( ( result == Result::eSuccess ) && propertyCount )
{ {
// allocate memory & query again // allocate memory & query again
properties.resize( propertyCount ); properties.resize( propertyCount );
result = static_cast<Result>( vk::enumerateDeviceLayerProperties( m_physicalDevice, &propertyCount, reinterpret_cast result = static_cast<Result>( vk::enumerateDeviceLayerProperties( m_physicalDevice, &propertyCount, reinterpret_cast
<VkLayerProperties*>( properties.data() ) ) ); <VkLayerProperties*>( properties.data() ) ) );
} }
} while ( result == Result::eIncomplete ); } while ( result == Result::eIncomplete );
// it's possible that the count has changed, start again if properties was not big enough // it's possible that the count has changed, start again if properties was not big enough
properties.resize(propertyCount); properties.resize(propertyCount);
``` ```
Since writing this loop over and over again is tedious and error prone the C++ binding takes care of the enumeration so that you can just write: Since writing this loop over and over again is tedious and error prone the C++ binding takes care of the enumeration so that you can just write:
```c++ ```c++
std::vector<LayerProperties> properties = physicalDevice.enumerateDeviceLayerProperties(); std::vector<LayerProperties> properties = physicalDevice.enumerateDeviceLayerProperties();
``` ```
### UniqueHandle for automatic resource management ### UniqueHandle for automatic resource management
Vulkan-Hpp provides a `vk::UniqueHandle<Type, Deleter>` interface. For each Vulkan handle type `vk::Type` there is a unqiue handle `vk::UniqueType` which will delete the underlying Vulkan resource upon destruction, e.g. `vk::UniqueBuffer ` is the unique handle for `vk::Buffer`. Vulkan-Hpp provides a `vk::UniqueHandle<Type, Deleter>` interface. For each Vulkan handle type `vk::Type` there is a unqiue handle `vk::UniqueType` which will delete the underlying Vulkan resource upon destruction, e.g. `vk::UniqueBuffer ` is the unique handle for `vk::Buffer`.
For each function which constructs a Vulkan handle of type `vk::Type` Vulkan-Hpp provides a second version which returns a `vk::UnqiueType`. E.g. for `vk::Device::createBuffer` there is `vk::Device::createBufferUnique` and for `vk::allocateCommandBuffers` there is `vk::allocateCommandBuffersUnique`. For each function which constructs a Vulkan handle of type `vk::Type` Vulkan-Hpp provides a second version which returns a `vk::UniqueType`. E.g. for `vk::Device::createBuffer` there is `vk::Device::createBufferUnique` and for `vk::allocateCommandBuffers` there is `vk::allocateCommandBuffersUnique`.
Note that using `vk::UniqueHandle` comes at a cost since most deleters have to store the `vk::AllocationCallbacks` and parent handle used for construction because they are required for automatic destruction. Note that using `vk::UniqueHandle` comes at a cost since most deleters have to store the `vk::AllocationCallbacks` and parent handle used for construction because they are required for automatic destruction.
### Custom allocators ### Custom allocators
Sometimes it is required to use `std::vector` with custom allocators. Vulkan-Hpp supports vectors with custom allocators as input for `vk::ArrayProxy` and for functions which do return a vector. For the latter case, add your favorite custom allocator as template argument to the function call like this: Sometimes it is required to use `std::vector` with custom allocators. Vulkan-Hpp supports vectors with custom allocators as input for `vk::ArrayProxy` and for functions which do return a vector. For the latter case, add your favorite custom allocator as template argument to the function call like this:
```c++ ```c++
std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>(); std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>();
``` ```
### Custom assertions ### Custom assertions
All over vulkan.hpp, there are a couple of calls to an assert function. By defining VULKAN_HPP_ASSERT, you can specifiy your own custom assert function to be called instead. All over vulkan.hpp, there are a couple of calls to an assert function. By defining VULKAN_HPP_ASSERT, you can specifiy your own custom assert function to be called instead.
### Extensions / Per Device function pointers ### Extensions / Per Device function pointers
The Vulkan loader exposes only the Vulkan core functions and a limited number of extensions. To use Vulkan-Hpp with extensions it's required to have either a library which provides stubs to all used Vulkan The Vulkan loader exposes only the Vulkan core functions and a limited number of extensions. To use Vulkan-Hpp with extensions it's required to have either a library which provides stubs to all used Vulkan
functions or to tell Vulkan-Hpp to dispatch those functions pointers. Vulkan-Hpp provides a per-function dispatch mechanism by accepting a dispatch class as last parameter in each function call. The dispatch functions or to tell Vulkan-Hpp to dispatch those functions pointers. Vulkan-Hpp provides a per-function dispatch mechanism by accepting a dispatch class as last parameter in each function call. The dispatch
class must provide a callable type for each used Vulkan function. Vulkan-Hpp provides one implementation, ```DispatchLoaderDynamic```, which fetches all function pointers known to the library. class must provide a callable type for each used Vulkan function. Vulkan-Hpp provides one implementation, ```DispatchLoaderDynamic```, which fetches all function pointers known to the library.
```c++ ```c++
// This dispatch class will fetch all function pointers through the passed instance // This dispatch class will fetch all function pointers through the passed instance
vk::DispatchLoaderDynamic dldi(instance); vk::DispatchLoaderDynamic dldi(instance);
// This dispatch class will fetch function pointers for the passed device if possible, else for the passed instance // This dispatch class will fetch function pointers for the passed device if possible, else for the passed instance
vk::DispatchLoaderDynamic dldid(instance, device); vk::DispatchLoaderDynamic dldid(instance, device);
// Pass dispatch class to function call as last parameter // Pass dispatch class to function call as last parameter
device.getQueue(graphics_queue_family_index, 0, &graphics_queue, dldid); device.getQueue(graphics_queue_family_index, 0, &graphics_queue, dldid);
``` ```
## See Also ## See Also
Feel free to submit a PR to add to this list. Feel free to submit a PR to add to this list.
- [Vookoo](https://github.com/andy-thomason/Vookoo/) Stateful helper classes for Vulkan-Hpp, [Introduction Article](https://accu.org/index.php/journals/2380). - [Vookoo](https://github.com/andy-thomason/Vookoo/) Stateful helper classes for Vulkan-Hpp, [Introduction Article](https://accu.org/index.php/journals/2380).
## License ## License
Copyright 2015-2017 The Khronos Group Inc. Copyright 2015-2017 The Khronos Group Inc.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.