使用 vkEnumerateInstanceVersion 获取准确的 Vulkan API 版本

问题描述

我正在使用 vkEnumerateInstanceVersion 获取 vulkan api 版本并将其传递给 VkApplicationInfo 结构。我可以轻松区分 VK_VERSION_1_0VK_VERSION_1_1

//query the api version in order to use the correct vulkan functionality
PFN_vkEnumerateInstanceVersion FN_vkEnumerateInstanceVersion = 
PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr,"vkEnumerateInstanceVersion"));
uint32_t *instanceVersion = (uint32_t*)malloc(sizeof(uint32_t));
VkResult result = FN_vkEnumerateInstanceVersion(instanceVersion);

//check what is returned
if(result == VK_SUCCESS){
    std::cout<<"RESULT(vkEnumerateInstanceVersion) : Intance version enumeration successful"<<std::endl;
    if(instanceVersion!=nullptr){
        std::cout<<"API_VERSION : VK_API_VERSION_1_1"<<std::endl;
        appInfo.apiVersion = VK_API_VERSION_1_1;
    }
    else{
        std::cout<<"API_VERSION : VK_API_VERSION_1_0"<<std::endl;
    }
    std::cout<<"Version number returned : "<<*instanceVersion<<std::endl;
}else if(result == VK_ERROR_OUT_OF_HOST_MEMORY){
    std::cerr<<"RESULT(vkEnumerateInstanceVersion) : VK_ERROR_HOST_OUT_OF_MEMORY"<<std::endl;
}else{
    std::cerr<<"RESULT(vkEnumerateInstanceVersion) : Something else returned while enumerating instance version"<<std::endl;
}

我使用上面的代码获取api版本。 vulkan 规范指出:

查询支持的实例级功能的版本 实现,调用

// 由 VK_VERSION_1_1 提供 VkResult vkEnumerateInstanceVersion( uint32_t* pApiVersion);

上面块中的注释意味着这是由 VK_VERSION_1_1 而不是 VK_VERSION_1_0 提供的。 现在,当我打开终端并输入:

vulkaninfo | head -n 5

我得到以下内容

ERROR: [Loader Message] Code 0 : /usr/lib32/libvulkan_intel.so: wrong ELF class: ELFCLASS32
ERROR: [Loader Message] Code 0 : /usr/lib32/libvulkan_radeon.so: wrong ELF class: ELFCLASS32
==========
VULKANINFO
==========

Vulkan Instance Version: 1.2.159

这意味着我有 VK_API_VERSION_1_2。我想要做的是获得确切的 api 版本。 在执行第一个代码块时,我得到:

RESULT(vkEnumerateInstanceVersion) : Intance version enumeration successful
API_VERSION : VK_API_VERSION_1_1
Version number returned : 4202655

有没有办法在程序中确定 VK_VERSION_1_1 或 VK_VERSION_1_2。此外,我正在检查版本 1.2.165

的 vulkan 参考指南

解决方法

我正在使用 vkEnumerateInstanceVersion 获取 vulkan api 版本并将其传递给 VkApplicationInfo 结构。

不是vkEnumerateInstanceVersion 的用途。

VkApplicationInfo::apiVersion 指定您的代码所针对的 Vulkan 版本。此版本是固定值,因为您的代码不能针对尚不存在的 Vulkan 版本编写。也就是说,如果您正在编写适用于 1.1 的应用程序,则指定 VK_VERSION_1_1

您可能仍会获得 1.2 版本,但这没关系,因为 Vulkan 主要版本都向后兼容较低的次要版本号。因此,如果您针对 Vulkan 1.1 编写代码,它将适用于任何 1.2 实现。

您还滥用了实例版本。实例版本是 Vulkan 实例机制的版本,而不是整个 Vulkan 实现。您可能连接到 1.2 实例机器,但 Vulkan 设备实现可能只为您提供 1.1。就 Vulkan 而言,这很好。

至于您的代码的详细信息:

此代码实际上并未正确区分 Vulkan 1.0 和 Vulkan 1.1。事实上,它包含许多错误和令人困惑的部分。

第一个未解决的潜在问题是实例实现可能太旧而无法支持 vkEnumerateInstanceVersion。由于 Vulkan 1.0 实例实现不提供此功能,因此您应首先确保该功能确实存在。也就是说,您应该在调用它之前检查 FN_vkEnumerateInstanceVersion 的值。如果该函数不存在,则实例版本必须为 1.0。

接下来,您调用该函数。但该功能不能失败;它只能返回错误代码 VK_SUCCESS。所以检查它的结果代码是没有意义的。

一旦你去检查有问题的实际值,你就会做一些奇怪的事情。你测试instanceVersion!=nullptr。但是这样做没有意义,因为它总是指向有效内存。所以由此得出的结论是实例实现版本是 1.1 是完全错误的。

Vulkan 中版本号值的含义是clearly specified in the specification。就您而言,如果您只是在寻找主要和次要版本号,您可以去掉补丁版本号。

所以获取实例版本的正确代码是:

auto FN_vkEnumerateInstanceVersion = PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr,"vkEnumerateInstanceVersion"));

if(FN_vkEnumerateInstanceVersion == nullptr)
  return VK_API_VERSION_1_0;
else
{
  uint32_t instanceVersion;
  auto result = FN_vkEnumerateInstanceVersion(&instanceVersion);
  return instanceVersion & 0xFFFF0000; //Remove the patch version.
}
,

您可以使用 vulkan 标头中定义的 3 个宏从 vkEnumerateInstanceVersion 返回的实例版本中获取 Vulkan 版本信息。

这是一个可以解决问题的片段:

uint32 instanceVersion = VK_API_VERSION_1_0;
auto FN_vkEnumerateInstanceVersion = PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr,"vkEnumerateInstanceVersion"));
if(vkEnumerateInstanceVersion){
    vkEnumerateInstanceVersion(&instanceVersion );
}

// 3 macros to extract version info
uint32_t major = VK_VERSION_MAJOR(instanceVersion);
uint32_t minor = VK_VERSION_MINOR(instanceVersion);
uint32_t patch = VK_VERSION_PATCH(instanceVersion);

cout << "Vulkan Version:" << major << "." << minor << "." << patch << endl;

这将打印出以下内容:

Vulkan Version:1.1.121