在 Android 上确定确切的屏幕翻转时间

Determine exact screen flip times on Android

我试图确定(在 1 毫秒内)特定屏幕翻转发生在 Android 上的时间。 Choreographer 会在每次帧翻转时触发,但无法确定实际显示的是哪一帧。根据https://source.android.com/devices/graphics/architecture.html,这个过程有好几层:user land buffer,翻转到triple-buffered queue,翻转到surface flinger,翻转到硬件。这些层中的每一层都可能丢帧,但此时我只确定了如何监控用户空间缓冲区。有没有办法监控另一个 buffers/flips(实时,在非 root、非自定义 phone 上)?

我在 HTC M8 上观察到意外的帧延迟(大约每 5 分钟 1 个),但 Nexus 7 似乎没有这个问题。我使用 Cedrus StimTracker (http://cedrus.com/stimtracker/) with a photo sensor and the Lab Streaming Layer (https://github.com/sccn/labstreaminglayer) 测量延迟。我已经尝试使用 eglPresentationTimeANDROID 来控制何时翻转屏幕,但并没有解决问题。

请注意,我使用的是 ndk,但我通常可以在需要时使用 JNI 来访问非 ndk 功能。

我关心的原因是为了将 Android 用于心理和神经学实验,其中 1 毫秒的精度是非常可取的。

就可访问的 API 而言,听起来您已经找到了相关的点点滴滴。如果您还没有,请通读 this Whosebug item.

使用 Choreographer 和外推法,您可以猜测下一次显示刷新发生的时间。在 Android 5.0+ 设备上使用 eglPresentationTimeANDROID(),您可以告诉 SurfaceFlinger 您希望将特定帧发送到显示器的时间。假设 SurfaceFlinger 正确考虑了所有延迟(例如 "smart" 面板添加的额外帧),这应该能让您获得可靠的计时。

(请记住,时间是基于显示器锁存下一帧的时间,而不是下一帧在显示器上完全可见的时间……那里的延迟将取决于面板。)

Grafika's "scheduled swap" Activity 使用此功能,但听起来您已经很熟悉了。

显示器在进行交换时发出信号的唯一方法是 dup() 来自前一帧的显示器退休栅栏 fd,并等待它。 SurfaceFlinger 中的一些代码执行此操作,特别是 DispSync 监视退休的栅栏以查看软件 "VSYNC" 是否在漂移。围栏没有public API,而且用户-space响应时间肯定会超过1毫秒......通常提前安排比反应更好.您对非根非自定义设备的要求使这成为问题。

如果您大部分时间都看到正确的行为,但偶尔会看到错误,最好的办法是使用 systrace 来查找原因。