Vulkan加载实例级函数

加载实例级函数
我们已经创建了一个Vulkan实例,下一步是获取物理设备名单,从名单中选择一个设备,然后通过该设备创建逻辑设备。这些操作是通过实例级函数执行的,要使用这些函数,需要先获取它们的地址。

具体处理过程
(1)获取我们刚刚创建的Vulkan实例的句柄,将其存储在VkInstance类型的变量instance中。
(2)选择想要加载的实例级函数的名称(表示为<函数名>)。
(3)创建一个PFN_<函数名>类型的变量,使用<函数名>命名它。
(4)调用vkGetInstanceProcAddr(instance,"<函数名>")函数。将第一个参数设置为我们刚刚创建的Vulkan实例的句柄,将第二个参数设置为<函数名>。将该函数调用操作获得的结果,转换为PFN_<函数名>类型,并将其存储到<函数名>变量中。
(5)通过查明<函数名>变量的值不是nullptr,确认该函数调用操作已成功完成。

具体运行情况
实例级函数主要用于在物理设备上执行操作,Vulkan中的实例级函数有很多:vkEnumeratePhysicalDevices()、vkGetPhysicalDeviceProperties()、vkGetPhysicalDeviceFeatures()、vkGetPhysicalDeviceQueueFamilyProperties()、vkCreateDevice()、vkGetDeviceProcAddr()、vkDestroyInstance()vkEnumerateDeviceExtensionProperties()等。

怎样分辨一个函数是实例级的还是设备级的呢?所有设备级函数第一个参数的类型都是VkDevice、VkQueue或VkCommandBuffer。因此,如果一个函数没有这种类型的参数,并且不是全局级的,那么该函数就是实例级的。如前所述,实例级函数用于操作物理设备、检查物理设备的属性和功能,以及创建逻辑设备。
注意,扩展也会引入新的函数。要在应用程序中使用扩展,就需要将扩展的函数添加到用于加载函数的代码中。然而,如果在创建实例的过程中没有启用某个扩展,就不应该加载该扩展引入的函数。如果具体的硬件平台不支持某些函数,那么加载这些函数的操作会失败(加载操作会返回空指针)。
因此,为了加载实例级函数,应使用下面的代码更新ListOfVulkanFunctions.inl文件。

Vulkan加载实例级函数
Vulkan加载实例级函数


在这段代码中,我们添加了多个(但并非所有)实例级函数的名称。这些函数都被封装到INSTANCE_LEVEL_VULKAN_FUNCTION宏中,并且被放在#ifndef#undef预处理指令定义中。
要使用前面定义的宏加载实例级函数,还应该添加下列代码。

Vulkan加载实例级函数
这个宏会调用vkGetInstanceProcAddr()函数。前面我们使用vkGetInstanceProcAddr()函数加载过全局级函数,但这次我们将该函数的第一个参数设置为一个Vulkan实例的句柄。这样我们就可以加载只有在Vulkan实例被创建后才能正常运行的函数。
vkGetInstanceProcAddr()函数会返回一个指向我们想要加载的函数的指针,可将vkGetInstanceProcAddr()函数的第二个参数设置为我们想要加载的函数的名称。vkGetInstanceProcAddr()函数返回值的类型为void*,因此需要转换该返回值的类型,使之与我们想要加载的函数的类型相匹配。
TIP 函数的类型是根据函数名定义的(在函数名前加PFN_)。例如,函数vkEnumeratePhysicalDevices()的类型就是PFN_vkEnumeratePhysicalDevices
如果vkGetInstanceProcAddr()函数无法找到我们想要加载的函数,它就会返回nullptr。因此,为了防止出现问题,应该执行检查操作并将合适的信息记录下来。
我们编写的函数加载代码,会获取在ListOfVulkanFunctions.inl文件定义的宏中设置的所有函数的指针,但是无法使用相同的方式获取某个扩展专有的函数,因为只有在相应的扩展被启用后,才能加载该扩展专有的函数。在没有启用任何扩展的情况下,只有Vulkan核心的函数才能被加载,这就是需要将Vulkan核心的函数与扩展专有函数区分开的原因。我们还需要知道哪些扩展被启用了,以及哪个函数是由哪个扩展引入的,这就是使用独立宏处理由扩展引入函数的原因。这种宏不仅会设置函数的名称,而且会设置相应扩展的名称。要加载这种函数,可使用下面的代码。

Vulkan加载实例级函数
enabled_extensions是一个std::vector<char const*>类型的变量,其中存储了所有已启用的实例级扩展的名称。遍历enabled_extensions变量含有的所有元素,查明指定扩展的名称与引入加载函数扩展的名称是否相同。如果两个扩展名称相同,就可以使用加载Vulkan核心函数的方式加载该函数。如果两个扩展名称不相同,就跳过执行加载函数指针操作的代码。如果没有启用指定的扩展,就无法加载由该扩展引入的函数。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!

 

Vulkan实战