我正在调查我的应用程序的性能,因为我注意到在滚动时会掉帧。我在运行4.3系统的Nexus 4上运行了systrace,并注意到输出中有一个有趣的部分。
一开始一切都很好。放大左侧部分, 我们可以看到每个vsync都开始绘制,完成后还有时间,并等待下一个vsync。由于它是三倍缓冲,所以应该绘制到一个缓冲区中,在完成后将在以下vsync上发布。
在缩放截图的第四个vsync中,应用程序执行了一些操作,绘制操作没有及时完成下一个vsync。但是,我们没有丢帧,因为之前的绘制已经提前一帧工作。
跟进问题
一开始一切都很好。放大左侧部分, 我们可以看到每个vsync都开始绘制,完成后还有时间,并等待下一个vsync。由于它是三倍缓冲,所以应该绘制到一个缓冲区中,在完成后将在以下vsync上发布。
在缩放截图的第四个vsync中,应用程序执行了一些操作,绘制操作没有及时完成下一个vsync。但是,我们没有丢帧,因为之前的绘制已经提前一帧工作。
在这种情况下,绘制操作无法弥补错过的垂直同步。相反,每个垂直同步只启动一次绘制操作,现在它们不再提前绘制一帧了。
放大右侧部分, 应用程序会执行更多的工作并错过另一个垂直同步。由于我们没有提前绘制一帧,因此实际上会丢失一帧。之后,它会回到提前绘制一帧的状态。
这是预期的行为吗?我的理解是三倍缓冲允许您在错过垂直同步时进行恢复,但这种行为似乎会在错过两个垂直同步时丢失一帧。
跟进问题
在这张截图的右侧,应用程序实际上正在比显示更快地渲染缓冲区。在执行遍历#1(在截图中标记)期间,假设正在显示缓冲区A并且正在渲染缓冲区B。 #1在vsync之前很长时间完成,并将缓冲区B放入队列中。此时,应用程序是否能够立即开始渲染缓冲区C?相反,执行遍历#2直到下一个vsync才开始,浪费了宝贵的时间。
同样地,我有点困惑为什么需要在这里左侧waitForever。假设正在显示缓冲区A,缓冲区B在队列中,缓冲区C正在被渲染。当缓冲区C完成渲染时,为什么不立即将其添加到队列中?相反,它会一直等待,直到从队列中删除缓冲区B,然后才添加缓冲区C,这就是为什么队列似乎始终保持大小为1,无论应用程序渲染缓冲区多快。