Fancy3D的_debug提供了监视性能表现的monitor, 打开frameMonitor之后我们最先看到的两个监视窗口是”FrameElapse”和”EngineElapse”. FrameElapse是设备主循环所用的时间, 也就是对应到FPS; EngineElapse是引擎中UpdateFancy3D和RenderFancy3D所用的时间, 也就是引擎完成一帧渲染逻辑所用的时间.

  在PC上这两个monitor的数值总是非常接近的, 但是在安卓上测试的时候有时我们会发现二者差距比较大(如图 红米2 47ms:28ms).

  

android 设置FrameLayout的位置_等待时间


  仔细观察, 更加奇怪的是, 在例子中开启ragdoll效果, EngineElapse消耗的时间增加了8ms左右(物理的更新需要更多计算), 但是FrameElapse并没有相应的增加, 他只增加了1ms左右.

  为了查明原因, 我先在Eclipse中对时间分布进行了分析. 通过在Eclipse中进行debug分析发现: 在安卓上, 一帧的时间主要集中在JniRender(下图中黄色部分)和eglSwapBuffers(下图中绿色部分). JniRender是实际调用引擎更新渲染的入口, 其耗时与EngineElapse的统计值比较接近, 而eglSwapBuffers则与之前所说的迷的差值接近.

  

android 设置FrameLayout的位置_等待时间_02


  所以我们的第一个疑问—-为什么FrameElapse和EngineElapse在安卓上存在差值便有了解释.

  在安卓上的swapBuffer并不像PC, 他实际上并没有在UpdateFancy3D和RenderFancy3D中执行, 这个差值便是swapBuffer所用的时间. ( swapBuffer: 交换缓冲区. 我们在渲染时都是采用的双缓冲技术, 显示在屏幕上的是一个缓冲, 在更新时先填充一个名为后备缓冲区的缓冲, 在所有更新执行完毕后交换前后两个缓冲, 后背缓冲的内容, 也就是下一帧, 便显示在屏幕上 )

  接下来通过测试关闭开启ragdoll时的耗时表现发现eglSwapBuffers在时间统计图上像弹簧一样时长时短, 于是我们推测swapBuffer中有一个类似sleep的等待, swapBuffer要等待某个条件才能退出. 这也就解释了为什么FrameElapse和EngineElapse的增长幅度差异那么大.

  通过查询资料, eglSwapBuffers的执行内容如下:

  1. 首先计算非dirty区域,然后将非dirty区域数据从上一个buffer拷贝到当前buffer
  2. 完成buffer内容的填充,然后将previousBuffer指向buffer,同时queue buffer
  3. Dequeue一块新的buffer,并等待fence。如果等待超时,就将buffer cancel掉
  4. 按需重新计算buffer
  5. Lock buffer,这样就实现page flip,也就是swapbuffer

  在Dequeue buffer的时候,是有在等待fence的。即便是等待超时,也是需要一个Vsync时间的. ( Vsync: 垂直同步, 为了保证在游戏逻辑更新速度超过显示器刷新速度时, 画面不产生撕裂而产生的技术, 其原理可以简单概括成下一帧的运算逻辑需要等待显示器提供Vsync的信号才能继续进行. 这也是我们运行一个什么都不做的空例子却只有60帧的原因, 60便源于屏幕的刷新率. )
  所以等待fence以及等待垂直同步Vsync导致了FrameElapse和EngineElapse的增长幅度存在差异. eglSwapBuffers等待时间变短中和了EngineElapse的增长.