使用 Vulkan 配置

此示例的源代码可以在 Khronos Vulkan 示例 github 存储库中找到。

此示例演示了 Vulkan 配置库 的用法。配置定义了属性、特性、扩展等的常见需求基线,以使 Vulkan 应用程序更具可移植性。您无需在运行时逐个检查应用程序中的所有这些,而是使用配置库来检查所选设备是否支持给定配置的所有要求。如果满足,则使用同一库来创建设备和/或实例。然后,该库负责启用所有必需的特性、扩展等,从而节省了大量常见的样板代码。

我们将在一个使用描述符索引的示例中展示这一点。

该示例使用 VP_KHR_roadmap_2022 配置,该配置为“2022 年或之后不久在主流智能手机、平板电脑、笔记本电脑、游戏机和台式机设备上发布的新型中高端设备”启用了一组基准特性和扩展。有关此配置包含内容的详细信息,请参见 此处

不使用配置

如果不使用配置库,并且 API 版本没有将其作为核心特性,则必须在设备和/或实例创建时手动启用特性和扩展。这可能如下所示:

VkPhysicalDeviceFeatures enabled_features{};
VkPhysicalDeviceVulkan11Features enabled_features_11{};
VkPhysicalDeviceVulkan12Features enabled_features_12{};

enabled_features.fullDrawIndexUint32 = VK_TRUE;
enabled_features.imageCubeArray = VK_TRUE;
enabled_features.independentBlend = VK_TRUE;
enabled_features.ampleRateShading = VK_TRUE;
enabled_features.rawIndirectFirstInstance = VK_TRUE;
enabled_features.depthClamp = VK_TRUE;
enabled_features.depthBiasClamp = VK_TRUE;
enabled_features.samplerAnisotropy = VK_TRUE;
enabled_features.occlusionQueryPrecise = VK_TRUE;
enabled_features.fragmentStoresAndAtomics = VK_TRUE;
enabled_features.shaderStorageImageExtendedFormats = VK_TRUE;
enabled_features.shaderUniformBufferArrayDynamicIndexing = VK_TRUE;
enabled_features.shaderSampledImageArrayDynamicIndexing = VK_TRUE;
enabled_features.shaderStorageBufferArrayDynamicIndexing = VK_TRUE;
enabled_features.shaderStorageImageArrayDynamicIndexing = VK_TRUE;
...

enabled_features_11.samplerYcbcrConversion = VK_TRUE;
enabled_features_11.pNext = &enabled_features_12;
...

enabled_features_12.samplerMirrorClampToEdge = VK_TRUE;
enabled_features_12.descriptorIndexing = VK_TRUE;
enabled_features_12.shaderUniformTexelBufferArrayDynamicIndexing = VK_TRUE;
...

VkDeviceCreateInfo device_create_info = {};
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.pNext = &enabled_features_11;

VkResult result = vkCreateDevice(...);
if (!result) {
    app_terminate('Could not create device, reason:' + vk_result_str(result));
}

随着每个额外的设备特性,此代码将变得越来越长,因为物理设备特性需要通过 pNext 成员链接起来。

使用配置

使用配置库和一个需要上述所有特性和扩展的配置,可以大大简化此过程:

// Profile to enable
const VpProfileProperties profile_properties = {VP_KHR_ROADMAP_2022_NAME, VP_KHR_ROADMAP_2022_SPEC_VERSION};

// Instance creation

VkBool32 profile_supported;
vpGetInstanceProfileSupport(nullptr, &profile_properties, &profile_supported);
if (!profile_supported) {
    app_terminate("The selected profile is not supported!");
}

VkInstanceCreateInfo create_info{};
create_info.sType                   = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.ppEnabledExtensionNames = enabled_extensions.data();
create_info.enabledExtensionCount   = static_cast<uint32_t>(enabled_extensions.size());

VpInstanceCreateInfo instance_create_info{};
instance_create_info.pEnabledFullProfiles    = &profile_properties;
instance_create_info.enabledFullProfileCount = 1;
instance_create_info.pCreateInfo             = &create_info;
result = vpCreateInstance(&instance_create_info, nullptr, &vulkan_instance);

// Device creation

std::vector<const char *> enabled_extensions;
enabled_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);

VkDeviceCreateInfo create_info{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
create_info.pNext                   = gpu.get_extension_feature_chain();
create_info.pQueueCreateInfos       = &queue_create_info;
create_info.queueCreateInfoCount    = 1;
create_info.enabledExtensionCount   = static_cast<uint32_t>(enabled_extensions.size());
create_info.ppEnabledExtensionNames = enabled_extensions.data();

VkBool32 profile_supported;
vpGetPhysicalDeviceProfileSupport(instance->get_handle(), gpu.get_handle(), &profile_properties, &profile_supported);
if (!profile_supported) {
    app_terminate("The selected profile is not supported (error at creating the device)!");
}

VpDeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.pCreateInfo             = &create_info;
deviceCreateInfo.pEnabledFullProfiles    = &profile_properties;
deviceCreateInfo.enabledFullProfileCount = 1;
VkResult result = vpCreateDevice(gpu.get_handle(), &deviceCreateInfo, nullptr, &vulkan_device);

这将启用所选配置中定义的所有特性和扩展,包括描述符索引。通过传递实例和/或设备的 pCreateInfo,您还可以启用不属于配置的其他扩展。

在像 RenderDoc 这样的图形调试器中检查使用配置创建的设备,我们可以看到配置库根据我们选择的 配置 执行了以下操作:

在实例创建时设置适当的 Vulkan 版本

RenderDoc instance Api version

启用设备特性并设置 pNext 链

RenderDoc device pNext

并启用所有必需的扩展(包括显式请求的扩展)

RenderDoc device extensions

结论

使用配置可以更容易地设置扩展和特性的基线。它还节省了大量代码,因为您不再需要担心启用扩展、设置其特性结构和正确链接 pNext 结构。