Sep 22

iOS的Tile Based Rendering

Lrdcq , 2021/09/22 13:35 , 程序 , 閱讀(1701) , Via 本站原創
我们知道在移动端设备上,GPU环节大多都会采用Tile Based Rendering方案。更具体来说,所有的iOS设备的GPU都采用的Tile-Based Deferred Rendering(TBDR)架构。正好翻阅到一篇WWDC2014的Advanced Graphics And Animation Performance文章对iOS中的TBDR进行了详解,因此针对iOS中Tile Based Rendering的基本情况与可能存在并可以进行的适配方案进行讨论。

Tile Based Rendering如何运作的

首先,用浅显的话重新描述一次Tile Based Rendering,即分块的GPU渲染流程,不是以整个画面frame而是以块为单位单次小范围渲染,最后组成整个画面。

为什么要这么做?继续用浅显易懂的话来说,要明白移动端soc上,虽然处理器比如苹果的A13A15上,确实是有明确的几核CPU几核GPU和什么什么专用处理器,但是和PC平台不同的是,GPU是不会配备专用显存的,换句话来说,实际GPU使用的显存储存空间是和内存共享的。当然现在soc访问内存的带宽也是非常快的,iPhone13这代应该还是配备的LDDR4x,带宽在50G上下,但是按照正常的GPU渲染流程其中的功耗也是相当惊人的,因此需要找一个更近,功耗更低的储存区域——于是找到了片上缓存SRAM。访问SRAM功耗低速度可以接受,就是一点容量确实太小了,远远无法放下一整个framebuffer。

因此有了Tile Based Rendering这个架构,GPU在顶点着色阶段,会把整个图形切割成小块,然后在实际片元着色即实际执行光栅化渲染到buffer过程中,以单块为单位在SRAM中逐块渲染,最后组合到屏幕上。

在苹果的ppt中有表述这个过程,如下图展示的一个icon的四边形顶点结构(蓝色),在经过红色网格的切分后,实际执行光栅化前的顶点结构会变成图2的形态:
點擊在新視窗中瀏覽此圖片
【tiler前】

點擊在新視窗中瀏覽此圖片
【tiler后】

按照网格的块的范围切分为了20个矩形,如果整个画面只需要渲染这个图形的话,就有20个块需要渲染。虽然明显自动网格化后顶点变复杂了,但是考虑到后续渲染得到的功耗上的收益,这一点性能损失就不叫损失了。

实际整个流程如下图:
點擊在新視窗中瀏覽此圖片

我们知道UIKit中界面渲染实际上是Core Animation驱动的。

1. Core Animation将界面结构处理完成后,将顶点信息与着色信息通过openGl,现在应该是Metal,传递到GPU,这一部分和PC的GPU流程没有什么区别。(本身TBR的区别主要体现在图形API实现与硬件流程上)

2. 这里加载数据的Command Buffer其实还是DRAM,利用DRAM的数据,优先执行用户的顶点着色器。

3. 随后执行块切分的Tiling流程,按上文描述将用户顶点切分到网格。这个过程输出的是切分后的顶点,还有实际的网格信息,回写到DRAM中。

4. 根据网格信息,然后分别取每一块的数据,执行实际的片段着色即render操作,这里的GPU内部处理流程使用的读写buffer(Parameter Buffer)即放到SRAM(On-Chip Buffer)中了。这一段的内容就是常见的Early Depth Test,用户片段shader执行,Alpha Blend等,完成单块的渲染,最后将渲染结果拷贝到内存中的Frame Buffer拼装起来即可。其中完成Depth Test后可以进行剔除优化等行为,这就是实际TBDR中的Deferred行为,具体可以参看https://zhuanlan.zhihu.com/p/347001411对HSR的描述。

GUI开发中TBDR特性的利用

给予上面对TBDR的认知与相对于PCGPU的IMR执行方式的区别,我们对移动端图形渲染与形如iOS操作系统与UIKit中的行为能有新的理解。

首先分块行为显然是有运算成本的。不过首先要确定的是,分块的逻辑的影响因素:a. 块大小:块的大小应该是buffer大小即SRAM大小,可以设定SRAM越大块就越大,切分成本越低(所以也有说未来如果SRAM足够大了,也不需要TBDR了)。b. 图形复杂的,如果一个块内部顶点图形复杂度极高,本质上切块是切内三角形,这种情况下切分成本也是极高的,考虑到细分精度较高的图形shape进行切分的情况。

由于块大小软件层完全是无感的(虽然可以针对设备推测硬编码),我们从图形下手:

a. 避免复杂度极高的图形,也就是所谓的高模。根据结论高模在移动设备的上会有相对差更多的性能损耗。而对于GUI开发来说,Core Animation传递给GPU的绝大部分元素都是矩形,但是Core Animation本身会有一定切分行为,如圆角离屏渲染优化的情况下,图形有可能实际切分为这样的图形:
點擊在新視窗中瀏覽此圖片
Core Animation中的多边形整体可以分为2d(包括3d仿射变换)图形与3d图形。显然所有的2d图形就算经过拆分也是尽量保证了横平竖直如上面离屏渲染拆分的那样,而3d图形就随缘了。同时,经过样子Core Animation不会构造出其他多边形,包括mask shape等技术均是通过Core Graphics绘制出实际位图后再参与计算的。shadow等参与拓展边缘的技术也是直接进了的相关layer的位图扩大。

b. 说到位图扩大这一点,除了图形复杂度,当然越大的顶点面被切分的快数越多,所以另一个关键点当然是尽量缩小图形及layer面积。这包含了:避免空白view被离屏渲染与透明位图,使用Core Image时输出图形裁剪空白区域与边缘(做模糊等滤镜操作时会出现)。但是相反的一点是view如果是可软件切分时,能不做切分反而尽量不做切分,因为软件未对其的切分反而会产生更多的顶点,因此还是以合并为主。

c. 这里还涉及到一点是:尽量避免半透明layer/图形。半透明layer在深度优化时无法剔除,并且还在后期涉及到alpha blending成本,所以避免半透明layer(包括离屏渲染后形成的半透明layer比如圆角,投影)总是好的。而针对TBDR,由于切片后很容易出现实际上是完全不透明的区域但是夹带在透明区域上,因此还有一个可见的优化方式是物理切分透明layer与不透明layer。比如如上图把圆角的四个角切出来,layer是透明的,其他部分虽然复杂但是layer是不透明的,这其实就是这个思路的优化。同理把矩形阴影的拓展部分切出来,非拓展部分即原始数据放在上面,也能起到优化效果。

d. 重绘区优化:在TBR架构下,重绘区优化收益更大。原本重绘区优化着重在数据带宽上,但是对于TBR来说,由于块与块之间其实是串行分块渲染的,因此可以做到飞重绘区剔除渲染这样的事情,重绘区优化可以带来直接的渲染性能提升。

以上。可能对于GUI的情况非极限性能下渲染性能影响不会那么大,但是对于长列表,带循环动效等GPU压力大的场景,(实测发现部分大型APP如淘宝京东,类似场景GPU压力比玩游戏还大)相关认知与优化偏向还是有很高的必要性。
关键词:tbr , tbdr , 图形学
logo