![]() |
VPP
0.8
A high-level modern C++ API for Vulkan
|
Creates shader-level function. More...
#include <vppLangConstructs.hpp>
Public Member Functions | |
Function (const char *pName="unnamedFunction") | |
Starts the definition of shader-level function. More... | |
ReturnType | operator() (typename Args::rvalue_type ... args) |
Calls the defined function from inside shader code on the GPU. | |
Creates shader-level function.
Vulkan allows you to define functions inside shaders. VPP has special syntax for it. Note that this is different from defining a C++ function containing shader code. The latter will cause the function code to be inlined into the caller code. The notation described here allows to define a true function on GPU level. The purpose is to avoid GPU code bloat.
Four major components of each function definition are Function and Par templates, as well as Begin(), End() and Return() constructs. Function defines the function, Par defines a parameter of the function, Begin() and End() delimit the function body. Return() allows to return a value.
The VPP code which defines a function is meant to be executed as the shader definition code, before the function is used. The Function template actually creates a callable functor in local scope, which in turn may be called from the shader. The simplest way to use function looks like this:
Here the shader first defines a function named factorial
and calls it. You may call the function as many times you want from anywhere in the shader, assuming the functor still exists.
The first template argument of Function template defines the return type. Zero or more types which may come later determine parameter types. These must match with Par declarations that come later.
The name of the function should be passed to its constructor. This name will be emited into final SPIR-V code and may be helpful during diagnostics.
The drawback of the notation shown above is leakage of factX
paramter name to the shader code scope. It might be a problem if you want to use another variable with this name. To prevent this, use slighly modified version, like in the binomial
function below:
Here we have entire definition enclosed in additional C++ scope which hides parameter names from the outside.
In all cases the scope between Begin() and End() is required, especially if the function defines any mutable variables of its own. It is an error to omit this scope. C++ compiler can't detect this error, but VPP will do and an exception will be thrown in such case during shader compilation.
What if we want a reusable function definition, e.g. to be placed in some library? The solution is simple - we can just convert the definition above into C++ class, like in this example:
The rules are now as follows:
gcd
above) in the calling shader to "import" the function. This operation will trigger generation function code to SPIR-V.Also it should be noted that you can pass additional parameters on the CPU level to the function object in order to parameterize the function. It can also be a C++ template, use virtual functions and generally utilise any C++ programming technique.
vpp::Function< ReturnType, Args >::Function | ( | const char * | pName = "unnamedFunction< ReturnType, Args >" | ) |
Starts the definition of shader-level function.
Specify the function name as the parameter. The name will be visible in generated code.