GetProcAddress() is a function available on Windows operating systems. dlsym() is a function available on Linux operating systems. They both acquire an address of a specified function from an already loaded dynamic-link library. The only function that must be publicly exported from all Vulkan implementations is called vkGetInstanceProcAddr(). It allows us to load any other Vulkan function in a way that is independent of the operating system we are working on.
To ease and automate the process of loading multiple Vulkan functions, and to lower the probability of making mistakes, we should wrap the processes of declaring, defining, and loading functions into a set of convenient macro definitions, as described in the Preparing for loading Vulkan API functions recipe. This way, we can keep all Vulkan API functions in just one file which contains a list of macro-wrapped names of all Vulkan functions. We can then include this single file in multiple places and get use of the C/C++ preprocessor. By redefining macros, we can declare and define the variables in which we will store function pointers, and we can also load all of them.
Here is the updated fragment of the ListOfVulkanFunctions.inl file:
#ifndef EXPORTED_VULKAN_FUNCTION
#define EXPORTED_VULKAN_FUNCTION( function )
#endif
EXPORTED_VULKAN_FUNCTION( vkGetInstanceProcAddr )
#undef EXPORTED_VULKAN_FUNCTION
The rest of the files (VulkanFunctions.h and VulkanFunctions.h) remain unchanged. Declarations and definitions are automatically performed with preprocessor macros. However, we still need to load functions exported from the Vulkan Loader library. The implementation of the preceding recipe may look as follows:
#if defined _WIN32
#define LoadFunction GetProcAddress
#elif defined __linux
#define LoadFunction dlsym
#endif
#define EXPORTED_VULKAN_FUNCTION( name ) \
name = (PFN_##name)LoadFunction( vulkan_library, #name ); \
if( name == nullptr ) { \
std::cout << "Could not load exported Vulkan function named: " \
#name << std::endl; \
return false; \
}
#include "ListOfVulkanFunctions.inl"
return true;
First we define a macro that is responsible for acquiring an address of a vkGetInstanceProcAddr() function. It gets it from the library represented by the vulkan_library variable, casts the result of this operation onto a PFN_kGetInstanceProcAddr type, and stores it in a variable named vkGetInstanceProcAddr. After that, the macro checks whether the operation succeeded, and displays the proper message on screen in the case of a failure.
All the preprocessor "magic" is done when the ListOfVulkanFunctions.inl file is included and the preceding operations are performed for each function defined in this file. In this case, it is performed for only the vkGetInstanceProcAddr() function, but the same behavior is achieved for functions from other levels.
Now, when we have a function loading function, we can acquire pointers to other Vulkan procedures in an OS-independent way.