从Vulkan Loader库加载导出函数
译者注:示例代码点击此处
加载(连接)Vulkan Loader库时,我们需要加载它的函数,以便在应用程序中使用Vulkan API。不幸的是,不同的操作系统有不同的方法来获取从动态库导出的函数的地址(Windows上的.dll文件或Linux上的.so文件)。然而Vulkan API在许多操作系统上都是可移植的。因此,为了允许开发人员加载API中可用的所有函数,不管他们针对的是哪个操作系统,Vulkan引入了一个函数,该函数可用于加载所有其他Vulkan API函数。但这个函数本身只能以操作系统的特定方式加载。
怎么做...
在Windows操作系统上:
1.创建一个名为PFN_vkGetInstanceProcAddr的vkGetInstanceProcAddr进程变量。
2.调用GetProcAddress(vulkan_library, "vkGetInstanceProcAddr"),将结果强转成PFN_vkGetInstanceProcAddr类型,赋值给vkGetInstanceProcAddr变量。
3.通过检查vkGetInstanceProcAddr变量的值是否不等于nullptr,确认此操作是否成功。
在Liunx操作系统上:
1.创建一个名为PFN_vkGetInstanceProcAddr的vkGetInstanceProcAddr进程变量。
2.调用GetProcAddress(vulkan_library, "vkGetInstanceProcAddr"),将结果强转成PFN_vkGetInstanceProcAddr类型,赋值给vkGetInstanceProcAddr变量。
3.通过检查vkGetInstanceProcAddr变量的值是否不等于nullptr,确认此操作是否成功。
这个怎么运作...
Windows系统要用到GetProcAddress()函数。而Liunx系统上用dlsym()函数。它们都从已加载的动态链接库中获取指定函数的地址。必须从Vulkan实现中获取一个导出函数vkGetInstanceProcAddr()。它允许以操作系统无关的方式加载任何其他Vulkan函数。
为了降低拼写错误的概率,我们会将声明、定义和加载函数的过程包装成一组宏定义,如准备加载Vulkan API函数所述,这样可以将所有Vulkan API函数保存在ListOfVulkanFunctions.inl文件中,该文件包含用宏包装的所有Vulkan函数的列表,然后可以在多个地方包含此文件。这样通过重新定义宏,我们可以声明和定义用于存储函数指针的变量。
以下是ListOfVulkanFunctions.inl文件的更新片段:
#ifndef EXPORTED_VULKAN_FUNCTION
#define EXPORTED_VULKAN_FUNCTION( function )
#endif
EXPORTED_VULKAN_FUNCTION( vkGetInstanceProcAddr )
#undef EXPORTED_VULKAN_FUNCTION
VulkanFunctions.h保持不变。声明和定义是用预处理器宏自动执行的。但是,如前所述我们仍然需要从Vulkan Loader库加载导出的函数。VulkanFunctions.cpp修改部分如下:
#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;
首先,我们定义一个宏,它负责获取vkGetInstanceProcAddr()函数的地址,这是从vulkan_library变量表示的库中获取,将该操作的结果转换为PFN_kGetInstanceProcAddr类型,并将其赋值给vkGetInstanceProcAddr变量,之后检查操作是否成功,并在故障的情况下在屏幕上显示适当的消息。
当包含ListOfVulkanFunctions.inl文件并对该文件中定义的每个函数执行前面的操作时,所有预处理器“魔术”就完成了。在这里只是执行vkGetInstanceProcAddr()函数,但对于其他级别的函数实现也是相同的行为。
现在,当我们有一个函数加载函数时,就可以用一个与系统无关的方式来获取指向其他Vulkan函数的指针。