14

Android 旗舰机标配的高帧屏(120Hz),对各位 App 开发者有什么影响?

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzIxNjc0ODExMA%3D%3D&%3Bmid=2247486751&%3Bidx=1&%3Bsn=a88aeb953bb0b842c82b762bc90d43f1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

IRni6nu.jpg!web

各大手机厂商发布的旗舰机,都将 90Hz 甚至 120Hz 高帧率流速屏当成了标配,那这对我们实际开发的 App 会不会有影响?原本在 60Hz 下,每帧只需保证 16ms 内绘制完成就可以做到流畅,换到高帧屏中,实际留给我们绘制时间是缩短了的,是否对我们的代码质量要求更高?

推荐一篇文章,来讲讲对此的影响,希望对大家有帮助。

以下文内的 "我" 为文章原作者。

前言

昨天在 IT 之家留言说,如果应用无法满足 120hz 的绘制会怎样?假设如果绘制一帧的时间,如果大于 1/120 秒,哪怕是多了 1 毫秒,就会导致应用在 120Hz 的手机上也就变成了 60Hz。

后来仔细想想,这句话说的并不是特别严谨,为什么这么说呢?

一、证明我的观点

首先我写一个 demo 来证明我的观点。

1.1 满帧的应用

public class MyTextView extends TextView {
int i = 0; @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (i < 6) {
this.post(new Runnable() {
@Override
public void run() {
MyTextView.this.setText(i++ + "");
}
});
}
}
}

我写了一个只绘制 6 帧的一个界面,Activity 中包含这个 MyTextView,通过抓 Trace 可以看到,下面这个 6 帧绘制图,都是在一个 Vsync 周期( 图中黑白相见的色块,均是一个 Vsync 周期 )绘制一帧。

zqmQ32f.jpg!web

为什么第一帧会有点延迟,主要是因为启动时,主线程在干了些其他事情,好在绘制花不了太多时间。

大概绘制也就 3 毫秒左右,毕竟界面简单。

1.2 帧数减半的应用

public class MyTextView extends TextView {
    int i = 0;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        try {
            Thread.sleep(16);
        } catch (Exception e) {
        }
        if (i < 6) {
            this.post(new Runnable() {
                @Override
                public void run() {
                    MyTextView.this.setText(i++ + "");
                }
            });
        }
    }
}

我手动人为在 MyTextView.onDraw() 方法中 sleep 了 16 毫秒,来模拟很多应用实现的不好,导致绘制耗时的情况,例如 View 层级厉害复杂,甚至在 onDraw() 方法中进行文件读写。

RnE36ja.jpg!web

通过抓 trace 可以看到,原本之前的例子( 1.1 )中 6 帧由 6 个时间周期绘制完成,现在变成了 6 帧由 12 个时间周期完成了。

1.3 小结

这就是我一直想说的一个观点, 120Hz 的手机体验不一定有 90Hz 的手机好的原因,一旦主线程一次 traversal(一次 ViewRootImpl 的 onDraw() 的遍历)的时间超出了 vsync 的时间周期 1/120s,就会导致帧率直接砍半,降为 60 帧 ,90Hz 可以让这个折半降帧率的现象减少。

二、绘制一帧指的是什么

为什么我说我的观点不准确?其实是我太笼统的定义了绘制一帧这个词。

在硬件加速开启的情况下:

  • 如果我将绘制一帧的时间定义成: 主线程一次 traversal ,那我说的话是正确的。

  • 如果我将绘制一帧的时间定义成: 主线程一次 traversal + renderthread 一次渲染 ,那我说的话是不严谨的。

2.1 引发我思考的 trace

因为要让主线程一次 traversal + renderthread 超时不是特别好写 demo,我就用一个昨天引发我思考的一个 trace 给大家讲解一下。

rURJje7.png!web

大家从第一个黄色 F 的圆圈开始看。

UI Thread 的 doFrame + RenderThread 的 DrawFrame 的时间超出了一个 Vsync 周期,接下来每一帧的情况,都是按照第一帧绘制的情况一样的情况运行,最好造成的现象就是虽然帧数是满帧,但是每一帧其实都是延迟显示的。

用一句哲学的话来概括就是: 你眼睛看到任何事物,其实都是事物过去的样子

