问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

移动端GPU 带宽功耗优化

创作时间:
作者:
@小白创作中心

移动端GPU 带宽功耗优化

引用
CSDN
1.
https://blog.csdn.net/chenweiyu11962/article/details/142006022

移动端GPU的性能优化是提升应用流畅度的关键。本文深入探讨了移动端GPU的内存结构、数据加载与存储机制,以及如何通过Fast Clear和Transaction Elimination等技术降低带宽消耗。对于从事移动端图形开发的技术人员,这些优化策略将帮助你更好地理解GPU的工作原理,从而实现更高效的资源管理。

移动端GPU 的内存结构

移动端GPU的内存结构主要包括以下几个部分:

  • on-Chip memory:包括L1、L2 cache,以及用于存储Tiles的高速存储区域。此外,还包括寄存器文件,为每个核心提供极高速的存储。

  • 共享内存(Shared Memory):用于同一计算单元内的线程组SM共享数据,访问速度比全局内存快。

  • 常量缓存(Constant Cache):专门用于缓存常量数据。

  • 纹理内存(Texture Memory):类似于常量缓存,也是具有缓存的全局内存,容量较大且一般仅可读。它们通过特定的方式进行访问,适用于纹理采样等操作。

移动端GPU流程

下图以ARM的Mali为例:


Load 与 Store

  • Load与 Store决定了每个Render Pass开始时如何处理Tile内存中的数据。

  • 从 SystemMemory 拷贝数据到 TileMemory 是 Load Action

  • 从 TileMemory 拷贝数据到 SystemMemory 是 Store Action

在移动端图形中GPU Load Actions(加载操作)决定了在渲染一个新的帧缓冲区FBO,如何处理FBO中已经存在的数据,这在优化性能和内存带宽方面非常重要。主要有三种GPU Load Actions:don‘t care、Load、Clear

在移动端图形中GPU Store Actions(存储操作)决定了在渲染完成一帧后如何处理FBO中已经存在的数据:主要有三种dont’care 、resolve、store

Apple 的Store Action 有三种, Store, DontCare,MultisampleResolve ,还有两种处理 MSAA 等的 Metal、vulkan 的storeAndMultisampleResolve, MultisampleResolve. 感兴趣可以直接参苹果的文档Metal Best Practices Guide: Load and Store Actions

想要优化pipline的性能,就一定要注意设置好每个RenderTarget的Load Action 和 Store Actions。比如,Depth和Stencil通常只有在Rasterize阶段才会使用,所以直接放到了On-chip上, 或者后处理执行后深度没有用Store Actions设置为Don‘t care这样就不用把结果写入system内存,省下了大量的带宽。

Fast Clear

Fast Clear 是 GPU 对帧缓冲区进行快速clear的一种硬件优化机制。当帧缓冲区被clear时,只需将每个像素初始化到一个特定的颜色值。如果直接操作整个帧缓冲区对整个缓冲区的逐步遍历,会非常耗时

Fast Clear 本质上是一些硬件预设的清除值,比如clear成黑色或者白色这种,比自己传一个clear value进去要快!现代的硬件都有 Fast Clear,不管是 PC 、Apple A系列、Adreno等都支持。

调用 clear 的时候根据硬件支持与驱动的设置会触发Fast Clear。比如在 amd 上Fast clear在设计上比不同clear快约100倍(压缩了省带宽所以快了100倍)

  • Fast clear 需要全图像clear。

  • Fast clear RT的 需要以下颜色RGBA(0,0,0,0),RGBA(0,0,0,1),RGBA(1,1,1,0) ,RGBA(1,1,1,1)

  • Depth RT Fast clear 需要将深度值设为1.f或者0.f。

  • 模板设置值为 0x00。

  • Depth target arrays 需要将全部slices都清除才能实现fast clear。

  • vulkan 与 D12有Discard或LOAD_OP_DONT_CARE 标记时(opengles 无),会跳过Clear。

Transaction Elimination 技术

这里特别澄清之前一个错误,ARM使用的Transaction Elimination 的技术与fast clear没有关系! transaction elimination是一种很有效的降低带宽的方法。在有些场景下,只有部分Tile中的内容会变化(例如摄像机不动,一个Tile中只有静态物体)。此时通过比较该Tile前一次和本次的渲染结果的 循环冗余校验(CRC值),可得到Tile是否变化的结论,如果不变,那么就没有必要执行Tile到System Memory的store写回操作了,有效地降低了带宽占用。并仅对其中已修改的特定部分执行部分更新,能显著减少每帧需要传输到外部内存的数据量。TE 可以被每个应用程序用于 GPU 支持的所有帧缓冲区格式,而不管帧缓冲区精度要求如何,并且非常有效,即使在第一人称射击 (FPS) 游戏和视频中也是如此。在大部分frame buffer在两个连续帧之间保持静态,TE 的帧缓冲带宽节省高达 99%。

