鸿蒙开发-Vulkan下也能自动省GPU?自适应可变速率着色
本文介绍了Vulkan环境下实现自适应可变速率着色(VRS)的方法,重点对比了与OpenGL ES版本的差异。Vulkan版采用对象管理模式,主要流程包括:1)通过查询扩展检查支持;2)创建XEG_AdaptiveVRS对象;3)将VRS计算命令录制到命令缓冲;4)手动销毁对象。相比GLES的直接调用方式,Vulkan版虽然代码量增加,但提供了更灵活的命令管理和更好的多线程支持。文章详细说明了各步
Vulkan 版自适应 VRS:用命令缓冲实现更灵活的着色率优化
如果你的图形引擎用的是 Vulkan 而不是 OpenGL ES,那自适应 VRS(Variable Rate Shading)的接入方式会有些不同。Vulkan 版的接口设计更符合 Vulkan 的风格——用句柄管理对象、用命令缓冲记录操作、用结构体传递参数。
这篇文章就来讲讲怎么在 Vulkan 环境下使用 XEngine 的自适应 VRS 特性。
Vulkan 版和 GLES 版有什么不同
最大的不同是 API 风格。GLES 版是直接调用函数,Vulkan 版是"创建对象 -> 录制命令 -> 销毁对象"的三步走模式。这和 Vulkan 本身的设计哲学是一致的:把操作记录到命令缓冲里,然后统一提交执行。
下面的流程图展示了 Vulkan 版自适应 VRS 的整体使用流程:
另外,Vulkan 版需要你通过 HMS_XEG_EnumerateDeviceExtensionProperties 接口来查询扩展支持,而不是 GLES 版的 HMS_XEG_GetString。
第一步:查询扩展支持
在 Vulkan 里查询 XEngine 扩展:
// 先查询支持的扩展数量
uint32_t propertyCount = 0;
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, NULL);
// 分配空间并查询扩展列表
XEG_ExtensionProperties* properties = (XEG_ExtensionProperties*)malloc(
sizeof(XEG_ExtensionProperties) * propertyCount
);
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, properties);
// 检查是否支持自适应 VRS
bool supportsAdaptiveVRS = false;
for (uint32_t i = 0; i < propertyCount; i++) {
if (strcmp(properties[i].extensionName, XEG_ADAPTIVE_VRS_EXTENSION_NAME) == 0) {
supportsAdaptiveVRS = true;
break;
}
}
free(properties);
if (!supportsAdaptiveVRS) {
return; // 不支持
}
HMS_XEG_EnumerateDeviceExtensionProperties 接受三个参数:
physicalDevice:当前使用的 Vulkan 物理设备pPropertyCount:指向扩展数量的指针。当pProperties为 NULL 时,返回支持的扩展数量pProperties:指向XEG_ExtensionProperties数组的指针,用于接收查询结果
查询成功返回 VK_SUCCESS,如果传入的数量不够则返回 VK_INCOMPLETE。
XEG_ADAPTIVE_VRS_EXTENSION_NAME 的值是 "XEG_adaptive_vrs"。
第二步:创建 XEG_AdaptiveVRS 对象
Vulkan 的哲学是"万物皆对象"。自适应 VRS 也不例外,你需要先创建一个 XEG_AdaptiveVRS 句柄:
XEG_AdaptiveVRS adaptiveVRS = VK_NULL_HANDLE;
XEG_AdaptiveVRSCreateInfo createInfo = {
.sType = XEG_STRUCTURE_TYPE_RT_SHADOWAO_CREATE_INFO, // 结构体类型
// ... 其他创建参数
};
VkResult result = HMS_XEG_CreateAdaptiveVRS(device, &createInfo, &adaptiveVRS);
if (result != VK_SUCCESS) {
// 创建失败,处理错误
return;
}
HMS_XEG_CreateAdaptiveVRS 有三个参数:
device:当前使用的VkDevicepXegAdaptiveVRSCreateInfo:创建参数结构体的指针,不允许为空pXegAdaptiveVRS:指向句柄的指针,创建成功后句柄会写入这里
当创建参数(比如分辨率、渲染区域等)发生变化时,你需要销毁旧对象、创建新对象。
第三步:录制自适应 VRS 命令
有了句柄之后,你可以在 Vulkan 命令缓冲里录制自适应 VRS 的计算命令:
// 准备描述信息
XEG_AdaptiveVRSDescription description = {
// ... 每一帧需要更新的参数
};
// 录制命令到命令缓冲
HMS_XEG_CmdDispatchAdaptiveVRS(commandBuffer, adaptiveVRS, &description);
HMS_XEG_CmdDispatchAdaptiveVRS 有三个参数:
commandBuffer:当前记录命令的VkCommandBuffer,这个命令缓冲必须被提交到vkQueueSubmit才会真正执行xegAdaptiveVRS:已创建的XEG_AdaptiveVRS对象pXegAdaptiveVRSDescription:参数结构体的指针,不允许为空。这个结构体里的信息每一帧都需要更新
注意,这个函数只是把命令"录制"到命令缓冲里,并不会立即执行。你需要在合适的时候提交命令缓冲,命令才会真正运行。
第四步:销毁对象
当你不再需要自适应 VRS 的时候(比如游戏退出或者分辨率切换),记得销毁对象:
HMS_XEG_DestroyAdaptiveVRS(adaptiveVRS);
这一步很重要。Vulkan 不像 OpenGL 那样有自动的资源回收机制,你创建的每一个对象都需要手动销毁。
完整流程
// 1. 查询扩展支持
uint32_t propertyCount = 0;
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, NULL);
XEG_ExtensionProperties* properties = malloc(sizeof(XEG_ExtensionProperties) * propertyCount);
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice, &propertyCount, properties);
bool supported = false;
for (uint32_t i = 0; i < propertyCount; i++) {
if (strcmp(properties[i].extensionName, XEG_ADAPTIVE_VRS_EXTENSION_NAME) == 0) {
supported = true;
break;
}
}
free(properties);
if (!supported) return;
// 2. 创建对象
XEG_AdaptiveVRS adaptiveVRS = VK_NULL_HANDLE;
XEG_AdaptiveVRSCreateInfo createInfo = { /* ... */ };
HMS_XEG_CreateAdaptiveVRS(device, &createInfo, &adaptiveVRS);
// 3. 每帧:录制命令
XEG_AdaptiveVRSDescription desc = { /* 当前帧参数 */ };
HMS_XEG_CmdDispatchAdaptiveVRS(commandBuffer, adaptiveVRS, &desc);
// 4. 退出时销毁
HMS_XEG_DestroyAdaptiveVRS(adaptiveVRS);
和 GLES 版的对比
下面的流程图对比了 GLES 版和 Vulkan 版在执行方式上的差异:
| 方面 | GLES 版 | Vulkan 版 |
|---|---|---|
| 查询接口 | HMS_XEG_GetString |
HMS_XEG_EnumerateDeviceExtensionProperties |
| 参数设置 | HMS_XEG_AdaptiveVRSParameter 逐个设置 |
通过结构体传递 |
| 执行方式 | 直接调用 | 录制到命令缓冲 |
| 资源管理 | 无显式销毁 | 需要手动创建和销毁 |
| 对象模型 | 无 | XEG_AdaptiveVRS 句柄 |
Vulkan 版的代码量确实比 GLES 版多一些,但换来的是更灵活的命令管理和更好的多线程支持。
使用建议
-
对象生命周期管理:创建参数变化时需要重建对象。建议用一个标志位来跟踪参数是否变化。
-
命令缓冲要提交:
HMS_XEG_CmdDispatchAdaptiveVRS只是录制命令,记得在合适的时候提交命令缓冲。 -
描述信息每帧更新:
XEG_AdaptiveVRSDescription里的信息每一帧都需要更新,因为着色率图是根据当前帧的输入动态计算的。 -
错误检查:创建函数返回
VkResult,记得检查返回值是否为VK_SUCCESS。
Vulkan 版自适应 VRS 适合那些已经用 Vulkan 做渲染引擎的项目。虽然接入成本比 GLES 版高一些,但能更好地融入 Vulkan 的渲染管线。
更多推荐

所有评论(0)