假如主线程一次 traversal + renderthread 一次渲染时间超出了 vsync 周期不多,这样子的应用大概率是可以满帧运行( 满帧不代表显示正常 )。

我上面一句话中用了不多,大概率这种模糊的文字,因为这个情况下能否满帧的临界点比较难定义。

2.2 如何定义这个 120 变成 60 帧的临界点

继续下面这个图,你会发现 UI Thread 的 doFrame 会非常 happy 的按照 Vsync 信号执行,但是下面 renderthread 已经忙的不可开交了。

fuMBfqn.png!web

其实第一帧已经延迟了,假如运气不好导致了 drawframe 的时间横跨了 2 个 Vsync 周期,还是会导致丢帧,这个时候就从 120 帧降为 60 帧。

三、总结

3.1 理想中的结论

假设开启硬件加速,一帧绘制的时间 = UI 线程( T1 )+ RenderThread 线程( T2 )。

那么 Vsync 时间的周期是 1/120s,约等于 8.3ms,此时:

  • 如果 16.6ms > T1 > 8.3ms,会导致从 120 帧降为 60 帧。

  • 如果 T1 <8.3ms,16.6ms> T1 + T2 > 8.3ms,虽然还是满帧,但是你看到的永远是前一帧的画面。

  • 如果 T1 + T2 > 16.6ms,毫无疑问会导致从 120 帧降为 60 帧。

上面理论看起来是很完美的结论,千万别把这个当做定理去记忆,因为现实会比这些情况复杂的多。

3.2 显示中的结论

可能会有人说现在 CPU,GPU 那么强,怎么可能会超时呢?

举个微信在 865 的手机上,滑动消息列表的例子,T1 约等于 6ms,T1 + T2 约等于 8.2ms。

这还并不是太过复杂的界面,大家会发现,6ms 已经很接近 8.3ms 了。

3.3 给开发者的建议

对于要适配 120hz 手机的应用的工程师,你们要注意以下事情。

  1. 避免 T1 > 8.3ms,也就是要减少主线程干的活,要减少一次 draw 的时间。千万别在 draw 的流程进行文件访问或者 sleep。

  2. 避免在滑动响应的时候 T1+T2 > 8.3ms,虽然界面在显示的时候,推迟一帧用户是察觉不了的,但是在滑动的响应中如果推迟一帧,可能会影响 "跟手" 的体验。

  3. 千万别关闭硬件加速,一旦关闭硬件加速 T1+T2 > 8.3ms 就会导致 120 降为 60 帧。

四、尾巴

说到这里,如果听得懂我在说什么的人,应该能懂我想表达的意思。

如果不懂我说的什么的人,希望你去补一下以下知识点,再回过头来看这个文章。

知识点 1:

TextView.setText 到屏幕显示文字,整个过程发生了什么。

知识点 2:

硬件加速之后,主线程( UI Thread )和 RenderThread 之间的协同工作的方式。

知识点 3:

APP 界面和 SurfaceFlinger 之间的关系

可能会有人说,你揪那么细致干嘛,对于用户来说,掉了几帧的影响也不大,,但是对于性能优化工程师来说,有时候就是要纠结那几个丢帧的情况,只有做好了每一帧的完美绘制,才能给用户带来最完美的用户体验。

- End -

文章看完了,最后我换个角度补充一些观点。

手机硬件虽然增加了高帧屏,确实看似对每一帧绘制的时间要求更短了,但别忘了,在升级屏幕的同时,对其他硬件( CPU、GPU、ROM等 )也做了相应的升级。虽然留给我们的刷新时间缩短了,但计算和渲染绘制的能力,也相应的提高了。

那么到具体的代码上,你在旧手机上绘制一帧需要 10ms 的代码,在 120Hz 的旗舰机上可能只需要 6ms,两相抵消之下问题不会太大。

所以最后核心还是在日常编码的过程中,随时注意性能的问题。管他高帧低帧,领导觉得" 跟手 ",咱就嘚优化。

本文对你有帮助吗? 留言、转发、点好看 是最大的支持,谢谢!

公众号后台回复成长『 成长 』,将会得到我准备的学习资料。

MbqQNzy.jpg!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK