【笔记】【百人计划】图形3.7 移动端TB(D)R架构基础

一、当前移动端GPU概况

1.1 移动端和桌面端功耗对比

对于移动端我们通常用soc芯片名称来代指CPU

移动端GPU生产厂商主要是高通adreno,Mali和PowerVR

image-20220822235329719

1.2 移动端和桌面端带宽对比

image-20220822235406315

二、名词解释

  • System on Chip(Soc)
    • Soc是把CPU、GPU、内存、通信基带、GPS模块等等整合在一起的芯片的称呼。常见的有A系Soc(苹果),骁龙Soc(高通),麒麟Soc(华为),联发科Soc,猎户座Soc(三星),2020年苹果推出M系Soc,暂用于Mac,这说明手机、笔记本、PC的通用芯片已经出现了。
  • System Memory
    • Soc中GPU和CPU共用一块片内LPDDR物理内存,就是常说的手机内存,也叫System Memory,大概几个G。
    • 此外CPU和GPU还分别有自己的高速SRAM的Cache,也叫On-chip Memory,一般几百k-几M。不同距离的内存访问存在不同时间消耗,距离越近消耗越低,读取System Memory的时间消耗大概是On-chip Memory的几倍到几十倍
    • (soc上gpu和cpu共享一个(虚拟)内存地址空间)
  • On-Chip Memory
    • 在TB(D)R架构下会存储Tile的颜色、深度和模板缓冲,读写修改都非常快。
  • Stall停滞
    • 当一个GPU核心的两次计算结果之间有依赖关系而必须串行时,等待的过程便是Stall。
  • FillRate
    • 像素填充率 = ROP运行的时钟频率 * ROP的个数 * 每个时钟ROP可以处理的像素个数
  • TB(D)R
    • Tile-Based (Deferred) Rendering
    • 是目前主流的移动GPU渲染架构,对应一般PC上的GPU渲染架构则是IMR(Immediate Mode Rendering)
    • 指屏幕被分块(16*16或32*32像素)渲染
    • TBR:VS - Defer - Rasterize - PS
    • TBDR:VS - Defer - Rasterize - Defer - PS
    • Defer字面是延迟,但从渲染数据的角度来看,Defer就是“阻塞+批处理”GPU的“一帧”的多个数据,然后一起处理

三、立即渲染IMR

1
2
3
4
5
6
7
for draw in renderPass:
for primitive in draw:
for vertex in primitive:
execute_vertex_shader(vertex)
if primitive not culled:
for fragment in primitive:
execute_fragment_shader(fragment)

image-20220823000924957

image-20220823001016993

四、基于块元的渲染TB(D)R

TB(D)R宏观上分为2阶段

  1. 第一阶段执行所有与几何相关的处理,并生成Primitive List,并且确定每个tile上面有哪些primitive
  2. 第二阶段将逐块执行光栅化及其后续处理,并在完成后将Frame Buffer从Tile Buffer写回到System Memory中。
1
2
3
4
5
6
7
8
9
10
11
12
# Pass one
for draw in renderPass:
for primitive in draw:
for vertex in primitive:
execute_vertex_shader(vertex)
if primitive not culled:
append_tile_list(primitive)
# Pass two
for tile in renderPass:
for primitive in tile:
for fragment in primitive:
execute_fragment_shader(fragment)

image-20220823001450220

image-20220823001533374

五、TB(D)R的硬件渲染顺序

image-20220823001818885

总结

TBR的核心目的是降低带宽,减少功耗,但渲染帧率上并不比IMR块

  • 优点
    • TBR给消除Overdraw提供了机会,PowerVR用了HSR技术,Mali用了Forward Pixel Killing技术,目标一样,就是要最大限度减少被遮挡Pixel的texturing和shading。
    • TBR主要是cached friendly,在cache里读写的速度要比全局内存的速度快得多,以降低render rate的代价,降低带宽,省电
  • 缺点
    • Binning过程是在vertex阶段之后,将输出的几何数据写入到DDR,然后才被fs读取。几何数据过多的管线,容易在此处有性能瓶颈。
    • 如果某些三角形叠加在数个tile上,需要绘制数次。意味着总渲染时间将高于即时渲染模式。

六、Binning过程

Binning过程(类似四叉树)/第一个Defer

image-20220823002346662

确定哪些块元渲染哪些图元

七、不同GPU的Early-Depth-Test

第二个Defer

  • Android

    • Qualcomm Adreno采用外置模块LRZ。在正常渲染管线前,多执行一次vs生成低精度depth texture,提前剔除不可见的triangles。直接用硬件做occlusion culling,功能类似软光栅遮挡剔除/pre-Z
    • Arm Mali的FPK(Forward Pixel Killing)
      • 发生在Early-Z之后
      • image-20220823002835382
  • IOS

    • PowerVR的HSR

    • TBDR的HSR实现

      • HSR=Hidden Surface Removal
      • 对每个被投影光束交接的对象进行排序处理(使用分块减少数据集大小)
      • 只有最近的不透明和最近的透明对象需要被渲染
      • 余下的片元被剔除
    • image-20220823003102289

