技术美术百人计划 | 《3.7 移动端GPU的TB(D)R架构》笔记

更多内容可见 3.4渲染路径补充-GPU架构

1. Mobile与PC的GPU对比

1.1. 移动端CPU与GPU型号

中国在TOP300中,从手机CPU(SoC)厂商来看,高通占比49.2%,相比于其他厂商有较大的优势,其次是华为28.6%,联发科21%,三星1.1%,其余CPU厂商并未进入TOP300。

GPU上,高通的Adreno与Mali的GPU市场分别占比49.2%与48.2%,而PowerVR-GPU在安卓机器上使用较少,占比仅有2.6%。虽然移动端gpu型号很多,但市场上的厂家主要就三家:Adrno、Mali、PowerVR。

1.2. 功耗对比

桌面端

  • 主流性能平台,功耗一般300w
  • 游戏主机,功耗一般150-200w

移动端

  • 入门和旗舰笔记本,功耗一般100w
  • 主流笔记本为50-60w,超极本为15-25w
  • 旗舰平板为8-15w
  • 旗舰手机为5-8w
  • 主流手机为3-5w

总结:如果用最高功耗的桌面和最低功耗的移动端对比,差距有100倍左右的差距

1.3. 带宽对比

绿线为桌面端的带宽演变,将近100起步,最多可到400左右;黑线是移动端,相比之下带宽很小,涨幅也不大(例如骁龙888的移动带宽是32)。因此带宽方面,两者差距也有起码10倍。

2. 名词解释

  • System on Chip(Soc)-整合在一起的手机芯片
  • Soc是把CPU、GPU、内存、通信基带、GPS模块等等整合在一起的芯片的称呼。常见有A系Soc(苹果),骁龙Soc(高通),麒麟Soc(华为),联发科Soc,猎户座Soc(三星)。去年苹果推出的M系Soc,暂用于Mac,但这说明手机、笔记本和PC的通用芯片已经出现了

  • 物理内存(System Memory)-Soc中的手机内存
  • Soc中GPU和CPU共用一块片内LPDDR物理内存,就是我们常说的手机内存,也叫System Memory,大概几个G。此外CPU和GPU还分别有自己的高速SRAM的Cache缓存,也叫On-chip Memory,一般几百K~几M。
  • 补充:手机上,cpu和gpu共享一个内存地址空间。桌面端两者的内存地址是分开的。

  • On-Chip Memory -CPU和GPU的Cache缓存
  • 除了系统内存外,cpu和gpu还分别有自己的高速SRAM的Cache缓存,叫作On-Chip Memory,一般为几百K~几百M。不同距离的内存访问存在不同的时间消耗,距离越近消耗越低,读取System Memory的时间消耗大概是On-chip Memory的几倍到几十倍。

  • On-Chip Buffer -缓冲区
  • 在TB(D)R架构下会存储Tile的颜色、深度和模板缓冲,读写修改都非常快。如果Load/Store指令中缓冲需要被Preserve,将会被写入一份到System Memory中。

  • Stall
  • 当一个GPU核心的两次计算之间有依赖关系而必须串行时,等待的过程就是Stall

  • FillRate
  • 即像素填充率,计算方式为像素填充率 = ROP运行的时钟频率 × ROP的个数 × 每个时钟的ROP可以处理的像素个数(ROP: Raster Operator Units 光栅处理单元)

  • TB(D)R(Tile-Based (Deferred) Rendering)
  • 是目前主流的移动GPU渲染架构,对应一般PC上的GPU渲染架构则是IMR(Immediate Mode Rendering )。简单来说就是屏幕被分块渲染。其中Deferred可以看作“延迟”,也就是阻塞+批处理GPU一帧的多个数据,然后一起处理。

  • 区分:
  • TBR: VS顶点着色器 - Defer - RS光栅化 - PS片元/像素着色器
  • TBDR:VS - Defer - RS - Defer - PS
  • 通过这第二个Defer,PowerVR的渲染架构真正最大程度上实现了“延后(Defer)PS的执行”,以避免执行不必要的PS计算与相关资源调用的带宽开销,以达到最少的性能消耗和最高的渲染效率。

  • 注意
    • 有些文章会将TBR叫作TBDR,所以看资料的时候,要搞清楚它说的"D"是指第一个Defer还是第二个。
    • 现在的手机基本都是TBDR架构了,但是受到提出TBDR的PowerVR公司的产权保护限制,大家都不敢说是TBDR架构。

3. 立即渲染(IMR)

