双缓冲减慢帧渲染 |系统跟踪分析

Double buffering slows frame rendering | systrace analysis

我正在使用自定义视图 canvas 绘图 (postInvalidate()) 和 HardwareAcceleration. After weeks of performance analysis i decided to sync my update and drawing operations with the VSYNC pulse over the Interface Choreographer.FrameCallback 开发一个简单的 2D 游戏。我认为这是获得流畅运动的正确方法。

但是我的动作仍然不稳定。我用 systrace 分析了它,发现这与我的 BufferQueue 有关。一旦双缓冲设置,帧时间超过 16ms。我对跟踪进行了截图并做了一些解释:

整个绘制操作等待SurfaceFlinger(消费者)的buffer release将自己新的空Buffer出队。

你能告诉我这是正常行为还是可能是什么原因造成的?

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

但是,如果您查看 BufferQueue 行,您会发现缓冲区在 VSYNC 截止日期之后到达。 SurfaceFlinger 醒了,但无事可做

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

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

您可以做几件事:

  1. 如果您错过了最后期限,请让应用丢帧。
  2. 指定帧的呈现时间,以便 SurfaceFlinger 会在超过该时间后丢弃它们。
  3. 故意每隔一段时间掉帧让队列清空。 (不是首选方法。)

#2 仅适用于 SurfaceView 上的 GLES,因此我们可以忽略那个。

#1 可能适合你;你可以看到 example in Grafika。它本质上说,"if the next VSYNC is firing in less than 2ms, or has already fired, don't bother rendering the current frame." View/invalidate 方法并没有为您提供与 GLES 相同的细粒度控制,所以我不确定它的效果如何。

在繁忙的设备上流畅播放动画的关键并不是每一帧都达到 60fps。关键是根据增量时间进行更新,这样即使丢掉一两帧也能看起来很流畅。

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