八、优化建议

  • 不使用FrameBuffer的时候clear或者discard
    • 主要是清空积存在tile buffer上的中间数据,所以在unity里面对render texture的使用也特别说明了一下,当不再使用这个rt之前,调用一次Discard。在Opengl ES上善用glClear,glInvalidateFrameBuffer避免不必要的Resolve(Resolve就是tile buffer刷新到system memory)行为
  • 不要在一帧里面频繁切换FrameBuffer的绑定
    • 本质上就是减少tile buffer和system memory之间的stall操作
  • 对于移动平台,建议使用alpha blend而非alpha test
    • 在实际使用中,你应该分析并比较alpha test和alpha blend的表现,因为这取决于具体内容,通常在移动平台上应避免使用alpha混合来实现透明。需要进行alpha blend时,尝试缩小混合区域的覆盖范围。
  • 手机上必须要做Alpha Test,先做一遍preZ
  • 图片尽量压缩,例如:ASTC,ETC2
  • 图片尽量走mipmap
  • 尽量使用从Vertex shader传来的Varying变量UV值采样贴图(连续的),不要在FragmentShader里动态计算贴图的UV值(非连续的),否则CacheMiss
  • 在延迟渲染尽量利用Tile Buffer
  • 如果你在unity里面调整ProjectSetting/Quality/Rendering/Texture Quality不同的设置,或者不同分辨率下,帧率有很多变化,那么多半是带宽出问题。
  • MSAA在TBDR下反而是非常快速的。
  • 少在fs中使用discard,调用gl_FragDepth从而打断Early-DT(HLSL中为Clip,GLSL中为discard)
  • 在shader里面浮点数精度,有目的区分使用float,half;
    • 带宽用量减少
    • GPU中使用的周期数减少,因为着色器编译器可以优化你的代码以提高并行化程度。
    • 要求的统一变量寄存器数量减少,这反过来又降低了寄存器数量溢出风险
  • 在移动端TB(D)R架构中,顶点处理部分容易成为瓶颈,避免使用曲面细分shader,置换贴图等负操作,提倡使用模型lod,本质上减少FrameData的压力,Unity中尽早在应用阶段借助umbra遮挡剔除。

作业

结合今天的课程,将最近做的demo继续安卓平台打包对比使用课上的优化点前后的性能变化。

这是第一次接触安卓平台的打包与性能分析。。关于性能分析使用了Unity的UPR工具。由于没有什么比较完整的demo,之前所有作业都是塞在一个项目里做的,就直接使用这个场景了,虽然感觉也很难触碰到性能瓶颈什么的。而且能够针对上面优化建议处理的点也不太多。于是选择了最直接的图片纹理压缩的部分(正好下一章节就会讲纹理压缩),应该也算非常适合了。

ASTC和ETC2两种压缩格式都非常接近

image-20220824014740272

而当我手动地取消所有纹理的压缩,改为8位浮点精度储存后,发现对性能的影响比想象中大得多。。。

image-20220824014834325

首先是apk文件的大小就增大了一些。其次是最明显的纹理资源峰值这一项,UPR还贴心地提供了说明和优化建议。而且,这里Mipmap甚至已经关掉了。(其实这里做法是相反的,应该关闭压缩开启mip,这样这两个功能在纹理和渲染效率上的作用才是协同的)

image-20220824015319329

那么在手机内存占用上,也发生了相应的变化

image-20220824020406052

image-20220824020414939

  • ReservedTotal峰值

    • image-20220824020439183
  • ReservedGFX峰值

    • image-20220824020513219

其次就是帧率也发生了下降。这当然也是由于纹理资源数据变大,计算的速度也就下降了。

image-20220824015213541

性能分析工具本身还有很多需要去研究的地方,当然这也需要项目内容的支撑。。。鉴于现在也没有什么合适的内容,这里也只能到此为止了,算是一次小小的尝试。当打包出来的项目在手机上成功渲染出画面的时候,还是非常激动的。。。

(此外,曲面细分与几何着色器生成的草地没能在手机上绘制出来,想必也是手机平台不支持这两个着色器的缘故了。)

参考资料

[1] https://www.bilibili.com/video/BV1Bb4y167zU

【技术美术百人计划】图形 3.7 移动端TB(D)R架构基础

[2] https://blog.imaginationtech.com/a-look-at-the-powervr-graphics-architecture-tile-based-rendering/

[3] https://upr.unity.cn/instructions/desktop