3.1. 伪代码

  • 每个renderpass中有各种DrawCall
  • 每个DrawCall里有很多图元
  • 我们首先要对每个图元中的顶vertex shader进行处理,如果这个图元没被剔除,就对它里面的fragment进行Fragment shader的处理

3.2. IMR数据流

  • 先经过vertex shader的处理
  • 再进过一个类似管道(先进先出FIFO)的顺序,最终提交给Fragment Shader
  • Fragment Shader最终将结果刷到FrameBuffer里

详细示意图:

PowerVR 图形架构概览:基于图块的渲染 - Imagination (imaginationtech.com)

  • 下面虚框:系统内存区域
  • 用户数据经过:顶点处理 → 剔除,投影 → 光栅化 → Early Visibility Test → Alpha Test → Late Visibility Test → Alpha Blend 最终将结果刷到FrameBuffer里
  • 整个过程直接和系统内存进行交互

4. 基于块元的渲染(TBDR)

4.1. 伪代码

  • 第一阶段(Pass one)-分图元
    • 对每个renderpass里的DrawCall,每个DrawCall里的图元,先进行Vertex shader处理,并生成Primitive List(图元列表)
    • 关键在于:分清楚每个块元(Tile)上有哪些图元(Primitve)
  • 第二阶段(Pass two)-执行光栅化及后续处理
    • 对renderpass的每个块元tile,块元中的每个图元primitive,图元中每个片元fragment,执行Fragment Shade处理
    • 并在完成后,将FrameBuffe从Tile Buffer写回到System Memory中
    • 相比传统的IMR架构,不是直接写回System Memory中,而是写到片上内存(OnChip Memory)中

片元不是像素,片元包含了比像素更多的信息,比如深度值、法线、纹理坐标等等信息,片元需要通过一定的测试(比如深度测试),才能最终成为我们所看到图像的像素。

片元着色器Fragment Shader就是像素着色器Pixel Shader。

4.2. TBR数据流

数据通过Vertex shader的处理 → 经过Tiler(图元分好的块) → 刷到一块On-chip Memory(每个块元的内存)上


详细示意图:

  • 【中间虚线框】On-Chip Buffer(Memory),Cache缓存
  • 【下边虚线框】System Memory ,系统内存

与IMR的区别

  • TBDR架构中,多了一步Tiling的过程,这一步是:将顶点处理经过剔除、投影的几何数据刷到系统内存(System Memory)
  • 经过光栅化(Raster)等流水线fragment shader、ROP等,最终把结果刷在片内存(On Chip Memory)
  • 最终片内存上的会刷到FrameBuffer上(FrameBuffer在System Memory上)

动态示意图,对屏幕上的每个块分别渲染:

实际中GPU硬件中乱序执行

4.3. 总结

核心目的

  • 为了降低带宽,减少功耗,但渲染帧率上并不比IMR快

优点

  • 给消除OverDraw提供了机会:PowerVR有HSR技术,Mali有Forward Pixel Killing技术,都有为了最大限度减少被遮挡的pixel的texturing和shading
  • 缓存友好(Cache friendly),在cache的读写速度要比全局内存中快得多(以降低帧率为代价,降低带宽、功耗)

缺点

  • 这个操作需要在vertex阶段之后,将输出的几何数据写入到DDR,然后才被fragment shader读取。这之间也就是tile写入DDR的开销和fragment shader渲染读取DDR开销的平衡。另外还有一些操作(比如曲面细分tessellation)也不适用于TBR;
  • 如果某些三角形叠加在数个图块(Overdraw),则需要绘制数次。这意味着总渲染时间将高于即时渲染模式。

4.4. TBDR的两个Defer过程

TBDR:VS - Defer(Binning) - RS - Defer - PS

4.4.1. 第一个Defer:Binning(像素合并)

目的:确定哪些图元属于哪些块元渲染

过程

第二幅图里的红色三角形,只用一个块元就能渲染,所以它只会被分配到一个块元中

第四幅图里的棕色三角形,需要多个块元才能渲染,所以它需要分配到9个块元中一起渲染

举例:红线代表tile的范围,可以显示每个块元的性能参数。

binning过程的耗时占比参考,如果项目中binning过程相比其他耗时长的话,就要考虑一下是不是几何数据过多了。

4.4.2. 第二个Defer:不同GPU 的 Early-Depth-Test

4.4.2.1. 安卓

1. Qualcomm Adreno

