HarmonyOS 自适应 VRS OpenGL ES 版:降低 GPU 负载的另一种选择
什么是自适应 VRS
上一篇我们介绍了用 Vulkan 实现自适应 VRS,这篇来看看用 OpenGL ES 怎么做。功能是一样的:自动分析画面,对不同区域使用不同的渲染精度,从而降低 GPU 负载。
简单回顾一下 VRS 的原理:人眼对画面中心的细节更敏感,对边缘区域不太在意。VRS 就是利用这个特点,重要的地方精细渲染,不重要的地方粗糙渲染,既保证视觉效果又提高性能。
环境搭建
硬件要求
- 设备类型:请参考 XEngine 开发指南的硬件要求
软件要求
- DevEco Studio 版本:DevEco Studio 6.0.0 Release 及以上
- HarmonyOS SDK 版本:HarmonyOS 6.0.0 Release SDK 及以上
搭建步骤
- 安装 DevEco Studio:去华为开发者官网下载安装
- 配置开发环境:确保网络环境正常
- 设备调试:使用真机进行调试
项目结构
├── entry/src/main // 代码区 │ ├── cpp │ │ ├── types │ │ │ ├── libnativerender │ │ │ └── index.d.ts // native层接口注册文件 │ │ │── napi_init.cpp // native api层接口的具体实现函数 │ │ │── CMakeLists.txt // native层编译配置 │ │ │── 3rdParty // 三方件 │ │ │── common // 通用接口 │ │ │── model // 模型 │ │ │── file // 文件管理 │ │ │── libs // 三方动态库 │ │ │── manager // native&arkts交互 │ │ │── render // 渲染 │ │ │── shader // 渲染shader │ ├── ets │ │ ├── entryability │ │ │ └── EntryAbility.ts // 程序入口类 │ │ ├── pages │ │ │ └── index.ets // 主界面展示类 │ ├── resources // 资源文件目录 │ │ ├── base │ │ │ ├── media │ │ │ └── icon.png // 图片资源 │ │ ├── rawfile/model/Sponza │ │ │ └── sponza.obj // 模型资源第一步:引入头文件
#include<cstring>#include<cstdlib>#include<xengine/xeg_gles_extension.h>#include<xengine/xeg_gles_adaptive_vrs.h>这些头文件的作用:
cstring、cstdlib:C++ 标准库xeg_gles_extension.h:XEngine 的 OpenGL ES 扩展接口xeg_gles_adaptive_vrs.h:自适应 VRS 的核心接口
第二步:配置 CMakeLists.txt
find_library( xengine-lib xengine ) find_library( EGL-lib EGL ) find_library( GLES-lib GLESv3 ) target_link_libraries(nativerender PUBLIC ${EGL-lib} ${GLES-lib} ${xengine-lib})链接了xengine、EGL和GLESv3三个库。
第三步:查询设备是否支持
constchar*extensions=(constchar*)HMS_XEG_GetString(XEG_EXTENSIONS);if(!strstr(extensions,XEG_ADAPTIVE_VRS_EXTENSION_NAME)){exit(1);// return error}和 Vulkan 版本一样,先检查设备是否支持自适应 VRS。OpenGL ES 的查询方式更简单,直接调用HMS_XEG_GetString获取扩展列表字符串,然后用strstr查找。
第四步:设置 VRS 参数
这是自适应 VRS 的配置步骤,需要设置多个参数:
设置输入尺寸
uint32_trenderWidth=800;uint32_trenderHeight=600;GLsizei inputSize[2]={static_cast<GLsizei>(renderWidth),static_cast<GLsizei>(renderHeight)};HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_INPUT_SIZE,inputSize);设置输入图像的尺寸,就是上一帧渲染结果的大小。inputSize是一个包含宽高的数组。
设置输入区域
GLuint inputRegion[4]={0,0,renderWidth,renderHeight};HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_INPUT_REGION,inputRegion);设置输入图像的采样区域。inputRegion是一个包含 4 个元素的数组:起始坐标 (x, y) 和宽高。从 (0, 0) 开始,大小等于渲染分辨率,表示处理整个图像。
设置分片大小
GLsizei texelSizes[2]={8,8};HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_TEXEL_SIZE,texelSizes);设置 VRS 的分片大小。画面会被分成很多小块,每块独立决定渲染精度。当前支持两种规格:
[8, 8]:8x8 像素一块,精度高但计算量大[16, 16]:16x16 像素一块,精度低但性能好
设置误差敏感度
GLfloat sensitivity=0.15;HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_ERROR_SENSITIVITY,&sensitivity);设置误差敏感度阈值,取值范围 [0, 1]。值越小,越倾向于高精度渲染;值越大,越倾向于低精度渲染。0.15 是一个比较保守的值,画质影响很小。
设置翻转选项
GLboolean flip=false;HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_FLIP,&flip);设置是否翻转图像。false表示不翻转。
第五步:生成着色率纹理
GLuint inputColorImage;GLuint inputDepthImage;GLuint outputShadingRateImage;float*reprojectionMatrix=nullptr;HMS_XEG_DispatchAdaptiveVRS(reprojectionMatrix,inputColorImage,inputDepthImage,outputShadingRateImage);调用HMS_XEG_DispatchAdaptiveVRS生成着色率纹理。参数说明:
reprojectionMatrix:重投影矩阵,用于处理相机运动。如果相机不动,传nullptrinputColorImage:上一帧的颜色纹理,就是渲染出来的彩色画面inputDepthImage:深度纹理,记录每个像素离相机有多远outputShadingRateImage:输出的着色率纹理,GPU 会根据它决定每个区域的渲染精度
第六步:应用着色率纹理
HMS_XEG_ApplyAdaptiveVRS(outputShadingRateImage);最后调用HMS_XEG_ApplyAdaptiveVRS把着色率纹理应用到渲染目标中。之后 GPU 在渲染下一帧时,就会根据这个纹理来决定每个区域的渲染精度。
自适应 VRS 的整体工作流程如下:
VRS 参数配置的决策流程:
OpenGL ES 版和 Vulkan 版的区别
对比一下两个版本:
| 方面 | OpenGL ES 版 | Vulkan 版 |
|---|---|---|
| 查询扩展 | HMS_XEG_GetString | HMS_XEG_EnumerateDeviceExtensionProperties |
| 设置参数 | HMS_XEG_AdaptiveVRSParameter | 通过创建结构体 |
| 生成着色率 | HMS_XEG_DispatchAdaptiveVRS | HMS_XEG_CmdDispatchAdaptiveVRS |
| 应用着色率 | HMS_XEG_ApplyAdaptiveVRS | 自动应用 |
| 销毁实例 | 无需显式销毁 | HMS_XEG_DestroyAdaptiveVRS |
主要区别:
- API 风格:OpenGL ES 版用函数参数设置,Vulkan 版用结构体设置
- 资源管理:OpenGL ES 版不需要显式销毁实例,Vulkan 版需要
- 命令提交:Vulkan 版需要通过命令缓冲区提交,OpenGL ES 版直接调用
选择哪个版本取决于你的应用已经在用哪个图形 API。
适用场景
自适应 VRS 特别适合以下场景:
- 3D 游戏:画面复杂,有很多区域可以降低精度
- VR/AR 应用:对帧率要求极高
- 图形渲染应用:需要稳定帧率的场景
注意事项
- 设备支持:不是所有设备都支持自适应 VRS,一定要先查询扩展
- 分片大小:8x8 精度高但性能开销大,16x16 性能好但精度低,要根据实际需求选择
- 误差敏感度:
sensitivity要根据画面质量要求来调整 - 重投影矩阵:如果相机在移动,需要传入正确的重投影矩阵
总结
OpenGL ES 版本的自适应 VRS 和 Vulkan 版本功能相同,核心流程:
- 查询设备是否支持
- 设置参数(输入尺寸、分片大小、误差敏感度等)
- 调用
HMS_XEG_DispatchAdaptiveVRS生成着色率纹理 - 调用
HMS_XEG_ApplyAdaptiveVRS应用着色率纹理
如果你的应用已经在用 OpenGL ES,用这个版本会更方便。如果用的是 Vulkan,就用 Vulkan 版本。