双缓冲减慢帧渲染| systrace分析

时间:2016-07-08 14:42:06

标签: android graphics double-buffering systrace

我正在使用自定义视图画布绘图(postInvalidate())和HardwareAcceleration处理简单的2D游戏。经过数周的性能分析后,我决定通过接口Choreographer.FrameCallback将我的更新和绘图操作与VSYNC脉冲同步。我认为这是获得平稳运动的正确方法。

然而我仍然经历着波涛汹涌的动作。我用systrace对它进行了分析,发现它与我的BufferQueue有关。双缓冲设置完成后,帧时间超过16ms。我用一些解释制作了我的踪迹截图:

整个绘制操作等待SurfaceFlinger(使用者)的缓冲区释放,以使其自己的新空缓冲区出列。

你能告诉我这是一种常规行为还是可能是什么原因?

1 个答案:

答案 0 :(得分:1)

在你的图表上,你有一个注释," SurfaceFlinger错过了VSYNC"。

但是,如果查看BufferQueue行,可以看到缓冲区在VSYNC截止日期之后到达。 SurfaceFlinger醒了,但没什么可做的。

您的应用程序随后提供了一个额外的缓冲区,这意味着您有两个待处理缓冲区。由于您继续在每个VSYNC上提供缓冲区,因此队列永远不会返回到零缓冲区。如果队列填满,每次添加额外缓冲区的尝试都会导致阻塞。

FWIW,你的BufferQueue是三重缓冲的:两个在队列中,一个在显示器上。

您可以做一些事情:

  1. 如果您错过了截止日期,请暂停应用。
  2. 指定帧的显示时间,以便SurfaceFlinger在时间过后将删除它们。
  3. 每隔一段时间故意丢弃一帧,让队列为空。 (不是首选方法。)
  4. #2仅适用于SurfaceView上的GLES,因此我们可以忽略它。

    #1可能适合你;你可以看到example in Grafika。它基本上说,"如果下一个VSYNC在不到2ms的时间内发射,或者已经发射,请不要再渲染当前帧。" View / invalidate方法并没有为您提供与GLES相同的细粒度控制,因此我不确定它的效果如何。

    在繁忙的设备上平滑动画的关键是不能以60fps的速度击中每一帧。关键是根据增量时间进行更新,即使你放弃一两帧,事情看起来也很顺利。

    有关图形架构的其他详细信息,请参阅this doc