采用外置模块LRZ。在正常渲染管线前,先多执行一次VS顶点着色器,生成低精度深度纹理depth texture,以提前剔除不可见的triangles(或像素块?实现细节不知)。说白了,直接用硬件做遮挡剔除occlusion culling,功能类似软光栅遮挡剔除。因为做LRZ时执行VS只需用到顶点位置信息,所以单独抽出position stream,能带来带宽bandwidth和缓存cache的优化。

2. Arm Mali

采用Forward Pixel Kill技术-Mali-T880

发生在Early-z之后

数据模型:先进先出的队列

简单概括一下:队列中有4个Quad(可以理解为2×2像素的平面),每个Quad有屏幕上位置pos的数据和深度Z数据,深度Z越大代表离摄像机越远。根据屏幕上相同位置pos的不同深度z,对不透明的像素进行替换,替换掉深度大的像素,这个过程叫作killed。

4.4.2.2. IOS

PowerVR以及后续自研GPU,采用内置模块HSR。修改原渲染管线架构,增强rasterizer硬件模块为HSR。也就是虚拟出一个射线,当它遇到第一个不透明的物体时就会停下来,这样就会打断后面三角形的后续ps处理。

一张场景图片:

在不经过HSR优化的话,会产生错误的效果。

而经过了HSR优化,效果如下。其中黑色区域是有非透明物体遮挡的部分,看不见后面的物体,而灰色部分是透明物体,可以看见后面的物体。

5. IMR 和 TBR对比

TBR、IMR简化版示意图

图(a)TBR架构

  • 几何处理数据形成了FrameData(放在System Memory上)
  • 这些Frame Data经过片段处理,结果放在了Tile Buffer上(片的内存上)
  • 最后的结果会刷到FrameBuffer中(System Memory上)

图(b)IMR架构

  • 对比TBR有以下两种区别
    • 几何处理数据直接到片段处理,没有中间数据(Frame Data)
    • 直接刷到System Memory上了,没有经过片内存(On-Chip Memory)

6. 优化建议

记得在不使用FrameBuffer的时候clear或discard

    • 这样做主要是为了清空积存在tile buffer上的中间数据(前边提到的Frame Data)
    • 对Unity里的rt(render texture)的使用也特别说明一下:当我们不再使用这个rt的时候,尽量调用一次Discard,RenderTexture.DiscardContents()
    • 在OpenGl ES上,要善用glclearglInvalidateFrameBuffer,避免不必要的Resolve(tile buffer刷新到system memory的行为),GL.Clear()

不要在一帧里频繁的切换FrameBuffer的绑定

    • 本质:减少tile buffer和system memory之间的stall(同步)操作

对于移动平台,建议使用Alpha Blending,而非Alpha Test。

    • 是一个经验性的结论,在实际使用的过程中应该使用比较两者的表现。通常情况下,移动端应该避免使用Alpha混合来实现透明,如果确实要用,尝试缩小混合区域的覆盖范围

手机上必须用Alpha Test时,先做一遍Depth Prepass(参考Alpha Test 的双pass优化思路)

图片尽量压缩

    • 例如ASTC 、ETC2

图片尽量走mipmap

尽量使用从Vertex shader传来的Varying变量uv值采样贴图(连续的),不要在Fragment shader里动态计算贴图的uv值(非连续的),否则Cache Miss

在延迟渲染中,尽量利用Tile Buffer(参考传统延迟渲染和TBDR)

如果在Unity中调整ProjectSetting-Quality-Rendering-Texture Quality的不同设置,或者不同分辨率下,帧率有很大的变化,大概率是带宽出问题了

MASS在TBDR下反而是非常快速的

    • MSAA是硬件上的,发生在片上的。相比FSAA,MSAA在手机上是非常快的

少在Fragment shader中使用discard函数,调用gl_FragDepth从而打断Early-DT的过程

    • (hlsl中为Clip,glsl中为discard)

在shader使用浮点数精度值时,有目的的区分使用float,half

    • 优点
      • 带宽减少
      • GPU中用的周期数减少,因为着色器编译器可以优化你的代码来提高并行化程度
      • 要求的统一变量寄存器的数量减少,这样反而又降低了寄存器数量溢出风险。
      • 具体参考:熊大的优化建议、shader数学计算优化技巧

在移动端的TBDR架构中,顶点处理部分(Binning过程)容易成为瓶颈

    • 避免使用曲面细分shader,置换贴图等负操作
    • 提倡使用模型LOD,(本质上减少Frame Data的压力)
    • Unity中尽早的在应用阶段做umbra(Unity内置)遮挡剔除、gpu的occlusion cull

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值