鸿蒙开发-想让GPU自动省着画?GLES自适应可变速率着色
2026/6/1 17:15:57 网站建设 项目流程

你有没有玩过那种大场景的 3D 游戏,角色跑起来很流畅,但一到复杂的场景帧率就往下掉?其实很多时候,画面里有很大一部分区域是玩家根本不会仔细看的——比如远处的草地、快速移动时的背景。这些区域用全分辨率去渲染,说白了就是浪费算力。

VRS(Variable Rate Shading,可变着色率)就是为了解决这个问题的。它允许你对画面的不同区域使用不同的着色精度:画面中心(玩家关注的地方)用高精度,边缘和远处用低精度。这样既保证了视觉效果,又省了 GPU 算力。

而"自适应"VRS 更进一步——它不需要你手动指定哪些区域用低精度,而是根据上一帧的颜色和深度信息,自动分析出哪些区域可以降低着色率。省心又高效。

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

不支持

支持

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

使用普通渲染

设置输入参数

INPUT_SIZE: 输入图像尺寸

INPUT_REGION: 渲染区域

TEXEL_SIZE: 着色率粒度

ERROR_SENSITIVITY: 灵敏度

每帧调用 DispatchAdaptiveVRS

输入: 上一帧颜色 + 当前帧深度

算法自动分析各区域复杂度

输出: 着色率图

ApplyAdaptiveVRS 应用着色率

后续绘制按着色率图着色

这个功能的使用前提

在 OpenGL ES 里使用自适应 VRS 之前,你得先确认设备支持这个特性。怎么确认呢?就是用上一篇文章讲的扩展查询接口:

constGLubyte*extensions=HMS_XEG_GetString(XEG_EXTENSIONS);bool supportsAdaptiveVRS=strstr((constchar*)extensions,"XEG_adaptive_vrs")!=NULL;

只有当supportsAdaptiveVRS为 true 的时候,你才能继续往下走。

整体流程

自适应 VRS 的使用分三步:

  1. 设置参数:告诉算法输入图像的尺寸、裁剪区域等信息
  2. 计算着色率图:算法根据上一帧的颜色和深度,生成一张着色率图像
  3. 应用着色率:把生成的着色率图像应用到当前帧的渲染目标上

下面一步一步来看。

第一步:设置参数

你需要通过HMS_XEG_AdaptiveVRSParameter函数来设置各种输入参数。这个函数接受两个参数:pname是参数名(用宏定义),param是参数值的指针。

设置输入图像尺寸(必填)

这是最重要的参数,必须设置。它告诉算法上一帧渲染结果的宽高:

GLsizei inputSize[2]={1920,1080};// 上一帧渲染结果的宽和高HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_INPUT_SIZE,inputSize);

XEG_ADAPTIVE_VRS_INPUT_SIZE的值是0x1U。传入的必须是长度为 2 的GLsizei数组,第一个元素是宽度,第二个是高度。这个值必须和后面HMS_XEG_DispatchAdaptiveVRS函数传入的inputColorImage纹理的宽高保持一致,否则会产生未定义行为。

设置渲染区域(可选)

如果你只渲染了画面的一部分区域(比如有黑边或者裁剪),可以用XEG_ADAPTIVE_VRS_INPUT_REGION来指定:

GLuint inputRegion[4]={0,0,1920,1080};// 左下角x, y, 宽, 高HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_INPUT_REGION,inputRegion);

XEG_ADAPTIVE_VRS_INPUT_REGION的值是0x2U。传入的是长度为 4 的GLuint数组,依次表示渲染区域左下角的 x、y 坐标和区域的宽高。如果不设置,默认值是整个输入图像的范围。

设置纹素大小(可选)

XEG_ADAPTIVE_VRS_TEXEL_SIZE控制着色率图的最小单元大小:

GLsizei texelSize[2]={8,8};// 支持 [8, 8] 和 [16, 16]HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_TEXEL_SIZE,texelSize);

XEG_ADAPTIVE_VRS_TEXEL_SIZE的值是0x3U。默认值是[8, 8],意味着每个 8x8 的像素块共享一个着色率。你也可以设成[16, 16],精度更低但性能更好。

设置误差灵敏度(可选)

XEG_ADAPTIVE_VRS_ERROR_SENSITIVITY控制算法判定"可以降低着色率"的阈值:

GLfloat errorSensitivity=0.5f;// 取值范围 [0, 1]HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_ERROR_SENSITIVITY,&errorSensitivity);

XEG_ADAPTIVE_VRS_ERROR_SENSITIVITY的值是0x4U。这个值越大,算法越"激进"地降低着色率——性能会更好,但画质会下降。默认值是 0.5。如果你的游戏对画质要求高,可以调低一点;如果帧率优先,可以调高一点。

