mirror of
https://github.com/KhronosGroup/Vulkan-Hpp.git
synced 2024-10-14 16:32:17 +00:00
Merge pull request #82 from asuessenbach/issue81
Fix issue #81, support Optional<string> for functions where strings are not required. Also remove static null() function in each struct. Use nullptr instead.
This commit is contained in:
commit
900744a8ca
412
README.md
412
README.md
@ -1,207 +1,207 @@
|
|||||||
# Open-Source Vulkan C++ API
|
# Open-Source Vulkan C++ API
|
||||||
|
|
||||||
Vulkan is a C API and as such inherits all common pitfalls of using a general C programming library. The motivation of a low-level Vulkan C++ API is to avoid these common pitfalls by applying commonly known C++ features while keeping the overall structure of a Vulkan program and preserving the full freedom it provides as low-level graphics API. An additional guideline we followed was not to introduce additional runtime overhead by providing a header-only library with inline functions.
|
Vulkan is a C API and as such inherits all common pitfalls of using a general C programming library. The motivation of a low-level Vulkan C++ API is to avoid these common pitfalls by applying commonly known C++ features while keeping the overall structure of a Vulkan program and preserving the full freedom it provides as low-level graphics API. An additional guideline we followed was not to introduce additional runtime overhead by providing a header-only library with inline functions.
|
||||||
|
|
||||||
Have a look at the following piece of code which creates a VkImage:
|
Have a look at the following piece of code which creates a VkImage:
|
||||||
|
|
||||||
```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 may be some issues that can happen when filling the structure which cannot be caught at compile time:
|
There may be some issues that can happen when filling the structure which cannot be caught at compile time:
|
||||||
|
|
||||||
* initialization of ```ci.sType``` using wrong enum values
|
* initialization of ```ci.sType``` using wrong enum values
|
||||||
* uninitialized data fields (e.g. missing initialization of ```ci.mipLevels```)
|
* uninitialized data fields (e.g. missing initialization of ```ci.mipLevels```)
|
||||||
* use of invalid bits for ```ci.flags``` (no type-safety for bits)
|
* use of invalid bits for ```ci.flags``` (no type-safety for bits)
|
||||||
* use of incorrect enums for fields (no type-safety for enums)
|
* use of incorrect enums for fields (no type-safety for enums)
|
||||||
|
|
||||||
These initializations will most likely show up as random runtime errors, which usually are nasty and time-consuming to debug.
|
These initializations will most likely show up as random runtime errors, which usually are nasty and time-consuming to debug.
|
||||||
Our auto-generated, C++ 11-conform layer uses commonly known C++ features like implicit initialization through constructors
|
Our auto-generated, C++ 11-conform layer uses commonly known C++ features like implicit initialization through constructors
|
||||||
to avoid incorrect or missing initializations and introduces type-safety with scoped enums to turn explicit initialization
|
to avoid incorrect or missing initializations and introduces type-safety with scoped enums to turn explicit initialization
|
||||||
errors into compile errors. Following is a list of features and conventions introduced by our Vulkan C++ layer:
|
errors into compile errors. Following is a list of features and conventions introduced by our Vulkan C++ layer:
|
||||||
|
|
||||||
* works along the official C version of the API
|
* works along the official C version of the API
|
||||||
* defines all symbols within the 'vk' namespace and to avoid redundancy the vk/Vk/VK_ prefixes have been removed from all symbols, i.e. ```vk::ImageCreateInfo``` for VkImageCreateInfo.
|
* defines all symbols within the 'vk' namespace and to avoid redundancy the vk/Vk/VK_ prefixes have been removed from all symbols, i.e. ```vk::ImageCreateInfo``` for VkImageCreateInfo.
|
||||||
* camel case syntax with an 'e' prefix has been introduced for all enums, i.e. ```vk::ImageType::e2D``` (the prefix was a compromise, more about that later) removes the 'BIT' suffix from all flag related enums, i.e. ```vk::ImageUsage::eColorAttachment```.
|
* camel case syntax with an 'e' prefix has been introduced for all enums, i.e. ```vk::ImageType::e2D``` (the prefix was a compromise, more about that later) removes the 'BIT' suffix from all flag related enums, i.e. ```vk::ImageUsage::eColorAttachment```.
|
||||||
* introduces constructors for all structs, which by default set the appropriate ```sType``` and all other values to zero.
|
* introduces constructors for all structs, which by default set the appropriate ```sType``` and all other values to zero.
|
||||||
* encapsulates member variables of the structs with getter and setter functions, i.e. ```ci.imageType()``` to get a value and ```ci.imageType(vk::ImageType::e2D)``` to set a value.
|
* encapsulates member variables of the structs with getter and setter functions, i.e. ```ci.imageType()``` to get a value and ```ci.imageType(vk::ImageType::e2D)``` to set a value.
|
||||||
* introduces wrapper classes around the vulkan handles, i.e. ```vk::CommandBuffer``` for VkCommandBuffer
|
* introduces wrapper classes around the vulkan handles, i.e. ```vk::CommandBuffer``` for VkCommandBuffer
|
||||||
* introduces member functions of those wrapper classes, that map to vulkan functions getting the corresponding vulkan handle as its first argument. The type of that handle is stripped from the function name, i.e. ```vk::Device::getProcAddr``` for vkGetDeviceProcAddr. Note the special handling for the class CommandBuffer, where most of the vulkan functions would just include "Cmd", instead of "CommandBuffer", i.e. ```vk::CommandBuffer::bindPipeline``` for vkCmdBindPipeline.
|
* introduces member functions of those wrapper classes, that map to vulkan functions getting the corresponding vulkan handle as its first argument. The type of that handle is stripped from the function name, i.e. ```vk::Device::getProcAddr``` for vkGetDeviceProcAddr. Note the special handling for the class CommandBuffer, where most of the vulkan functions would just include "Cmd", instead of "CommandBuffer", i.e. ```vk::CommandBuffer::bindPipeline``` for vkCmdBindPipeline.
|
||||||
With those changes applied, the updated code snippet looks like this:
|
With those changes applied, the updated code snippet looks like this:
|
||||||
|
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
vk::ImageCreateInfo ci;
|
vk::ImageCreateInfo ci;
|
||||||
ci.flags(...some flags...);
|
ci.flags(...some flags...);
|
||||||
ci.imageType(vk::ImageType::e2D);
|
ci.imageType(vk::ImageType::e2D);
|
||||||
ci.format(vk::Format::eR8G8B8A8Unorm);
|
ci.format(vk::Format::eR8G8B8A8Unorm);
|
||||||
ci.extent(vk::Extent3D { width, height, 1 });
|
ci.extent(vk::Extent3D { width, height, 1 });
|
||||||
ci.mipLevels(1);
|
ci.mipLevels(1);
|
||||||
ci.arrayLayers(1);
|
ci.arrayLayers(1);
|
||||||
ci.samples(1);
|
ci.samples(1);
|
||||||
ci.tiling(vk::ImageTiling::eOptimal);
|
ci.tiling(vk::ImageTiling::eOptimal);
|
||||||
ci.usage(vk::ImageUsage::eColorAttachment);
|
ci.usage(vk::ImageUsage::eColorAttachment);
|
||||||
ci.sharingMode(vk::SharingMode::eExclusive);
|
ci.sharingMode(vk::SharingMode::eExclusive);
|
||||||
// ci.queueFamilyIndexCount(0) // no need to set, already initialized
|
// ci.queueFamilyIndexCount(0) // no need to set, already initialized
|
||||||
// ci.pQueueFamilyIndices(0) // no need to set, already initialized
|
// ci.pQueueFamilyIndices(0) // no need to set, already initialized
|
||||||
ci.initialLayout(vk::ImageLayout::eUndefined);
|
ci.initialLayout(vk::ImageLayout::eUndefined);
|
||||||
device.createImage(&ci, allocator, &image);
|
device.createImage(&ci, allocator, &image);
|
||||||
```
|
```
|
||||||
|
|
||||||
Which is a total of 13 lines of code, versus 17 lines for the C version. In addition, this code is more robust as described above.
|
Which is a total of 13 lines of code, versus 17 lines for the C version. In addition, this code is more robust as described above.
|
||||||
|
|
||||||
# Type-safe Enums
|
# Type-safe Enums
|
||||||
|
|
||||||
Splitting up the C enums into a namespace and scoped enums resulted in two compilation issues.
|
Splitting up the C enums into a namespace and scoped enums resulted in two compilation issues.
|
||||||
First some enums started with a digit like ```vk::ImageType::1D``` which resulted in a compilation error.
|
First some enums started with a digit like ```vk::ImageType::1D``` which resulted in a compilation error.
|
||||||
Second, there's the risk that upper symbols like ```vk::CompositeAlphaFlagBitsKHR::OPAQUE``` do clash with preprocessor defines.
|
Second, there's the risk that upper symbols like ```vk::CompositeAlphaFlagBitsKHR::OPAQUE``` do clash with preprocessor defines.
|
||||||
In the given example ```OPAQUE``` has been defined in ```win32gdi.h``` resulting a compilation error.
|
In the given example ```OPAQUE``` has been defined in ```win32gdi.h``` resulting a compilation error.
|
||||||
|
|
||||||
To overcome those two issues the symbols have been converted to camel case and the prefix 'e' has been added so that each enum starts with a letter.
|
To overcome those two issues the symbols have been converted to camel case and the prefix 'e' has been added so that each enum starts with a letter.
|
||||||
|
|
||||||
# Improvements to Bit Flags
|
# Improvements to Bit Flags
|
||||||
|
|
||||||
After those changes the code might look more familiar to C++ developers, but there is still no gain with regards to safety.
|
After those changes the code might look more familiar to C++ developers, but there is still no gain with regards to safety.
|
||||||
With C++ features available we replaced all Vulkan enums with scoped enums to achieve type safety which already uncovered
|
With C++ features available we replaced all Vulkan enums with scoped enums to achieve type safety which already uncovered
|
||||||
a few small issues in our code. The good thing with scoped enums is that there is no implicit casts to integer types anymore.
|
a few small issues in our code. The good thing with scoped enums is that there is no implicit casts to integer types anymore.
|
||||||
The downside is that OR'ing the bits for the flags does not work anymore without an explicit cast. As a solution to this problem
|
The downside is that OR'ing the bits for the flags does not work anymore without an explicit cast. As a solution to this problem
|
||||||
we have introduced a new ```vk::Flags<T>``` template which is used for all flags. This class supports the standard
|
we have introduced a new ```vk::Flags<T>``` template which is used for all flags. This class supports the standard
|
||||||
operations one usually needs on bitmasks like &=, |=, & and |. Except for the initialization with 0, which is being replaced by
|
operations one usually needs on bitmasks like &=, |=, & and |. Except for the initialization with 0, which is being replaced by
|
||||||
the default constructor, the ```vk::Flags<T>``` class works exactly like a normal bitmask with the improvement that
|
the default constructor, the ```vk::Flags<T>``` class works exactly like a normal bitmask with the improvement that
|
||||||
it is impossible to set bits not specified by the corresponding enum. To generate a bit mask with two bits set write:
|
it is impossible to set bits not specified by the corresponding enum. To generate a bit mask with two bits set write:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
ci.usage = vk::ImageUsage::eColorAttachment | vk::ImageUsage::eStorage;
|
ci.usage = vk::ImageUsage::eColorAttachment | vk::ImageUsage::eStorage;
|
||||||
```
|
```
|
||||||
|
|
||||||
By adding the scoped enums and ```vk::Flags<T>``` the C++ API provides type safety for all enums and flags which is a
|
By adding the scoped enums and ```vk::Flags<T>``` the C++ API provides type safety for all enums and flags which is a
|
||||||
big improvement. This leaves the remaining issue that the compiler might not detect uninitialized fields in structs. As a solution
|
big improvement. This leaves the remaining issue that the compiler might not detect uninitialized fields in structs. As a solution
|
||||||
we have added constructors to all structs which accept all values defined by the corresponding struct.
|
we have added constructors to all structs which accept all values defined by the corresponding struct.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
vk::ImageCreateInfo ci(
|
vk::ImageCreateInfo ci(
|
||||||
...some flags..., vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
|
...some flags..., vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
|
||||||
vk::Extent3D { width, height, 1 }, 1, 1,
|
vk::Extent3D { width, height, 1 }, 1, 1,
|
||||||
vk::SampleCount::e1, vk::ImageTiling::eOptimal,
|
vk::SampleCount::e1, vk::ImageTiling::eOptimal,
|
||||||
vk::ImageUsage::eColorAttachment, vk::SharingMode::eExclusive,
|
vk::ImageUsage::eColorAttachment, vk::SharingMode::eExclusive,
|
||||||
0, 0, vk::ImageLayout::eUndefined);
|
0, 0, vk::ImageLayout::eUndefined);
|
||||||
```
|
```
|
||||||
|
|
||||||
# String conversions
|
# String conversions
|
||||||
|
|
||||||
At development time it can be quite handy to have a utility function that can convert an enum or flags to a string for debugging purposes. To achieve this,
|
At development time it can be quite handy to have a utility function that can convert an enum or flags to a string for debugging purposes. To achieve this,
|
||||||
we have implemented ```getString(type)``` functions for all enums and flags. Calling ```getString(vk::SharingMode::eExclusive)``` will return 'Exclusive' and calling
|
we have implemented ```to_string(type)``` functions for all enums and flags. Calling ```to_string(vk::SharingMode::eExclusive)``` will return 'Exclusive' and calling
|
||||||
```getString(vk::QueueFlagBits::eGraphics | vk::QueueFlagBits::eCompute)``` will return the concatenated string 'Graphics | Compute'.
|
```to_string(vk::QueueFlagBits::eGraphics | vk::QueueFlagBits::eCompute)``` will return the concatenated string 'Graphics | Compute'.
|
||||||
|
|
||||||
# Alternative Initialization of Structs
|
# Alternative Initialization of Structs
|
||||||
|
|
||||||
Another nice feature of those constructors is that sType is being initialized internally and thus is always correct.
|
Another nice feature of those constructors is that sType is being initialized internally and thus is always correct.
|
||||||
|
|
||||||
Finally, we have added a default constructor to each struct which initializes all values to 0 to allow setting the values with the named parameter idiom which is similar to the designated initializer list of C99.
|
Finally, we have added a default constructor to each struct which initializes all values to 0 to allow setting the values with the named parameter idiom which is similar to the designated initializer list of C99.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
vk::ImageCreateInfo ci = vk::ImageCreateInfo()
|
vk::ImageCreateInfo ci = vk::ImageCreateInfo()
|
||||||
.flags(...some flags...)
|
.flags(...some flags...)
|
||||||
.imageType(vk::ImageType::e2D)
|
.imageType(vk::ImageType::e2D)
|
||||||
.format(vk::Format::eR8G8B8A8Unorm)
|
.format(vk::Format::eR8G8B8A8Unorm)
|
||||||
.extent(vk::Extent3D { width, height, 1 })
|
.extent(vk::Extent3D { width, height, 1 })
|
||||||
.mipLevels(1)
|
.mipLevels(1)
|
||||||
.arrayLayers(1)
|
.arrayLayers(1)
|
||||||
.samples(1)
|
.samples(1)
|
||||||
.tiling(vk::ImageTiling::eOptimal)
|
.tiling(vk::ImageTiling::eOptimal)
|
||||||
.usage(vk::ImageUsage::eColorAttachment)
|
.usage(vk::ImageUsage::eColorAttachment)
|
||||||
.sharingMode(vk::SharingMode::eExclusive)
|
.sharingMode(vk::SharingMode::eExclusive)
|
||||||
// .queueFamilyIndexCount(0) // no need to set, already initialized
|
// .queueFamilyIndexCount(0) // no need to set, already initialized
|
||||||
// .pQueueFamilyIndices(0) // no need to set, already initialized
|
// .pQueueFamilyIndices(0) // no need to set, already initialized
|
||||||
.initialLayout(vk::ImageLayout::eUndefined);
|
.initialLayout(vk::ImageLayout::eUndefined);
|
||||||
device.createImage(&ci, allocator, &image);
|
device.createImage(&ci, allocator, &image);
|
||||||
```
|
```
|
||||||
|
|
||||||
# Enhancements beyond native Vulkan
|
# Enhancements beyond native Vulkan
|
||||||
To provide a more object oriented feeling we're providing classes for each handle which include all Vulkan functions where the first
|
To provide a more object oriented feeling we're providing classes for each handle which include all Vulkan functions where the first
|
||||||
parameter matches the handle. In addition to this we made a few changes to the signatures of the member functions
|
parameter matches the handle. In addition to this we made a few changes to the signatures of the member functions
|
||||||
* To enable the enhanced mode put ```#define VKCPP_ENHANCED_MODE``` before including ```vk_cpp.h```
|
* To enable the enhanced mode put ```#define VKCPP_ENHANCED_MODE``` before including ```vk_cpp.h```
|
||||||
* ```(count, T*)``` has been replaced by ```std::vector<T>```
|
* ```(count, T*)``` has been replaced by ```std::vector<T>```
|
||||||
* ```const char *``` has been replaced by ```std::string ```
|
* ```const char *``` has been replaced by ```std::string ```
|
||||||
* ```T const*``` has been replaced by ```T const &``` to allow temporary objects. This is useful to pass small structures like ```vk::ClearColorValue``` or ```vk::Extent*```
|
* ```T const*``` has been replaced by ```T const &``` to allow temporary objects. This is useful to pass small structures like ```vk::ClearColorValue``` or ```vk::Extent*```
|
||||||
```commandBuffer.clearColorImage(image, layout, std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f}, {...});```
|
```commandBuffer.clearColorImage(image, layout, std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f}, {...});```
|
||||||
Optional parameters are being replaced by ```Optional<T> const &``` which accept a type of ```T const&```. To tell the wrapper that a nullptr should be passed use ```T::null()```.
|
Optional parameters are being replaced by ```Optional<T> const &``` which accept a type of ```T const&```. ```nullptr``` can be used to initialize an empty ```Optional<T>```.
|
||||||
* The wrapper will throw a ```std::system_error``` if a ```vk::Result``` return value is not an success code. If there's only a single success code it's not returned at all. In this case functions with a single output value do return this output value instead.
|
* The wrapper will throw a ```std::system_error``` if a ```vk::Result``` return value is not an success code. If there's only a single success code it's not returned at all. In this case functions with a single output value do return this output value instead.
|
||||||
|
|
||||||
Here are a few code examples:
|
Here are a few code examples:
|
||||||
```c++
|
```c++
|
||||||
try {
|
try {
|
||||||
VkInstance nativeInstance = nullptr; // Fetch the instance from a favorite toolkit
|
VkInstance nativeInstance = nullptr; // Fetch the instance from a favorite toolkit
|
||||||
|
|
||||||
// create a vkcpp handle from a native handle
|
// create a vkcpp handle from a native handle
|
||||||
vk::Instance i(nativeInstance);
|
vk::Instance i(nativeInstance);
|
||||||
|
|
||||||
// operator=(VkInstance const &) is also supported
|
// operator=(VkInstance const &) is also supported
|
||||||
i = nativeInstance;
|
i = nativeInstance;
|
||||||
|
|
||||||
// Get VkInstance from vk::Instance
|
// Get VkInstance from vk::Instance
|
||||||
nativeInstance = i;
|
nativeInstance = i;
|
||||||
|
|
||||||
// Get a std::vector as result of an enumeration call.
|
// Get a std::vector as result of an enumeration call.
|
||||||
std::vector<vk::PhysicalDevice> physicalDevices = i.enumeratePhysicalDevices();
|
std::vector<vk::PhysicalDevice> physicalDevices = i.enumeratePhysicalDevices();
|
||||||
vk::FormatProperties formatProperties = physicalDevices[0].getFormatProperties(vk::Format::eR8G8B8A8Unorm);
|
vk::FormatProperties formatProperties = physicalDevices[0].getFormatProperties(vk::Format::eR8G8B8A8Unorm);
|
||||||
|
|
||||||
vk::CommandBuffer commandBuffer = ...;
|
vk::CommandBuffer commandBuffer = ...;
|
||||||
vk::Buffer buffer = ...;
|
vk::Buffer buffer = ...;
|
||||||
|
|
||||||
// Accept std::vector as source for updateBuffer
|
// Accept std::vector as source for updateBuffer
|
||||||
commandBuffer.updateBuffer(buffer, 0, {some values}); // update buffer with std::vector
|
commandBuffer.updateBuffer(buffer, 0, {some values}); // update buffer with std::vector
|
||||||
|
|
||||||
// Sometimes it's necessary to pass a nullptr to a struct. For this case we've added Optional<T> T::null() to all structs T as replacement for the nullptr.
|
// Sometimes it's necessary to pass a nullptr to a struct. For this case we've added Optional<T>(std::nullptr_t).
|
||||||
device.allocateMemory(allocateInfo, vk::AllocationCallbacks::null());
|
device.allocateMemory(allocateInfo, nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (std::system_error e)
|
catch (std::system_error e)
|
||||||
{
|
{
|
||||||
std::cerr << "Vulkan failure: " << e.what() << std::endl;
|
std::cerr << "Vulkan failure: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
To start with the C++ version of the Vulkan API download header from GIT, put it in a vulkan subdirectory and add
|
To start with the C++ version of the Vulkan API download header from GIT, put it in a vulkan subdirectory and add
|
||||||
```#include <vulkan/vk_cpp.h>``` to your source code.
|
```#include <vulkan/vk_cpp.h>``` to your source code.
|
||||||
|
|
||||||
To build the header for a given vk.xml specification continue with the following steps:
|
To build the header for a given vk.xml specification continue with the following steps:
|
||||||
|
|
||||||
* Build VkCppGenerator
|
* Build VkCppGenerator
|
||||||
* Grab your favourite version vk.xml from Khronos
|
* Grab your favourite version vk.xml from Khronos
|
||||||
* Excute ```VkCppGenerator <vk.xml>``` to generate ```vk_cpp.h``` in the current working directory.
|
* Excute ```VkCppGenerator <vk.xml>``` to generate ```vk_cpp.h``` in the current working directory.
|
||||||
|
|
||||||
# Build instructions for VkCppGenerator
|
# Build instructions for VkCppGenerator
|
||||||
|
|
||||||
* Clone the repository: ```git clone https://github.com/nvpro-pipeline/vkcpp.git```
|
* Clone the repository: ```git clone https://github.com/nvpro-pipeline/vkcpp.git```
|
||||||
* Update submodules: ```git submodule update --init --recursive```
|
* Update submodules: ```git submodule update --init --recursive```
|
||||||
* Use CMake to generate a solution or makefile for your favourite build environment
|
* Use CMake to generate a solution or makefile for your favourite build environment
|
||||||
* Launch the build
|
* Launch the build
|
||||||
|
|
||||||
# Providing Pull Requests
|
# Providing Pull Requests
|
||||||
|
|
||||||
NVIDIA is happy to review and consider pull requests for merging into the main tree of vkcpp for bug fixes and features. Before providing a pull request to NVIDIA, please note the following:
|
NVIDIA is happy to review and consider pull requests for merging into the main tree of vkcpp for bug fixes and features. Before providing a pull request to NVIDIA, please note the following:
|
||||||
|
|
||||||
* A pull request provided to this repo by a developer constitutes permission from the developer for NVIDIA to merge the provided
|
* A pull request provided to this repo by a developer constitutes permission from the developer for NVIDIA to merge the provided
|
||||||
changes or any NVIDIA modified version of these changes to the repo. NVIDIA may remove or change the code at any time and in any
|
changes or any NVIDIA modified version of these changes to the repo. NVIDIA may remove or change the code at any time and in any
|
||||||
way deemed appropriate. Due to the required paperwork please refrain from providing pull requests for simple changes and file an issue
|
way deemed appropriate. Due to the required paperwork please refrain from providing pull requests for simple changes and file an issue
|
||||||
describing a bug or the desired change instead.
|
describing a bug or the desired change instead.
|
||||||
* Not all pull requests can be or will be accepted. NVIDIA will close pull requests that it does not intend to merge.
|
* Not all pull requests can be or will be accepted. NVIDIA will close pull requests that it does not intend to merge.
|
||||||
* The modified files and any new files must include the unmodified NVIDIA copyright header seen at the top of all shipping files.
|
* The modified files and any new files must include the unmodified NVIDIA copyright header seen at the top of all shipping files.
|
@ -215,20 +215,21 @@ const std::string flagsHeader(
|
|||||||
);
|
);
|
||||||
|
|
||||||
std::string const optionalClassHeader = (
|
std::string const optionalClassHeader = (
|
||||||
" template <typename RefType>\n"
|
" template <typename RefType>\n"
|
||||||
" class Optional\n"
|
" class Optional\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" public:\n"
|
" public:\n"
|
||||||
" Optional(RefType & reference) { m_ptr = &reference; }\n"
|
" Optional(RefType & reference) { m_ptr = &reference; }\n"
|
||||||
"\n"
|
" Optional(std::nullptr_t) { m_ptr = nullptr; }\n"
|
||||||
" operator RefType*() const { return m_ptr; }\n"
|
"\n"
|
||||||
"\n"
|
" operator RefType*() const { return m_ptr; }\n"
|
||||||
" private:\n"
|
" RefType const* operator->() const { return m_ptr; }\n"
|
||||||
" Optional(std::nullptr_t) { m_ptr = nullptr; }\n"
|
" explicit operator bool() const { return !m_ptr; }\n"
|
||||||
" friend RefType;\n"
|
"\n"
|
||||||
" RefType *m_ptr;\n"
|
" private:\n"
|
||||||
" };\n"
|
" RefType *m_ptr;\n"
|
||||||
"\n"
|
" };\n"
|
||||||
|
"\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// trim from end
|
// trim from end
|
||||||
@ -1603,7 +1604,15 @@ void writeCall(std::ofstream & ofs, std::string const& name, size_t templateInde
|
|||||||
}
|
}
|
||||||
else if (commandData.arguments[it->first].pureType == "char")
|
else if (commandData.arguments[it->first].pureType == "char")
|
||||||
{
|
{
|
||||||
ofs << reduceName(commandData.arguments[it->first].name) << ".c_str()";
|
ofs << reduceName(commandData.arguments[it->first].name);
|
||||||
|
if (commandData.arguments[it->first].optional)
|
||||||
|
{
|
||||||
|
ofs << " ? " << reduceName(commandData.arguments[it->first].name) << "->c_str() : nullptr";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ofs << ".c_str()";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1626,11 +1635,11 @@ void writeCall(std::ofstream & ofs, std::string const& name, size_t templateInde
|
|||||||
{
|
{
|
||||||
ofs << "&";
|
ofs << "&";
|
||||||
}
|
}
|
||||||
ofs << reduceName(commandData.arguments[i].name)
|
ofs << reduceName(commandData.arguments[i].name) << (commandData.arguments[i].optional ? "))" : " )");
|
||||||
<< (commandData.arguments[i].optional ? "))" : " )");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
assert(!commandData.arguments[i].optional);
|
||||||
ofs << "reinterpret_cast<Vk" << commandData.arguments[i].pureType << "*>( &" << reduceName(commandData.arguments[i].name) << " )";
|
ofs << "reinterpret_cast<Vk" << commandData.arguments[i].pureType << "*>( &" << reduceName(commandData.arguments[i].name) << " )";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1646,7 +1655,15 @@ void writeCall(std::ofstream & ofs, std::string const& name, size_t templateInde
|
|||||||
if (commandData.arguments[i].type.find("const") != std::string::npos)
|
if (commandData.arguments[i].type.find("const") != std::string::npos)
|
||||||
{
|
{
|
||||||
assert(commandData.arguments[i].type.find("char") != std::string::npos);
|
assert(commandData.arguments[i].type.find("char") != std::string::npos);
|
||||||
ofs << reduceName(commandData.arguments[i].name) << ".c_str()";
|
ofs << reduceName(commandData.arguments[i].name);
|
||||||
|
if (commandData.arguments[i].optional)
|
||||||
|
{
|
||||||
|
ofs << " ? " << reduceName(commandData.arguments[i].name) << "->c_str() : nullptr";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ofs << ".c_str()";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1864,63 +1881,65 @@ void writeFunctionHeader(std::ofstream & ofs, std::string const& indentation, st
|
|||||||
{
|
{
|
||||||
ofs << ", ";
|
ofs << ", ";
|
||||||
}
|
}
|
||||||
if (vectorParameters.find(i) == vectorParameters.end())
|
|
||||||
|
std::map<size_t,size_t>::const_iterator it = vectorParameters.find(i);
|
||||||
|
size_t pos = commandData.arguments[i].type.find('*');
|
||||||
|
if ((it == vectorParameters.end()) && (pos == std::string::npos))
|
||||||
{
|
{
|
||||||
size_t pos = commandData.arguments[i].type.find('*');
|
ofs << commandData.arguments[i].type << " " << commandData.arguments[i].name;
|
||||||
if (pos == std::string::npos)
|
if (!commandData.arguments[i].arraySize.empty())
|
||||||
{
|
{
|
||||||
ofs << commandData.arguments[i].type << " " << commandData.arguments[i].name;
|
ofs << "[" << commandData.arguments[i].arraySize << "]";
|
||||||
if (!commandData.arguments[i].arraySize.empty())
|
|
||||||
{
|
|
||||||
ofs << "[" << commandData.arguments[i].arraySize << "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string type = commandData.arguments[i].type;
|
|
||||||
if (type.find("char") != std::string::npos)
|
|
||||||
{
|
|
||||||
type = "std::string const&";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(type[pos] == '*');
|
|
||||||
if (commandData.arguments[i].optional)
|
|
||||||
{
|
|
||||||
type[pos] = ' ';
|
|
||||||
type = "vk::Optional<" + trimEnd(type) + "> const &";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
type[pos] = '&';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ofs << type << " " << reduceName(commandData.arguments[i].name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (templateIndex == i)
|
bool optional = commandData.arguments[i].optional && ((it == vectorParameters.end()) || (it->second == ~0));
|
||||||
|
if (optional)
|
||||||
{
|
{
|
||||||
ofs << "std::vector<T> ";
|
ofs << "vk::Optional<";
|
||||||
}
|
}
|
||||||
else if (commandData.arguments[i].pureType == "char")
|
if (vectorParameters.find(i) == vectorParameters.end())
|
||||||
{
|
{
|
||||||
ofs << "std::string ";
|
assert(pos != std::string::npos);
|
||||||
}
|
if (commandData.arguments[i].type.find("char") != std::string::npos)
|
||||||
else if (commandData.arguments[i].pureType == "void")
|
{
|
||||||
{
|
ofs << "std::string const";
|
||||||
ofs << "std::vector<uint8_t> ";
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(commandData.arguments[i].type[pos] == '*');
|
||||||
|
ofs << trimEnd(commandData.arguments[i].type.substr(0, pos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ofs << "std::vector<" << commandData.arguments[i].pureType << "> ";
|
if (templateIndex == i)
|
||||||
|
{
|
||||||
|
ofs << "std::vector<T>";
|
||||||
|
}
|
||||||
|
else if (commandData.arguments[i].pureType == "char")
|
||||||
|
{
|
||||||
|
ofs << "std::string";
|
||||||
|
}
|
||||||
|
else if (commandData.arguments[i].pureType == "void")
|
||||||
|
{
|
||||||
|
ofs << "std::vector<uint8_t>";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ofs << "std::vector<" << commandData.arguments[i].pureType << ">";
|
||||||
|
}
|
||||||
|
if (commandData.arguments[i].type.find("const") != std::string::npos)
|
||||||
|
{
|
||||||
|
ofs << " const";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (commandData.arguments[i].type.find("const") != std::string::npos)
|
if (optional)
|
||||||
{
|
{
|
||||||
ofs << "const";
|
ofs << "> const";
|
||||||
}
|
}
|
||||||
ofs << "& " << reduceName(commandData.arguments[i].name);
|
ofs << " & " << reduceName(commandData.arguments[i].name);
|
||||||
}
|
}
|
||||||
argEncountered = true;
|
argEncountered = true;
|
||||||
}
|
}
|
||||||
@ -2506,13 +2525,6 @@ void writeTypeStruct( std::ofstream & ofs, VkData const& vkData, DependencyData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// null handle
|
|
||||||
ofs << " static Optional<const " << dependencyData.name << "> null()" << std::endl
|
|
||||||
<< " {" << std::endl
|
|
||||||
<< " return Optional<const " << dependencyData.name << ">(nullptr);" << std::endl
|
|
||||||
<< " }" << std::endl
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
// the cast-operator to the wrapped struct, and the struct itself as a private member variable
|
// the cast-operator to the wrapped struct, and the struct itself as a private member variable
|
||||||
ofs << " operator const Vk" << dependencyData.name << "&() const" << std::endl
|
ofs << " operator const Vk" << dependencyData.name << "&() const" << std::endl
|
||||||
<< " {" << std::endl
|
<< " {" << std::endl
|
||||||
|
789
vulkan/vk_cpp.h
789
vulkan/vk_cpp.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user