Core Animation是如何在CPU和GPU之间分配工作的

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014799068/article/details/81098505

Core Animation是如何在CPU(中央处理器)软件层面和GPU(图形处理器)硬件层面分配工作的:

  • 动画和屏幕上组合的图层实际上被一个单独的进程管理,而不是你的应用程序,iOS5之前的版本是SpringBoard进程,iOS6之后的版本叫做BackBoard.
    当运行一段动画时候,这个过程会被四个分离的阶段被打破: 1
    布局:这是准备你的视图/图层的图层关系,以及设置图层属性(位置,背景.边框等)的阶段. 2
    显示:这是图层的寄宿图片被绘制的阶段.绘制有可能涉及你的-drawRect:和-drawLayer:inContext:方法的调用路径.
    3 准备:这是Core Animation准备发送动画数据到渲染服务的阶段.这同时也是Core Animation
    将要执行一些别的事务例如解码动画过程中将要显示的图片的时间点. 4 提交:这是最后的阶段,Core
    Animation打包所有图层和动画属性,然后通过IPC(内部处理通信)发送到渲染服务进行显示.
    一旦打包的图层和动画到达渲染服务进程,他们会被反序列化来形成另一个叫做渲染树的图层树.渲染服务对动画的每一帧做出如下工作: 5
    对所有的图层属性计算中间值,设置OpenGL几何形状(纹理化的三角形)来执行渲染. 6 在屏幕上渲染可见的三角形
    一共六个阶段,前五个阶段在软件层面处理(通过CPU),最后一个阶段被GPU执行.你真正只能控制前两个阶段:布局和显示.CoreAnimation框架在内部处理剩下的事务,你也控制不了它.
    这并不是个问题,因为在布局和显示阶段,你可以决定哪些由CPU执行,哪些交 给GPU去做。那么改如何判断呢? GPU相关的操作
    GPU为一个具体的任务做了优化:它用来采集图片和形状(三角形),运行变换,应用纹理和混合然后把它们输送到屏幕上。现代iOS设备上可编程的GPU在这些操作的执行上又很大的灵活性,但是Core
    Animation并没有暴露出直接的接口。除非你想绕开Core
    Animation并编写你自己的OpenGL着色器,从根本上解决硬件加速的问题,那么剩下的所有都还是需要在CPU的软件层面上完成。
    大多数 CALayer 的属性都是用GPU来绘制。比如如果你设置图层背景或者边框的颜色,那么这些可以通过着色的三角板实时绘制出来。如果对一个 contents
    属性设置一张图片,然后裁剪它 - 它就会被纹理的三角形绘制出来,而不需要软件层面做任何绘制。
    但是有一些事情会降低(基于GPU)图层绘制,比如: 太多的几何结构 -
    这发生在需要太多的三角板来做变换,以应对处理器的栅格化的时候。现代iOS设备的图形芯片可以处理几百万个三角板,所以在Core
    Animation中几何结构并不是GPU的瓶颈所在。但由于图层在显示之前通过IPC发送到渲染服务器的时候(图层实际上是由很多小物体组成的特别重量级的对象),太多的图层就会引起CPU的瓶颈。这就限制了一次展示的图层个数.
    **重绘 - 主要由重叠的半透明图层引起。**GPU的填充比率(用颜色填充像素的比 率)是有限的,所以需要避免重绘(每一帧用相同的像素填充多次)的发生。 在现代iOS设备上,GPU都会应对重绘;即使是iPhone
    3GS都可以处理高达
    2.5的重绘比率,并任然保持60帧率的渲染(这意味着你可以绘制一个半的整屏的冗余信息,而不影响性能),并且新设备可以处理更多。 离屏绘制 - 这发生在当不能直接在屏幕上绘制,并且必须绘制到离屏图片的上下文中的时候。离屏绘制发生在基于CPU或者是GPU的渲染,或者是为离屏图片分配额外内存,以及切换绘制上下文,这些都会降低GPU性能。对于特定图层效果的使用,比如圆角,图层遮罩,阴影或者是图层光栅化都会强制Core
    Animation提前渲染图层的离屏绘制。但这不意味着你需要避免使用这些效果,只是要明白这会带来性能的负面影响。 过大的图片 -
    如果视图绘制超出GPU支持的2048x2048或者4096x4096尺寸的纹理,就必须要用CPU在图层每次显示之前对图片预处理,同样也会降低性能。 CPU相关的操作 大多数工作在Core Animation的CPU都发生在动画开始之前。这意味着它不会影 响到帧率,所以很好,但是他会延迟动画开始的时间,让你的界面看起来会比较迟钝。 布局计算 -
    如果你的视图层级过于复杂,当视图呈现或者修改的时候,计算图层帧率就会消耗一部分时间。特别是使用iOS6的自动布局机制尤为明显,它应该是比老版的自动调整逻辑加强了CPU的工作。
    视图懒加载 - iOS只会当视图控制器的视图显示到屏幕上时才会加载它。这对 内存使用和程序启动时间很有好处,但是当呈现到屏幕上之前,按下按钮导致的许多工作都会不能被及时响应。比如控制器从数据库中获取数据,或者视图
    从一个nib文件中加载,或者涉及IO的图片显示,都会比CPU正常操作慢得多。 Core Graphics绘制 -
    如果对视图实现了-drawRect:方法,或者 CALayerDelegate 的
    -drawlayer:inContext:方法,那么在绘制任何东西之前都会产生一个巨大的性能开销。为了支持对图层内容的任意绘制,Core Animation必须创建一个内存中等大小的寄宿图片。然后一旦绘制结束之后, 必须把图片数据通过IPC传到渲染服务器。在此基础上,Core
    Graphics绘制就会变得十分缓慢,所以在一个对性能十分挑剔的场景下这样做十分不好。 解压图片 -
    PNG或者JPEG压缩之后的图片文件会比同质量的位图小得多。但
    是在图片绘制到屏幕上之前,必须把它扩展成完整的未解压的尺寸(通常等同于图片宽 x 长 x
    4个字节)。为了节省内存,iOS通常直到真正绘制的时候才去解码图片。根据你加载图片的方式,第一次对图层内容赋值的时候(直接或者间接使用
    UIImageView )或者把它绘制到 Core Graphics中,都需要对它解压,这样的话,对于一个较大的图片,都会占用一定的时间。
    当图层被成功打包,发送到渲染服务器之后,CPU仍然要做如下工作:为了显示屏幕上的图层,Core
    Animation必须对渲染树种的每个可见图层通过OpenGL循环转换成纹理三角板。由于GPU并不知晓Core
    Animation图层的任何结构,所以必须要由CPU做这些事情。这里CPU涉及的工作和图层个数成正比,所以如果在你的层级关系中有太多的图层,就会导致CPU每一帧的渲染,即使这些事情不是你的应用程序可控的。
    IO相关操作 还有一项没涉及的就是IO相关工作。上下文中的IO(输入/输出)指的是例如闪存或者网络接口的硬件访问。一些动画可能需要从闪存(甚至是远程URL)来加载。一个典型的例子就是两个视图控制器之间的过渡效果,这就需要从一个nib文件或者是它的内容中懒加载,或者一个旋转的图片,可能在内存中尺寸太大,需要动态滚动来加载。
    IO比内存访问更慢,所以如果动画涉及到IO,就是一个大问题。总的来说,这就需要使用聪敏但尴尬的技术,也就是多线程,缓存和投机加载(提前加载当前不需要的资源,但是之后可能需要用到)。

猜你喜欢

转载自blog.csdn.net/u014799068/article/details/81098505
今日推荐