OpenGL ES 的dont’t care 实现

在 opengl 中don’t care 对应的是glinvalidate,clear对应glclear,综上所述在 opengl 中glinvalidate与glclear不等价。所以glinvalidate应该会比clear会更好。glInvalidateFramebuffer 在 ogles2.0 是需要扩展,在 es3.0 是支持的详细参考 gl 文档:glInvalidateFramebuffer - OpenGL ES 3 Reference Pages

pipline开始时将显卡内存初始化使用glclear然后fast clear设置为特定颜色值,而无需system从内存中读回旧的帧缓冲区内容。在进行任何绘制调用之前,除非需要前一帧中渲染的内容上做处理,都可以使用以下的

glClear()
glClearBuffer()
glInvalidateFramebuffer()

你需要使用 glclear 、glClearBuffer、glInvalidateFramebuffer给 GPU 驱动标记opengl驱动会自己优化load过程。但是需要特别注意:每一帧中只有开始是免费(几乎无消耗)的。在pipline中的第一次绘制调用再后调用 glClear() 或 glClearBuffer*() 不是免费的,会增多指令并且这会导致每个着色器的片段都会被清除。同时这些是清除整个 framebuffer,而不仅仅是它的一个子区域!

对于store过程,最重要的是可以通过调用glInvalidateFramebuffer()作为pipline中的最后一个绘制调用,将内容标记为无效!

arm Mali参考

Minimizing-Start-of-Tile-Loads

Minimizing End of Tile Stores

gl 的例子 glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, &attachment);

Load/Store Unit的性能指标含义

首先,特别注意:

1、issues在 GPU 中是专业术语不能直接翻译成“问题”应该翻译成“发射”或者”调度“用于描述GPU在某个时钟周期内,某种操作(例如读、写、计算)被硬件单元执行或发射的次数

2、beats 指的是内存控制器中的一个传输单元。它代表一次数据传输中的“拍子”或“节奏”,可以理解为传输过程中一个周期内的数据量。因此,这里的 beats 应该翻译为“传输单位”

其次,如下表的指标主要是android GPU inspector的指标也是最全的,同样的 Arm 、adreno 等的指标都是下表的特定指标;

load/store参数的分析

Demo假设你在分析一个 GPU 程序,并且性能分析工具streamline提供了如下参数值:

Load/Store Read Beats from L2 Cache: 5000

Load/Store Read Beats from External Memory: 20000

Internal Load/Store Writeback/Other Write Beats: 15000

从这些数据你可以推断出:

  1. 程序高度依赖外部内存:因为从外部内存的读取节拍(20000)显著高于从 L2 缓存的读取节拍(5000),表明许多数据访问没有命中 L2 缓存。

  2. 写操作较频繁:内部加载/存储写回和其他写操作节拍总数(15000)表明有大量的数据写入,可能是计算结果或状态更新(这个时候使用dontcare会有较好的优化效果)。

假设你有以下参数值:

  • Load Read Bytes from L2 Cache:320000 / 每访问周期 64 字节

  • Load Read Bytes from External Memory:640000 / 每访问周期 128 字节

从这组数据中可以看到:

  • 从 L2 缓存读取总共 320,000 字节,平均每个访问周期读取 64 字节。

  • 从外部内存读取总共 640,000 字节,平均每个访问周期读取 128 字节。

尽管外部内存每个周期读取的字节数较大,但外部内存访问的延迟比 L2 缓存高,整体访问效率可能较低。因此,如果程序频繁地访问外部内存,而不是 L2 缓存,可能会导致性能下降。在这种情况下,优化策略可能包括:

  1. 提高 L2 缓存命中率,通过更有效的数据布局(内存对齐)和访问模式减少对外部内存的依赖。

  2. 使用共享内存(内存数组等)或寄存器来缓存频繁访问的数据,从而减少全局内存访问。

参考资料

1、移动端高性能图形开发 - 移动端GPU架构探究

2、移动GPU体系结构

3、OpenGL ES 3.0 帧缓冲区失效-

4、移动平台的GPU性能分析

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号