写点什么

「Android 渲染」为什么 alpha 渲染性能低?

用户头像
李小四
关注
发布于: 2021 年 04 月 04 日
「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:


//before API 16setLayerType(View.LAYER_TYPE_HARDWARE, null);//before alpha animationsetLayerType(View.LAYER_TYPE_NONE, null);//after alpha animation
//from API 16ViewPropertyAnimator.alpha(0.0f).withLayer();//manage layer type automatically
复制代码


刚刚我们谈到,问题的出现是因为重叠部分的 UI 出现了异常,如果你的确信不会出现 UI 重叠,或者(为了更好的渲染性能)可以接受因此产生的 UI 问题,可以重写 View 的hasOverlappingRendering方法,结果返回false, 它会带来渲染性能的提升。


class MyView extends View {
@Override public boolean hasOverlappingRendering() { return false; }}
复制代码



以上。



Reference

https://www.youtube.com/watch?v=zdQRIYOST64

https://www.youtube.com/watch?v=wIy8g8yNhNk&feature=emb_logo

发布于: 2021 年 04 月 04 日阅读数: 18
用户头像

李小四

关注

Android Engineer 2018.05.01 加入

好奇心患者

评论

发布
暂无评论
「Android渲染」为什么alpha渲染性能低?