初识Android Project Butter: 黄油项目,使动画更加的平滑、流畅

来源:互联网 发布:淘宝手机店铺收藏代码 编辑:程序博客网 时间:2024/06/05 18:16
原文地址:http://www.androidpolice.com/2012/07/12/getting-to-know-android-4-1-part-3-project-butter-how-it-works-and-what-it-added/
VSYNC将帧绘制转入一个平滑的机制之中
       PC游戏玩家应该对‘VSync’这个术语十分的熟悉。VSync是一个图形选项框,这个图形选项框可以阻止一个视频游戏中的屏幕被撕裂(停顿)。
        为了正确的理解‘VSync’究竟是什么,我们将需要一种敏捷新手教学:视频是由一系列独特的,我们称之为‘帧’,图片组成。通常而言,一个光滑的动画每秒会有播放60个帧。一张帧(图片)又由许多像素点组成,当绘制一张帧的时候,像素点被一行一行的填充。
       显示屏(液晶显示器?主动矩阵有机发光二极体面板?无所谓)从显卡中获取每一帧,并逐行绘制此帧。理想情况下,显示屏在完成上一帧的绘制后,你期望显示屏能从显卡中获取新的一帧。然而实际情况却是,在显示屏的中央位置在加载一个新的帧图片时,一个撕裂(停顿)发生了,所以你将看到上一帧的一半内容以及新的帧的一半内容。
       VSync则是同步这种情况的存在。它将告诉显卡,在显卡导入新的一张帧图片之前,需要等待屏幕完成它的逐行绘制。
       Android总会使用VSync来阻止屏幕撕裂(停顿),但是android4.1却让这件事更进一步。VSync脉冲,被用来开始下一帧的所有处理。
       绝大部分Android显示屏一秒钟都将运行大约60张帧图片。事实上,为了有一个平滑的动画,你不得不以每秒60张帧图片的速率来处理动画——这意味着你将只有16毫秒的时间来处理每一张帧图片。如果你花费的时间多余了16毫秒,动画将有种结巴的感觉,而我们让动画像黄油一样平滑起来的这个目标,将烟消云散。
       16毫秒不是一个很长的时间,所以需要充分利用。在android4.0中,处理下一帧就有点懒洋洋的感觉,当系统开始着手去做这件事情时。而在android4.1中,上一帧一结束(VSync脉冲一开始),制造下一帧的总体流程就开始了。换而言之,它们将尽可能的使用少于16毫秒的时间来处理一张帧图片。
      没有VSync的情况下,进行的处理:

       此图就是在关掉VSync一切的情况下,绘制的生命周期。首先帧图片被CPU和GPU(显卡)处理,当这个过程结束后,在下一个VSync开始时,帧图片就会被传递给显示屏。所以在此图之中,第0张帧图片被展示了,在其被展示的16毫秒期间,CPU和GPU准备第1张帧图片。经过一段时间,计算完成,并在下一个VSync脉冲时,CPU和GPU将准备好的第一张帧图片交出。
       至此我们将第一张帧图片显示出来了,并且应该开始第二张帧图片的工作了。即使会因为某些原因使得系统被减缓了,然而对下一张帧图片的处理并不会马上开始,直到我们很好的进入了16毫秒的时间限制。对应到此张图而言,CPU和GPU开始处理第二张帧图片时,系统大概只有4毫秒(第一个VSync与第二个VSync之间大约最后一个四分之一的地方)的时间来计算第二张帧图片,所以针对第二张帧图片的处理并不能及时的完成。因为第二张帧图片还未计算完成,所以显示屏会强制要求再显示一次第一张帧图片(即上图标示有Jank字样的那一段16毫秒),android团队称之为闪避,意思是在这期间发生的动画不流畅,用户将有一种很结巴的感觉。
       拥有VSync的情况下,进行的处理:

            在android4.1中,有一个新的方式来处理这个流程。所以对下一张帧图片的处理都将在一个VSync脉冲发出时开始,所以现在你需要充分利用这段用来渲染的16毫秒时间。对帧图片的处理已经从“是的,我们可以随时启动它”向一种严格的排班、高度组织化的事件转变。在此图中,所有的处理过程都发生在16毫秒这个限制时间之中,所有的帧图片都会按时交付,作为结果你将有一个类似于黄油般平滑的体验。

三缓存,用来阻止像雪球一样越来越多的闪避

      VSync并不是唯一的一种用来帮助动画更加平滑化的方法;android也能够更加平滑的从一个缓慢中恢复。
        两缓存并行处理的模式:

         那么到底什么是一个“缓存(Buffer)”呢?简单而言,一个缓存就是一张帧图片在其中建立并存储其中的容器。上文我们通过数字来提及帧图片(例如第0张帧图片、第1张帧图片……),但是实际上,android使用了一个双缓(容器)存机制,一个非常典型的设计,这个机制意味着当一个帧图片被展示的时候,另一张帧视图正在被处理;此外,这两个缓存中分别对应一张帧图片,上文提及的每一张帧图片都是这两者之一。此图中,两个缓存被标记为A和B。当展示A容器中的帧图片时,系统将在B容器中建立一张新的帧图片。当新帧图片被建立完毕后,两者进行交换。B容器中的帧图片将被显示,而A容器中的帧图片将被情况并且一张新的帧图片将被处理。
       当你绘制帧图片的时间超过了16毫秒,则双缓存潜在的问题就发生了。如下图所示:
      
       B容器像这样运行,则一个闪避发生了。虽说闪避也是不好的,但是这张图所反映的真正问题却是CPU与GPU存在大量被浪费的时间(图中CPU与GPU存在大量空白区域,空白区域表示CPU与GPU没有东西可以处理)。在第一个帧时(一帧时等于16毫秒)中,B缓存的处理超时,在B缓存被展示出来之前,它一直处于使用中,A缓存也处于使用中,因为A缓存中的帧视图被展示了2个帧时(一帧时等于16毫秒),之所以要展示2个帧时的原因,是因为android只会在一帧时结束,下一帧时开始的时候切换缓存。CPU和GPU受限于可以使用的缓存数,不得不消极怠工(产生空白区域),从而使得系统,一步慢步步慢,这就是android4.0的缺陷。
        在android4.1中,通过引入第三个缓存,来解决上文中所提及的双缓存机制中潜在的问题。如下图所示:
      
         与双缓冲机制中的过程一样,B缓存将花费太多的时间;然而与双缓存机制中浪费CPU与GPU时间不一样的是,这段被浪费的时间,被用来创建了C缓存(第三个缓存),并且这个缓存会立即作用于一张新的帧图片。三缓存机制阻止了闪避情况的产生,经过最初的闪避后,将会为用户展示出一段平滑的动画。即便有些问题发生了,但系统还会努力给用户满意的结果。
      那么为什么系统不一直采用三缓存机制呢?正如上图所示,三缓存机制向处理过程中引入了一点输入延迟。例如,在渲染C缓存(上图蓝/绿部分)和展示C缓存之间。所以,当出现某些错误行为时,你有两个选项: 输入延迟(你的触摸操作生效时间会延长)或者画面卡顿。
     为了解决这个问题,android4.1并没有一直执行三缓存机制。一般而言,它会正常的执行双缓存机制,而第三个缓存将会出现在任何它应该出现的位置。通过这种方式,你将得到一个更少的输入延迟,而当有不好的事情发生时,你又能通过第三个缓存来恢复系统。
0 0
原创粉丝点击