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_CALLHMS_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函数只返回数量。返回值是VkResultVK_SUCCESS查询成功所有扩展信息都返回了VK_INCOMPLETE你提供的数组太小只返回了部分信息XEG_ExtensionProperties 结构体每个扩展的信息通过XEG_ExtensionProperties结构体返回structXEG_ExtensionProperties{charextensionName[XEG_MAX_EXTENSION_NAME_SIZE];// 扩展名称// ... 可能还有其他字段};XEG_MAX_EXTENSION_NAME_SIZE的值是 256意味着扩展名最长 255 个字符加上结尾的\0。典型用法两步查询法Vulkan 风格的查询通常是两步走先问有多少个再一个个取回来。下面的流程图展示了完整的查询流程是否是否调用查询接口 pPropertiesNULL获取扩展数量propertyCountpropertyCount是否为0?没有可用扩展分配propertyCount大小的数组再次调用查询接口获取扩展列表返回值是否VK_INCOMPLETE?数组太小, 重新分配并查询遍历扩展列表用strcmp匹配目标扩展名找到目标扩展初始化对应XEngine特性// 第一步查询扩展数量uint32_tpropertyCount0;VkResult resultHMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice,propertyCount,NULL);if(result!VK_SUCCESS||propertyCount0){// 没有可用的 XEngine 扩展return;}// 第二步分配空间并查询扩展列表XEG_ExtensionProperties*properties(XEG_ExtensionProperties*)malloc(sizeof(XEG_ExtensionProperties)*propertyCount);resultHMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice,propertyCount,properties);if(result!VK_SUCCESS){free(properties);return;}// 第三步遍历扩展列表查找你需要的特性for(uint32_ti0;ipropertyCount;i){printf(XEngine Extension: %s\n,properties[i].extensionName);}free(properties);检查具体特性是否支持拿到扩展列表之后你可以检查你需要的特性是否在里面。下面的流程图展示了 XEngine 支持的主要扩展特性XEngine扩展特性图像增强类光照渲染类计算加速类XEG_spatial_upscale: 空域超分XEG_temporal_upscale: 时域超分XEG_adaptive_vrs: 自适应着色XEG_rtgi: 全局光照XEG_rt_shadow_ao: 阴影环境光遮蔽XEG_rt_reflection: 光线追踪反射XEG_hps_radix_sort: 高性能基数排序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 超分}// 自适应 VRSif(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_NAMEXEG_spatial_upscaleXEG_TEMPORAL_UPSCALE_EXTENSION_NAMEXEG_temporal_upscaleXEG_ADAPTIVE_VRS_EXTENSION_NAMEXEG_adaptive_vrsXEG_RTGI_EXTENSION_NAMEXEG_rtgiXEG_RT_SHADOW_AO_EXTENSION_NAMEXEG_rt_shadow_aoXEG_RT_REFLECTION_EXTENSION_NAMEXEG_rt_reflectionXEG_HPS_RADIX_SORT_EXTENSION_NAMEXEG_hps_radix_sort封装一个辅助函数在实际项目里你可能会频繁查询某个特定扩展是否支持。建议封装一个辅助函数boolisXEngineExtensionSupported(VkPhysicalDevice physicalDevice,constchar*extensionName){uint32_tpropertyCount0;HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice,propertyCount,NULL);if(propertyCount0)returnfalse;XEG_ExtensionProperties*propertiesmalloc(sizeof(XEG_ExtensionProperties)*propertyCount);HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice,propertyCount,properties);bool foundfalse;for(uint32_ti0;ipropertyCount;i){if(strcmp(properties[i].extensionName,extensionName)0){foundtrue;break;}}free(properties);returnfound;}// 使用if(isXEngineExtensionSupported(physicalDevice,XEG_TEMPORAL_UPSCALE_EXTENSION_NAME)){// 初始化时域超分...}当然更高效的做法是在初始化的时候查询一次把结果缓存起来后面直接查缓存。VK_INCOMPLETE 的处理如果HMS_XEG_EnumerateDeviceExtensionProperties返回VK_INCOMPLETE说明你提供的数组太小了只拿到了部分扩展信息。这种情况一般发生在你第一次查询之后、第二次查询之前系统支持的扩展数量增加了理论上不太可能发生但防御性编程总没错。处理方式很简单用返回的propertyCount重新分配空间再查一次。和 GLES 版的对比方面GLES 版Vulkan 版查询函数HMS_XEG_GetStringHMS_XEG_EnumerateDeviceExtensionProperties返回格式空格分隔的字符串结构体数组判断方式strstr字符串搜索strcmp精确匹配物理设备参数不需要需要VkPhysicalDeviceVulkan 版的查询虽然代码多一点但更结构化、更不容易出错。字符串搜索有时候会碰到子串匹配的问题比如XEG_spatial会匹配到XEG_spatial_upscale而strcmp是精确匹配不会有这个问题。使用建议初始化时查询一次就够了扩展列表在运行过程中不会变。在 Vulkan 设备创建之后、特性初始化之前查一次把结果存起来。封装辅助函数别每次都写一堆查询代码封装一个isXEngineExtensionSupported函数会让代码清爽很多。注意物理设备Vulkan 可能有多个物理设备比如集成显卡和独立显卡。确保你查询的是你实际使用的那个物理设备。