鸿蒙开发--@ohos.multimedia.media用法
2026/6/8 11:45:56 网站建设 项目流程

HarmonyOS 自适应 VRS:用 Vulkan 降低 GPU 渲染负载

什么是 VRS

你玩 3D 游戏的时候有没有注意到,画面中间你盯着看的地方特别清晰,但边缘部分其实没那么精细?人眼就是这样,对中心区域的细节更敏感,对边缘区域不太在意。

VRS(Variable Rate Shading,可变速率着色)就是利用了这个原理。它允许 GPU 对画面的不同区域使用不同的渲染精度:重要的区域(比如你盯着看的地方)用高精度渲染,不重要的区域(比如边缘、背景)用低精度渲染。

自适应 VRS 更进一步:它会自动分析画面内容,智能决定哪些区域需要高精度渲染,哪些可以降低精度。这样既保证了视觉效果,又降低了 GPU 的负载,提高了帧率。

环境搭建

硬件要求

  • 设备类型:请参考 XEngine 开发指南的硬件要求

软件要求

  • DevEco Studio 版本:DevEco Studio 6.0.0 Release 及以上
  • HarmonyOS SDK 版本:HarmonyOS 6.0.0 Release SDK 及以上

搭建步骤

  1. 安装 DevEco Studio:去华为开发者官网下载安装
  2. 配置开发环境:确保网络环境正常
  3. 设备调试:使用真机进行调试

项目结构

├── entry/src/main // 代码区 │ ├── cpp │ │ ├── types │ │ │ ├── libnativerender │ │ │ └── index.d.ts // native层接口注册文件 │ │ │── napi_init.cpp // native api层接口的具体实现函数 │ │ │── CMakeLists.txt // native层编译配置 │ │ │── 3rdParty // 三方件 │ │ │── common // 通用接口 │ │ │── file // 文件管理 │ │ │── libs // 三方动态库 │ │ │── manager // native&arkts交互 │ │ │── render // 渲染 │ │ │── vulkanbase // vulkan基础能力封装 │ ├── ets │ │ ├── entryability │ │ │ └── EntryAbility.ts // 程序入口类 │ │ ├── pages │ │ │ └── index.ets // 主界面展示类 │ ├── resources // 资源文件目录 │ │ ├── base │ │ │ ├── media │ │ │ └── icon.png // 图片资源 │ │ ├── rawfile │ │ │ ├── Sponza │ │ │ └── sponza.obj // 模型资源

这个项目使用 Vulkan 图形 API,代码主要在 C++ 层。vulkanbase目录里封装了 Vulkan 的基础能力,render目录里是渲染相关的代码。

第一步:引入头文件

#include<string>#include<vector>#include<algorithm>#include<xengine/xeg_vulkan_extension.h>#include<xengine/xeg_vulkan_adaptive_vrs.h>

这些头文件的作用:

  • stringvectoralgorithm:C++ 标准库,处理字符串、数组、查找等
  • xeg_vulkan_extension.h:XEngine 的 Vulkan 扩展接口,用来查询设备支持哪些扩展
  • xeg_vulkan_adaptive_vrs.h:自适应 VRS 的核心接口,创建实例、生成着色率纹理等

第二步:配置 CMakeLists.txt

find_library( xengine-lib xengine ) find_library( EGL-lib EGL ) find_library( Vulkan-lib vulkan ) target_link_libraries(nativerender PUBLIC ${EGL-lib} ${Vulkan-lib} ${xengine-lib})

这里链接了三个库:

  • xengine:XEngine 的核心库,自适应 VRS 的功能就在这个库里
  • EGL:OpenGL ES 的窗口系统接口
  • vulkan:Vulkan 图形 API 的库

第三步:查询设备是否支持自适应 VRS

在使用自适应 VRS 之前,必须先检查设备是否支持这个功能。就像你买电器之前要先看看家里有没有对应的插座。

VkPhysicalDevice physicalDevice;std::vector<std::string>supportedExtensions;uint32_tpPropertyCount;

先定义几个变量:

  • physicalDevice:Vulkan 物理设备,代表你的 GPU
  • supportedExtensions:存储支持的扩展名称
  • pPropertyCount:扩展的数量
HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice,&pPropertyCount,nullptr);if(pPropertyCount>0){std::vector<XEG_ExtensionProperties>pProperties(pPropertyCount);if(HMS_XEG_EnumerateDeviceExtensionProperties(physicalDevice,&pPropertyCount,&pProperties.front())==VK_SUCCESS){for(autoext:pProperties){supportedExtensions.push_back(ext.extensionName);}}}

调用HMS_XEG_EnumerateDeviceExtensionProperties查询设备支持的扩展。这个函数调用两次:

  1. 第一次传nullptr,只获取扩展数量(pPropertyCount
  2. 第二次传入数组,获取所有扩展的详细信息

这是 Vulkan 的标准用法,很多 Vulkan API 都是这种"先问数量,再取数据"的模式。

if(std::find(supportedExtensions.begin(),supportedExtensions.end(),XEG_ADAPTIVE_VRS_EXTENSION_NAME)==supportedExtensions.end()){exit(1);// return error}

std::find在支持的扩展列表里查找自适应 VRS 的扩展名。如果找不到,说明设备不支持,直接退出程序。

第四步:创建自适应 VRS 实例

XEG_AdaptiveVRS xeg_adaptiveVRS;

先声明一个实例句柄。这个句柄就像一个"遥控器",后面所有的 VRS 操作都要通过它。

intm_renderWidth;intm_renderHeight;intVRS_TILE_SIZE;VkDevice device;XEG_AdaptiveVRSCreateInfo xeg_createInfo;XEG_AdaptiveVRSDescription xeg_description;

定义一些变量:

  • m_renderWidthm_renderHeight:渲染的宽高
  • VRS_TILE_SIZE:VRS 的分片大小。画面会被分成很多小块,每块独立决定渲染精度
  • device:Vulkan 逻辑设备
  • xeg_createInfo:创建 VRS 实例所需的参数
  • xeg_description:下发着色率纹理命令所需的参数
VkExtent2D inputSize;inputSize.width=m_renderWidth;inputSize.height=m_renderHeight;VkRect2D inputRegion{};inputRegion.extent.width=m_renderWidth;inputRegion.extent.height=m_renderHeight;inputRegion.offset.x=0;inputRegion.offset.y=0;

设置输入尺寸和区域:

  • inputSize:上一帧渲染结果的图像尺寸
  • inputRegion:输入纹理的区域,从 (0,0) 开始,大小等于渲染宽高
xeg_createInfo.inputSize=inputSize;xeg_createInfo.inputRegion=inputRegion;xeg_createInfo.adaptiveTileSize=VRS_TILE_SIZE;xeg_createInfo.errorSensitivity=0.5;xeg_createInfo.flip=false;

配置创建参数:

  • inputSize:输入图像的尺寸
  • inputRegion:输入图像的区域
  • adaptiveTileSize:分片大小,越小精度越高,但计算量也越大
  • errorSensitivity:误差敏感度,0.5 是一个平衡点。值越小,越倾向于高精度渲染;值越大,越倾向于低精度渲染
  • flip:是否翻转图像。false 表示不翻转
HMS_XEG_CreateAdaptiveVRS(device,&xeg_createInfo,&xeg_adaptiveVRS);

最后调用HMS_XEG_CreateAdaptiveVRS创建实例。如果创建成功,xeg_adaptiveVRS就被初始化了。

第五步:生成着色率纹理

这是自适应 VRS 的核心步骤:根据上一帧的渲染结果,生成一个"着色率纹理",告诉 GPU 每个区域应该用什么精度渲染。

VkImageView inputColorImageView=VK_NULL_HANDLE;VkImageView inputDepthImageView=VK_NULL_HANDLE;VkImageView outputShadingRateImage=VK_NULL_HANDLE;VkCommandBuffer commandBuffer=VK_NULL_HANDLE;

定义三个图像视图和一个命令缓冲区:

  • inputColorImageView:上一帧的颜色附件,就是渲染出来的彩色画面
  • inputDepthImageView:上一帧的深度附件,记录了每个像素离相机有多远
  • outputShadingRateImage:输出的着色率纹理,GPU 会根据这个纹理决定每个区域的渲染精度
  • commandBuffer:Vulkan 命令缓冲区,用来记录和执行 GPU 命令
xeg_description.inputColorImage=inputColorImageView;xeg_description.inputDepthImage=inputDepthImageView;xeg_description.outputShadingRateImage=outputShadingRateImage;xeg_description.reprojectionMatrix=nullptr;HMS_XEG_CmdDispatchAdaptiveVRS(commandBuffer,xeg_adaptiveVRS,&xeg_description);

把参数填入xeg_description,然后调用HMS_XEG_CmdDispatchAdaptiveVRS下发命令。

这个函数会分析上一帧的颜色和深度信息,然后生成着色率纹理。分析的逻辑大概是:

  • 颜色变化剧烈的区域(比如物体边缘):保持高精度
  • 颜色变化平缓的区域(比如纯色背景):降低精度
  • 深度变化大的区域(比如前景和背景交界处):保持高精度

reprojectionMatrix是重投影矩阵,用于处理相机运动时的对齐。如果相机不动,可以传nullptr

第六步:销毁实例

HMS_XEG_DestroyAdaptiveVRS(xeg_adaptiveVRS);

不需要 VRS 功能时,调用HMS_XEG_DestroyAdaptiveVRS销毁实例,释放内存资源。这就像用完遥控器要关机一样。

自适应 VRS 的整体工作流程如下:

查询设备是否支持自适应VRS

创建自适应VRS实例

配置输入尺寸和分片大小

设置误差敏感度

每帧获取上一帧渲染结果

调用 CmdDispatchAdaptiveVRS

分析颜色变化和深度变化

生成着色率纹理

GPU 根据着色率渲染下一帧

自适应 VRS 的工作原理

让我用更通俗的语言解释整个流程:

  1. 渲染上一帧:GPU 正常渲染一帧画面,得到颜色图和深度图
  2. 分析画面:自适应 VRS 分析颜色图和深度图,找出哪些区域需要高精度,哪些可以降低精度
  3. 生成着色率纹理:根据分析结果,生成一个纹理,每个区域标记一个渲染精度等级
  4. 渲染下一帧:GPU 在渲染下一帧时,根据着色率纹理,对不同区域使用不同的渲染精度

这个过程是每帧自动进行的,开发者只需要设置好参数,剩下的交给 XEngine 处理。

画面分析的决策逻辑如下:

是 如物体边缘

否 如纯色背景

是 如前后景交界

输入颜色图和深度图

按分片大小划分区域

分析每个区域的颜色变化

分析每个区域的深度变化

颜色变化是否剧烈?

深度变化是否剧烈?

保持高精度渲染

降低渲染精度

输出着色率纹理

适用场景

自适应 VRS 特别适合以下场景:

  • 3D 游戏:画面复杂,有很多区域可以降低精度
  • VR/AR 应用:对帧率要求极高,VRS 可以有效降低 GPU 负载
  • 图形渲染应用:需要稳定帧率的场景

注意事项

  1. 设备支持:不是所有设备都支持自适应 VRS,一定要先查询设备扩展
  2. 分片大小VRS_TILE_SIZE要根据你的应用来设置。太小精度高但计算量大,太大精度低但性能好
  3. 误差敏感度errorSensitivity要根据画面质量要求来调整。值越小画质越好,值越大性能越好
  4. 重投影矩阵:如果相机在移动,需要传入正确的重投影矩阵,否则着色率纹理会和画面对不上

总结

自适应 VRS 是一个很实用的图形优化技术,它能在不明显影响画质的情况下,显著降低 GPU 的渲染负载。核心流程:

  1. 查询设备是否支持自适应 VRS
  2. 创建自适应 VRS 实例,配置参数
  3. 每帧调用HMS_XEG_CmdDispatchAdaptiveVRS生成着色率纹理
  4. GPU 根据着色率纹理渲染下一帧
  5. 不需要时销毁实例

掌握了这些,你就能在 HarmonyOS 应用中实现自适应 VRS,让你的 3D 应用跑得更流畅。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询