iOS上的vsync:它是如何工作的

时间:2016-12-10 17:40:14

标签: ios graphics opengl-es

我试图弄清楚vsync如何在iOS上运行,并与CADisplayLink结合使用。我想在这里回答的问题是:

  • 如果我错过了CPU端的框架,iOS上会发生什么?

我设置了一些测试:

  • 在iPhone
  • 上使用间隔为1 = ~60Hz的CADisplayLink计时器
  • 使用[CADisplayLink timestamp]mach_absolute_time()
  • 分析计时器调用之间的时间

测试1:基础测试:在这里,我只跟踪了10000个样本:

timestamp-----
max: 16.762583
min: 16.627625
mean: 16.675080
variance: 0.000333

mach----------
max: 22.606042
min: 10.815958
mean: 16.675694
variance: 0.602793

diff----------
max: 5.941417
min: 0.000750
mean: -0.000615
variance: 0.607476

测试2:由于CPU等待时间短而导致帧丢失:这里,在帧X上,我只是坐在自旋锁中进行Y次迭代。记录相对于第X帧的帧时间:

Y = 200000
-1: 16.72   17.85   (-1.13)
0:  16.66   15.37   (1.29)
1:  33.32   43.74   (-10.42) (*)
2:  16.74   4.34    (12.40) (*)
3:  16.61   16.70   (-0.10)
4:  16.71   16.65   (0.06)  

Y = 100000
-1: 16.66   16.50   (0.16)
0:  16.69   16.67   (0.02)
1:  16.63   22.21   (-5.58) (*)
2:  16.68   9.91    (6.77) (*)
3:  16.70   16.04   (0.67)
4:  16.69   16.70   (-0.01)

测试3:与测试2相同,但使用OS调用睡眠t秒

t = 0.03
-1: 16.67   16.54   (0.14)
0:  16.68   16.91   (-0.23)
1:  33.35   34.78   (-1.43) (*)
2:  16.68   14.93   (1.74) (*)
3:  16.68   16.87   (-0.20)
4:  16.67   16.48   (0.19)

t = 0.02
-1: 16.64   16.54   (0.09)
0:  16.72   16.91   (-0.19)
1:  16.66   20.79   (-4.13) (*)
2:  16.69   12.60   (4.08) (*)
3:  16.67   18.24   (-1.57)
4:  16.68   15.09   (1.59)

t = 3.0
-1: 16.68   16.74   (-0.07)
0:  16.63   16.58   (0.05)
1:  266.84  3004.04 (-2737.20) (*)
2:  2751.35 14.82   (2736.54) (*)
3:  16.66   16.80   (-0.14)
4:  16.68   15.86   (0.81)

观察:

  • 与Apple文档不同,CADisplayLink NOT 在CPU帧丢失时等待vsync。
  • 然而,对于小错过,通过[CADisplayLink timestamp]
  • 看起来是Apple 想要我们相信的东西
  • 我最好的解释是:
  1. CADisplayLink调用仅在图形驱动程序的命令缓冲区为空,或GPU的命令缓冲区为空(因此从图形驱动程序请求更多命令或取消阻止)时发生)。
  2. iPhone上的GPU启用了vsync - 停止,并在处理更多GPU命令之前等待物理屏幕刷新。
  3. 如果我们的GPU和CPU帧始终低于16.6ms,我们将生成更多GPU命令然后GPU可以消耗
  4. 因此,当GPU停止时,它会停止从驱动程序中提取命令,一旦我们填满驱动程序命令缓冲区,我们的CADisplayLink就会停止被调用。
  5. 在vsync之后,GPU能够处理更多GPU命令,因此也能够从驱动程序中提取命令。当驱动程序命令队列中有足够的空间时,驱动程序通知iOS它需要更多命令,并且我们得到CADisplayLink调用。
  6. (我无法判断这是否会驱动iOS上的整个事件循环,或者事件循环是否始终在运行,并且只是轮询驱动程序迭代以查看它是否可以调用CADisplayLink
  7. 因此,我们大约每16.6毫秒调用一次CADisplayLink - 一个 管道的下游结果等待远端的vsync。
  8. 但是,如果我们错过了CPU端的帧,即在驱动程序请求后产生命令稍长于16.6ms,则可以。仍然有一两帧(需要测量)仍在管道中的命令。只要我们不让管道耗尽,我们就可以了:我们仍然可以让GPU渲染1个新帧,每16.6毫秒,与vsync一起准时
  9. 这就是[CADisplayLink timestamp]与"实际"不同的原因。时间,mach_absolute_time()
  10. 例如,测试2:i = 100000

    1. 我们运行了一堆帧,很容易在16.6ms以下打包管道
    2. 我们花了很长时间在第X帧(22.21ms)
    3. 然而,GPU落后1帧:第X-2帧在屏幕上,当vsync发生时,它不需要帧X的命令,帧X-1是还有在管道中
    4. 当下一个vsync发生时,GPU 需要第X帧命令时,它们就在那里。
    5. 在X帧上花了一段时间后,我们能够在快速启动X + 1帧后填满管道
    6. 因此,对于用户来说,没有丢帧。

      我离这里有多远?我希望自己是一名计算机工程师。

0 个答案:

没有答案