「Android 渲染」为什么 alpha 渲染性能低?
开门见山
1. 多次写入像素
在渲染不透明的像素时,只需要写入一次
在渲染透明像素时,每个像素至少需要写入两次
第一次是之前的像素值
第二次把之前的颜色与设置的不透明度做混合,产生一个新的颜色值,写入这个新的颜色值。
我们看到的一层下面有另一层的半透明效果,对于屏幕来说就是一个混合后的具体的颜
2. 指令重排无效
发给 RenderThread 的 DisplayList,里面的内容是按照 View 层级来排列的,默认顺序执行,但这样性能并不好:
分治、归并的思路可以提高性能,大家都听过指令重排序,把相同的指令一起执行、合并成一次操作执行,这样性能肯定是更好的,经过优化,绘制的流程如下:
很多内容一次绘制成功,非常高效。只是有一个问题,其实上面的例子中,背景 item 并不是一次性渲染的,原因是因为出现了重叠(overlap),为了确保重叠后的 alpha 是正确的,这里的渲染只能串行执行,而不能归并。
我们发现,正确性还是 Android 默认方案的第一权重;在第 1 点中提到过,alpha 渲染,底层是在原像素上做 blending,要依次渲染。
我们看到,大部分的渲染操作都可以享受指令重排序、归并批处理的高性能,但 alpha 渲染被排除在外了。
3. 灾难情况: ViewGroup 的 alpha 渲染
在动画中,经常需要更改 ViewGroup 的透明度实现淡入淡出效果。这时候,事情有了一些变化,如果沿用之前的绘制方式(每个子 View 逐个透明度绘制)会出现一个问题:
重叠的部分,不透明度会叠加(如下图右侧).
我们想要的效果是下图左侧,而不是右侧。
这个问题应该怎么解决呢?Android 渲染团队当然也意识到这个问题,他们的解决方案是:
绘制一帧未做 alpha 变换的数据到内存中
然后把这一帧的数据做 alpha 处理之后,渲染到屏幕
这个方案确实可以解决上面的 UI 异常问题。只是,他导致了一次整个 View Hierarchy 的重新绘制,每次 ViewGroup 的 alpha 变换都要重绘一帧数据,如果我在执行一个动画,那岂不是性能灾难?
于是问题就来了:
这一帧数据为什么要重新绘制?刚刚渲染的不就是这一帧吗?
同学你说的很对,这一帧确实生成过了,只是被丢弃了。毕竟它会占用不小的内存,如果不知道是否有用,默认在会之后丢弃。
我们优化的方向,就是使用缓存数据,空间换时间。具体的执行调用如下 API:
刚刚我们谈到,问题的出现是因为重叠部分的 UI 出现了异常,如果你的确信不会出现 UI 重叠,或者(为了更好的渲染性能)可以接受因此产生的 UI 问题,可以重写 View 的hasOverlappingRendering
方法,结果返回false
, 它会带来渲染性能的提升。
以上。
Reference
https://www.youtube.com/watch?v=zdQRIYOST64
https://www.youtube.com/watch?v=wIy8g8yNhNk&feature=emb_logo
版权声明: 本文为 InfoQ 作者【李小四】的原创文章。
原文链接:【http://xie.infoq.cn/article/59c992c87d129102dc738b0fe】。文章转载请联系作者。
评论