(转载)了解Android 4.1,之三:黄油项目 —— 运作机理及新鲜玩意
Welcome back to GTKA, everyone's favorite investigative series where we learn all about the newest version of Android (with a heavy emphasis on "all"). The previous two episodes, if you didn't catch them, are here and here.
欢迎回到人见人爱的《了解Android》系列文章。从这个系列中,我们会了解Android新版本的所有(注意,是所有喔!)内容。如果你还没看过之前两篇的话,它们在这里和这里。
Today we'll be doing something a little different and looking at something near and dear to everyone's hearts: performance. Jelly Bean is crazy fast. Slap it on a Galaxy Nexus and it'll feel like a brand new phone. Scrolling is faster and smoother, and the touch response is hyper-sensitive. In addition to all the smoothness work, there are new transitions all over the place.
今天,我们要关注一些跟以前不同的内容,更贴近我们需求的东西:性能! Jelly Bean快的很疯狂啊!把它搞到一部Galaxy Nexus里,你会感觉好像拿了一台新手机一样。卷动是那么的迅速顺畅、而触摸响应是那么的敏感。此外,还多了很多动画效果!
I'm sure you've all seen a sweeping overview of this, but those are boring. What exactly is new, and how did they do it? That's what we're here to figure out. So, grab your popcorn, kids; it's time to learn all about Project Butter. How They Did It
我知道你们已经看过一些关于这个的说明,但它们写的都弱透了。到底哪些是新的,而它们又是如何做到的?我们马上就能搞清这些。好,抓上你的爆米花,孩子;我们来了解一下传说中的“黄油项目”吧。他们是怎么干的
So how do you make an 8 month old Galaxy Nexus run like a Galaxy S III? Lots of hard work. Hard work that was thoughtfully detailed to us at Google I/O by two of my favorite I/O presenters, Chet Haase and Romain Guy. An hour long PowerPoint presentation geared towards developers is not the most accessible thing in the world, so I'm going steal some slides and try to cover the more interesting parts, and (hopefully) condense it down to a few minutes. Doesn't that sound like fun? VSync Turns Frame Drawing Into A Well-Oiled Machine
怎么才能让一部寿命已达八个月的老Galaxy Nexus跑的好似Galaxy S III一样呢?嗯,这需要很多努力。在Google I/O上,我最爱的两个I/O演讲者——Chet Haase 和Romain Guy为我们详细阐述了这些努力。长达一个小时的PPT演示着眼于说明开发者是怎样一群不容于世的存在,所以我干脆偷出一些包含有趣内容的页面,把它们压缩到几分钟内(希望如此),听起来很爽吧?垂直同步为帧绘制加油
PC Gamers are probably familiar with the term "VSync." It's that graphics option checkbox that will stop your screen from tearing in a video game.
PC游戏玩家大概对垂直同步这个词很熟悉了。包含这个词的钩选框可以帮助你的游戏避免画面撕裂的问题。
To understand what exactly VSync is, we're going to need a quick display primer: Video (ie a phone display doing stuff) is made of individual pictures called "frames." Smooth animation is usually 60 frames per second. Frames are made of pixels, and, when the display draws a frame, the pixels are filled in row by row. Got it? Good.
为了理解垂直同步到底是个什么东西,我们需要对显示系统做一个新手教学:视象(比如说手机屏幕显示的东西)是由一系列叫做“帧”的独立图片所组成的。平滑的动画一般需要每秒六十帧。而帧是由像素点构成的。当屏幕绘制一帧的时候,像素点是一行一行的进行填充的。明白?很好。
The display (LCD, AMOLED, whatever) gets each frame from the graphics chip, and starts drawing it line by line. Ideally, you want the display to get a new frame from the graphics chip after it is finished drawing the previous frame. Tearing occurs when the graphics chip loads a new frame in the middle of the LCD draw, so you get half of one frame and half of another.
显示屏(LCD,AMOLED或者别的什么)从图形芯片获取每帧的数据,然后一行一行的进行绘制。理想状况下,你期望显示屏在绘制完一帧之后,图形芯片整好能提供新帧的数据。图像撕裂的状况就发生在图形芯片在图像绘制到一半的时候,就载入了新一帧的数据,以致你最终得到的数据帧是半个帧的新数据和半个帧的老数据。
VSync, well, synchronizes things. It tells the GPU to wait for the screen to finish its line by line drawing before loading the next frame.
而垂直同步,顾名思义,就是用来同步的。它告知GPU在载入新帧之前,要等待屏幕绘制完成前一帧。
Android has always used VSync to stop screen tearing, but Jelly Bean takes things a step further. The VSync pulse is now used to start all the processing for the next frame.
Android一直使用垂直同步来避免屏幕撕裂。而Jelly Bean更进一步。垂直同步脉冲现在会贯穿于所有的图形运作过程。
Most Android displays run at or around 60 frames per second (or 60 Hz, in display jargon). In order to have a smooth animation, you have to actually be able to process 60 frames per second - that means you've got 16ms to process each frame. If you take longer than 16ms, the animation will stutter, and that buttery smooth feeling we're aiming for melts away.
大多数Android显示系统是以每秒钟60帧的频率工作的(专业点说,叫60Hz)。为获得更平滑的动画,就必须具有每秒钟处理60帧的能力——意味着每帧只能花费16毫秒的时间。如果这个过程超过16毫秒,动画显示就会有停滞感,我们期待的如丝般顺滑的体验也就消失无踪了。
16 milliseconds isn't a lot of time, so you're going to want to make the most of it. In Ice Cream Sandwich, processing for the next frame would just kind-of lazily start whenever the system got around to it. In Jelly Bean, the whole process of making the next frame starts as soon as the last frame is finished, at the beginning of the VSync pulse. In other words, they're using as much of the 16ms as they can. Here's an example:
16毫秒不是很长的一段时间,所以你会希望充分利用它。在ICS中,系统对下一帧的处理有点懒加载的意思,需要的时候才进行处理。而在Jelly Bean中,整个进程将在上一帧刚结束时,在垂直同步脉冲开始时,就立刻开始下一帧的处理过程。换句话说,系统会尽量充分的利用那16毫秒。举个例子说:
This is what life is like without running everything off of VSync. In these slides, the numbers are frames. First the frame is processed by the CPU and GPU, and, when it's finished, it's handed to the display at the beginning of the next VSync.
这就是在没有进行全面垂直同步时的状态。在图片中,数字代表着帧。首先,帧由CPU和GPU进行处理,当处理完成后,在下一个垂直同步开始时交付显示。
So in this picture, Frame 0 is displayed, and, during the 16ms of display time, the CPU and GPU prepare the next frame. The calculations get done in time, and at the next VSync pulse, they hand over the next frame, "Frame 1." Great.
在例图里,先显示了第0帧,在16毫秒的显示时间内,CPU和GPU准备下一帧。运算按时完成了,在下一个垂直同步脉冲到达时,它们交付了下一帧:第1帧。很好。
We're now showing frame 1, and it's time to start working on frame 2. Something slows the system down, though, and processing for the next frame doesn't start until we're well into our 16ms time limit. The system now only has about 4ms to figure out frame 2, so the processing for it doesn't get finished in time. With no frame 2, the display is forced to show frame 1 again, for another 16ms. Team Android has dubbed this "Jank," and it basically means any animations happening during this time won't be fluid; the user will see stuttering.
显示了第一帧后,是时间完成第二帧了。但某些因素导致了系统变慢,所以,直到16毫秒即将过去时,下一帧的处理工作才刚刚开始。此时,仅剩4毫秒来绘制第二帧了。毫无意外的,这工作没及时完成。此时,显示屏在第二帧没完成的情况下,只能在后面的16毫秒内再次显示第一帧。Android小组将这种情况称为”废帧“,标示着此其间内所有的屏幕动效都无法及时传递,而用户会体验到停滞感。
Here's the new way of doing things in Jelly Bean. All the processing for the next frame starts at the VSync pulse, so you're now making the most of your 16ms of render time.
这幅图展示了在Jelly Bean中事情是如何运作的。所有下一帧的运算工作都在垂直同步脉冲抵达时开始。这样16毫秒的渲染时间就会被充分利用了。
Frame processing has moved from "Yeah whenever we get around to it," to a rigidly scheduled, highly organized affair. Sort of like the difference between a car mechanic and a NASCAR pit crew. In this example, all the processing happens within the 16ms time limit, all the frames get delivered on time, and you get a smooth, buttery experience. Triple Buffering Stops Jank From Snowballing
帧处理由”不管三七二十一,反正我搞完了“,变成了高度组织,严格按照时间表执行。有点类似街边修汽车的和云斯顿赛车维修站的区别。在这个例子中,所有的处理都在16毫秒限制内发生,所有帧都按时交付,而用户则获得了平滑、流畅的体验。三倍缓冲解决了画面撕裂问题
VSync isn't the only thing that helps out animation smoothness, Android is also able to recover from a slowdown more smoothly.
除了垂直同步外,Android还使用了其它方式来使动效更顺畅。
So what the heck is a "buffer"? Put simply, a buffer is the container the frame is built and stored in. We've been referring to frames by number, but really, those frames sit in one of the two buffers. Android is double buffered, a pretty typical setup, meaning it can display 1 frame while working on another. In this picture the buffers are labeled "A" and "B." While displaying buffer A, the system starts building a new frame in buffer B. When that's ready, they swap buffers. B gets displayed, and A gets cleared and a new frame is worked on.
那么,到底什么是“缓冲”呢?简单的说,缓冲就是帧构建和保存的容器。我们在前面用序号指代帧,但实际上,这些帧其实是在两个缓冲中的。遵循惯例,Anroid采用双缓冲机制,意味着它可以在显示一帧的同时进行另一帧的处理。在图中,就是缓冲A和B。当显示缓冲A时,系统在缓冲B中构建新的帧。完成后,则交换缓冲。显示缓冲B,而A则被清空,继续下一帧的绘制。
The problem with double buffer arises when you take longer than 16ms to draw your frame. Here the processing on buffer B runs over, which means a stutter (Jank!) happens. Stuttering is bad and all, but the real problem here is all the white space in the CPU and GPU graphs, that's wasted time. In the first frame, buffer B runs over, so that buffer is in use until it can be displayed, buffer A is also in use, because it is being displayed for 2 frames in a row, and remember, you can only switch frames (and hence, buffers) at the VSync pulse. The CPU and GPU are out of usable buffers, so they just sit there. One slowdown puts the system behind, which causes more slowdowns. This was how Ice Cream Sandwich worked.
当某帧的绘制时间超过16毫秒时,双缓冲的问题就暴露出来了。如图所示,当缓冲B超时后,一个卡顿发生了。卡顿总是不好的,但更严重的问题在于图中代表CPU和GPU的图片之间的空白,这是对时间的浪费。在第一帧中,缓冲B超时,则在它被显示之前,都处于使用中的状态,而缓冲A因为为了填补空白,仍在显示,则也处于使用中的状态。我们知道,仅在收到垂直同步脉冲时,才会进行帧(缓冲)切换。则CPU和GPU受限于可以使用的缓冲数,不得不消极怠工。一步慢步步慢,这就是ICS的缺陷。
In Jelly Bean, we've got a solution for 2 full buffers, a third one! Same situation as before, buffer B takes too long, and A is in use displaying the current frame. This time though, instead of wasting processing time during the repeated buffer, the systems creates a C buffer, and gets to work on the next frame. Triple buffering stops the stutter fest, and after the initial skip, the user sees a smooth animation. It's all about presenting a stiff upper lip to the user even though things aren't going so smoothly under the hood.
在Jelly Bean中,我们有了解决双缓冲问题的办法:再加入第三个缓冲!在前述的情况下,B缓冲超时,而A缓冲用于当前帧的显示中。此时,不会因前述原因造成时间的浪费,系统会新创建缓冲C,并继续下一帧的工作。三倍缓冲结束了频繁卡顿的产生,在初始化跳顿后,用户得到了平滑的动画效果。即便有些问题发生了,但系统还会努力给用户满意的结果
So why don't they just do triple buffering all the time? Well, as you can see from the diagram, triple buffering introduces a bit of input lag into the process. Look, for instance, at the distance between the rendering of buffer C (the blue/green part), and the displaying of it. So, when things are misbehaving, you get a choice of 2 evils: input lag (your touches taking longer to have an effect) or choppy animation.
那么,为什么不干脆一直用三倍缓冲呢?正如你在图中看到的,三倍缓冲在整个过程中引入了一些输入延迟。比如说,在缓冲C(暗绿色部分)渲染过程与它被显示之间。所以,当出现某些错误行为时,你有两个选项: 输入延迟(你的触摸操作生效时间会延长)或者画面卡顿。
To address this, Jelly Bean doesn't do triple buffering all the time. It normally runs a double buffer, but that third one is around whenever you need it. This way you get less input lag, and when things go wrong, you've got a third buffer at the ready to help you recover. The Results
为解决这个问题,Jelly Bean没有一直使用三倍缓冲。一般情况下,它只使用了双缓冲,但当需要的时候,会用三倍缓冲来进行增强。这样,即将输入延迟降低到最少,又能在发生意外的情况下保持画面流畅。结果
The result of all this hard work is buttery smooth animation. The team was so impressed with their new animation aptitude that they spruced up many of the transition animations, which I will now present to you in excruciating detail. Check out ICS vs Jelly Bean, in super slow-mo. New Animations
以上努力的结果是得到了顺畅的动画。我们都为簇新的动画效果震惊了,过会儿我会展示这些动画的详情。相对于Jelly Bean, ICS简直就像拉车的老牛一样。新动画
Icon Launch Transitions - Left: ICS's no-frills app launch transition. Right: JB zooms in from the location of the icon
There isn't much to say about these videos, but I'll try my best. Ice Cream Sandwich (left) has an absolutely boring icon launch transition. It's just a simple stretch and fade to the center of the screen. In Jelly Bean (right), applications zoom out from the icon position. This manages to be both neater looking and more communicative: "You pressed this icon, and this is opening from it." I like it.
Uninstalling - Left: ICS just uses the standard screen transition. Right: Jelly Bean's fun "toilet flush" animation
Uninstall gets a cool transition too. It's a slide/fade/shrink animation to the bottom of the screen. It sort of reminds me of a toilet flush. The previous screen also gracefully slides into view when the app is gone.
Launching from within an app - Left: ICS does a simple fade. Right: JB slides things all over the place.
This transition is pretty much the uninstall animation in reverse, and it is used all over the place. I think it's triggered whenever an app opens another app. So here, you see the play store launching an app, and you'll see it when something like Google Reader launches a web browser, it's all over the place.
Update: Googler Clarification!
The always-helpful Dianne Hackborn, an Android Framework Engineer, stopped by our Google+ page (you are following us on G+ right?) with some insight on this animation:
"One thing I'd like to clarify -- the "uninstall" and "launch" animations are actually the same thing. This is the animation set for a "task switch". That is, moving in the UI from one task to another. A task is the thing you see in recent tasks, so this effectively tells you that you are moving between tasks that would be seen in the recent tasks UI."
So there's even more communication through animation. Thanks Dianne!
Recent Apps - Left: ICS oddly fades to a blank desktop. Right: JB's awesome transition
Recent apps probably has the coolest animation out of the bunch. The app grows out of the thumbnail, which is, again, neat looking and communicative - the perfect use of an animation system like this.
And finally, the new Jelly Bean camera animation. Snapping a picture sends your still flying off to the right, and a swipe will bring it back. I didn't bother showing you the ICS version because, well, nothing happens.
That's about it for Project Butter. You really have to experience it to get the full effect. Everything is smooth and fast. It really is impressive how much more power they've managed to squeeze out of my old Nexus.