设置是否翻转图像(可选)

有些渲染管线的坐标系是上下翻转的,你可以通过XEG_ADAPTIVE_VRS_FLIP来控制:

GLboolean flip=GL_FALSE;// true 表示翻转,false 表示不翻转HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_FLIP,&flip);

XEG_ADAPTIVE_VRS_FLIP的值是0x5U。默认是false,不翻转。如果你发现着色率图的效果不对,可以试试翻转一下。

第二步:计算着色率图

参数设好之后,调用HMS_XEG_DispatchAdaptiveVRS来让算法生成着色率图像:

HMS_XEG_DispatchAdaptiveVRS(reprojectionMatrix,// 重投影矩阵inputColorImage,// 上一帧的颜色附件纹理IDinputDepthImage,// 当前帧的深度附件纹理IDshadingRateImage// 输出的着色率纹理ID(需要你提前创建));

这里面有四个参数,每个都很重要:

reprojectionMatrix:这是一个 4x4 的列主序矩阵,用于描述上一帧和当前帧之间的空间变换关系。计算公式是:(上一帧投影矩阵 * 上一帧观察矩阵)* 逆(当前帧投影矩阵 * 当前帧观察矩阵)。这个矩阵是可选的,但如果你能提供的话,画质会更好。如果你传 NULL,算法也能工作,只是效果可能差一点。

inputColorImage:上一帧渲染管线最终输出的颜色纹理 ID。纹理类型必须是GL_TEXTURE_2D,mipLevels 必须是 1。

inputDepthImage:当前帧渲染管线最终输出的深度纹理 ID。同样要求是GL_TEXTURE_2D,mipLevels 为 1。

shadingRateImage:这是你要提前创建好的一张纹理,用来接收算法输出的着色率信息。它的尺寸应该和着色率的粒度匹配。

第三步:应用着色率图

着色率图生成之后,你需要调用HMS_XEG_ApplyAdaptiveVRS把它应用到当前的渲染目标上:

HMS_XEG_ApplyAdaptiveVRS(shadingRateImage);

调用之后,后续的绘制操作就会按照着色率图里的信息来决定每个区域的着色精度。如果你想关闭自适应 VRS,传入 0 就行:

HMS_XEG_ApplyAdaptiveVRS(0);// 关闭自适应VRS

完整的使用流程

把上面的步骤串起来,每帧渲染时的自适应 VRS 调用时序如下:

每帧渲染开始

HMS_XEG_DispatchAdaptiveVRS

传入重投影矩阵

传入上一帧颜色纹理

传入当前帧深度纹理

输出着色率纹理

HMS_XEG_ApplyAdaptiveVRS

正常绘制场景

GPU 按着色率图决定每区域精度

帧渲染完成

把上面的步骤串起来,一个典型的使用流程是这样的:

// 1. 检查设备支持constGLubyte*extensions=HMS_XEG_GetString(XEG_EXTENSIONS);if(strstr((constchar*)extensions,"XEG_adaptive_vrs")==NULL){return;// 不支持,走普通渲染}// 2. 设置参数GLsizei inputSize[2]={1920,1080};HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_INPUT_SIZE,inputSize);GLfloat errorSensitivity=0.5f;HMS_XEG_AdaptiveVRSParameter(XEG_ADAPTIVE_VRS_ERROR_SENSITIVITY,&errorSensitivity);// 3. 计算着色率图(每一帧都要调用)HMS_XEG_DispatchAdaptiveVRS(reprojectionMatrix,lastFrameColorTexture,currentFrameDepthTexture,shadingRateTexture);// 4. 应用着色率图HMS_XEG_ApplyAdaptiveVRS(shadingRateTexture);// 5. 继续正常的渲染流程...// 此时绘制的内容会按照着色率图来着色

几个要注意的点

  1. 每一帧都要重新计算:着色率图是根据上一帧和当前帧的信息生成的,所以每帧都要调用HMS_XEG_DispatchAdaptiveVRS

  2. 纹理格式要求:所有传入的纹理都必须是GL_TEXTURE_2D类型,mipLevels 为 1。不满足这个条件的话,结果是未定义的。

  3. 重投影矩阵的计算:如果你的相机在移动,最好提供重投影矩阵。这个矩阵的计算公式是(prevProjection * prevView) * inverse(currProjection * currView)。如果你的相机是固定的,传 NULL 也可以。

  4. 性能和画质的平衡ERROR_SENSITIVITY参数是你调节性能和画质平衡的主要手段。建议从 0.5 开始,根据实际效果微调。

自适应 VRS 是一个很实用的性能优化手段,特别适合那些场景复杂、GPU 负担重的游戏。用好了,帧率提升个 10%-20% 是很常见的。

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

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

立即咨询