鸿蒙开发-想用Vulkan的高级GPU特性?XEngine扩展功能详解
本文介绍了在Vulkan环境下查询XEngine支持特性的方法。与GLES的字符串查询不同,Vulkan使用HMS_XEG_EnumerateDeviceExtensionProperties接口,通过结构体数组返回扩展信息。文章详细解释了该接口的参数用法和典型的两步查询流程:先获取扩展数量,再获取具体扩展列表。同时给出了XEngine主要扩展特性的分类(图像增强、光照渲染、计算加速)和对应的扩展
Vulkan 下怎么查 XEngine 支持哪些特性?用枚举扩展接口
在 GLES 环境下,你用 HMS_XEG_GetString 一行代码就能查到所有支持的 XEngine 扩展。但到了 Vulkan 环境下,查询方式变了——你需要用 HMS_XEG_EnumerateDeviceExtensionProperties 接口。这篇文章就来详细讲讲这个 Vulkan 版的扩展查询接口怎么用。
为什么要用不同的接口
GLES 和 Vulkan 的设计理念不同。GLES 是"查字符串"风格——返回一个空格分隔的扩展名列表,你用字符串搜索来判断支持什么。Vulkan 是"查结构体"风格——返回一个结构体数组,每个结构体描述一个扩展的属性。
XEngine 遵循了各自的惯例,所以 GLES 版用字符串查询,Vulkan 版用结构体查询。
接口详解
HMS_XEG_EnumerateDeviceExtensionProperties 的函数签名是这样的:
VKAPI_ATTR VkResult VKAPI_CALL HMS_XEG_EnumerateDeviceExtensionProperties(
VkPhysicalDevice physicalDevice,
uint32_t *pPropertyCount,
XEG_ExtensionProperties *pProperties
);
三个参数:
physicalDevice:当前使用的 Vulkan 物理设备。就是你通过 vkEnumeratePhysicalDevices 拿到的那个。
pPropertyCount:指向数量的指针。这个参数的行为取决于 pProperties 是否为 NULL:
- 如果
pProperties为 NULL:函数会把支持的扩展数量写入*pPropertyCount - 如果
pProperties不为 NULL:*pPropertyCount表示你提供的数组大小
pProperties:指向 XEG_ExtensionProperties 数组的指针。如果为 NULL,函数只返回数量。
返回值是 VkResult:
VK_SUCCESS:查询成功,所有扩展信息都返回了VK_INCOMPLETE:你提供的数组太小,只返回了部分信息
XEG_ExtensionProperties 结构体
每个扩展的信息通过 XEG_ExtensionProperties 结构体返回:
struct XEG_ExtensionProperties {
char extensionName[XEG_MAX_EXTENSION_NAME_SIZE]; // 扩展名称
// ... 可能还有其他字段
};
XEG_MAX_EXTENSION_NAME_SIZE 的值是 256,意味着扩展名最长 255 个字符(加上结尾的 \0)。
典型用法:两步查询法
Vulkan 风格的查询通常是两步走:先问有多少个,再一个个取回来。下面的流程图展示了完整的查询流程:
// 第一步:查询扩展数量
uint32_t propertyCount = 0;
VkResult result = HMS_XEG_EnumerateDeviceExtensionProperties(
physicalDevice, &propertyCount, NULL
);
if (result != VK_SUCCESS || propertyCount == 0) {
// 没有可用的 XEngine 扩展
return;
}
// 第二步:分配空间并查询扩展列表
XEG_ExtensionProperties* properties = (XEG_ExtensionProperties*)malloc(
sizeof(XEG_ExtensionProperties) * propertyCount
);
result = HMS_XEG_EnumerateDeviceExtensionProperties(
physicalDevice, &propertyCount, properties
);
if (result != VK_SUCCESS) {
free(properties);
return;
}
// 第三步:遍历扩展列表,查找你需要的特性
for (uint32_t i = 0; i < propertyCount; i++) {
printf("XEngine Extension: %s\n", properties[i].extensionName);
}
free(properties);
检查具体特性是否支持
拿到扩展列表之后,你可以检查你需要的特性是否在里面。下面的流程图展示了 XEngine 支持的主要扩展特性:
XEngine 定义了一系列扩展名宏,方便你使用:
// 空域 GPU 超分
if (strcmp(properties[i].extensionName, XEG_SPATIAL_UPSCALE_EXTENSION_NAME) == 0) {
// 支持空域 GPU 超分
}
// 时域 AI 超分
if (strcmp(properties[i].extensionName, XEG_TEMPORAL_UPSCALE_EXTENSION_NAME) == 0) {
// 支持时域 AI 超分
}
// 自适应 VRS
if (strcmp(properties[i].extensionName, XEG_ADAPTIVE_VRS_EXTENSION_NAME) == 0) {
// 支持自适应 VRS
}
// 光线追踪全局光照
if (strcmp(properties[i].extensionName, XEG_RTGI_EXTENSION_NAME) == 0) {
// 支持 RTGI
}
// 光线追踪阴影和环境光遮蔽
if (strcmp(properties[i].extensionName, XEG_RT_SHADOW_AO_EXTENSION_NAME) == 0) {
// 支持 RT ShadowAO
}
// 光线追踪反射
if (strcmp(properties[i].extensionName, XEG_RT_REFLECTION_EXTENSION_NAME) == 0) {
// 支持 RT Reflection
}
// 高性能基数排序
if (strcmp(properties[i].extensionName, XEG_HPS_RADIX_SORT_EXTENSION_NAME) == 0) {
// 支持 HPS 基数排序
}
这些扩展名宏的值分别是:
| 宏名 | 值 |
|---|---|
XEG_SPATIAL_UPSCALE_EXTENSION_NAME |
"XEG_spatial_upscale" |
XEG_TEMPORAL_UPSCALE_EXTENSION_NAME |
"XEG_temporal_upscale" |
XEG_ADAPTIVE_VRS_EXTENSION_NAME |
"XEG_adaptive_vrs" |
XEG_RTGI_EXTENSION_NAME |
"XEG_rtgi" |
XEG_RT_SHADOW_AO_EXTENSION_NAME |
"XEG_rt_shadow_ao" |
XEG_RT_REFLECTION_EXTENSION_NAME |
"XEG_rt_reflection" |
XEG_HPS_RADIX_SORT_EXTENSION_NAME |
"XEG_hps_radix_sort" |
封装一个辅助函数
在实际项目里,你可能会频繁查询某个特定扩展是否支持。建议封装一个辅助函数:
bool isXEngineExtensionSupported(VkPhysicalDevice physicalDevice, const char* extensionName) {
uint32_t propertyCount = 0;
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, NULL);
if (propertyCount == 0) return false;
XEG_ExtensionProperties* properties = malloc(sizeof(XEG_ExtensionProperties) * propertyCount);
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, properties);
bool found = false;
for (uint32_t i = 0; i < propertyCount; i++) {
if (strcmp(properties[i].extensionName, extensionName) == 0) {
found = true;
break;
}
}
free(properties);
return found;
}
// 使用:
if (isXEngineExtensionSupported(physicalDevice, XEG_TEMPORAL_UPSCALE_EXTENSION_NAME)) {
// 初始化时域超分...
}
当然,更高效的做法是在初始化的时候查询一次,把结果缓存起来,后面直接查缓存。
VK_INCOMPLETE 的处理
如果 HMS_XEG_EnumerateDeviceExtensionProperties 返回 VK_INCOMPLETE,说明你提供的数组太小了,只拿到了部分扩展信息。这种情况一般发生在你第一次查询之后、第二次查询之前,系统支持的扩展数量增加了(理论上不太可能发生,但防御性编程总没错)。
处理方式很简单:用返回的 propertyCount 重新分配空间,再查一次。
和 GLES 版的对比
| 方面 | GLES 版 | Vulkan 版 |
|---|---|---|
| 查询函数 | HMS_XEG_GetString |
HMS_XEG_EnumerateDeviceExtensionProperties |
| 返回格式 | 空格分隔的字符串 | 结构体数组 |
| 判断方式 | strstr 字符串搜索 |
strcmp 精确匹配 |
| 物理设备参数 | 不需要 | 需要 VkPhysicalDevice |
Vulkan 版的查询虽然代码多一点,但更结构化、更不容易出错。字符串搜索有时候会碰到子串匹配的问题(比如 "XEG_spatial" 会匹配到 "XEG_spatial_upscale"),而 strcmp 是精确匹配,不会有这个问题。
使用建议
-
初始化时查询一次就够了:扩展列表在运行过程中不会变。在 Vulkan 设备创建之后、特性初始化之前查一次,把结果存起来。
-
封装辅助函数:别每次都写一堆查询代码,封装一个
isXEngineExtensionSupported函数会让代码清爽很多。 -
注意物理设备:Vulkan 可能有多个物理设备(比如集成显卡和独立显卡)。确保你查询的是你实际使用的那个物理设备。
更多推荐



所有评论(0)