如何在使用Android的GLSurfaceView.RENDERMODE_CONTINUOUSLY时限制帧率?

gri*_*liz 21 android opengl-es

我有一个在Android中运行JNI的C++游戏.由于场景复杂性,帧速率从大约20-45fps变化.任何高于30fps的东西对于游戏都是愚蠢的; 它只是燃烧电池.我想将帧速率限制为30 fps.

  • 我可以切换到RENDERMODE_WHEN_DIRTY,并使用Timer或ScheduledThreadPoolExecutor来requestRender().但这增加了一大堆额外的移动部件,这些部件可能会或可能不会始终正确地工作.
  • 当事情快速运行时,我尝试注入Thread.sleep(),但这对于小时间值似乎根本不起作用.它可能只是将事件支持到队列中,而不是实际上暂停.

是否有隐藏在API中的"capFramerate()"方法?有任何可靠的方法吗?

小智 38

Mark的解决方案几乎是好的,但并不完全正确.问题是交换本身需要相当长的时间(特别是如果视频驱动程序是缓存指令).因此,您必须考虑到这一点,否则您将以低于预期的帧速率结束.所以事情应该是:

在某个地方(如构造函数):

startTime = System.currentTimeMillis();
Run Code Online (Sandbox Code Playgroud)

然后在渲染循环中:

public void onDrawFrame(GL10 gl)
{    
    endTime = System.currentTimeMillis();
    dt = endTime - startTime;
    if (dt < 33)
        Thread.Sleep(33 - dt);
    startTime = System.currentTimeMillis();

    UpdateGame(dt);
    RenderGame(gl);
}
Run Code Online (Sandbox Code Playgroud)

这样,您将考虑交换缓冲区所需的时间和绘制帧的时间.

  • 应该是Thread.sleep()吗?用小's' (8认同)
  • 这段代码存在根本缺陷; 在结束/开始时间获取之间发生的时间会发生什么?为了防止时间泄漏,应始终将当前结束时间用作后续开始时间.这对FPS保真度和多玩家同步都有影响. (7认同)
  • @KNfLrPn:Taliadon说`startTime = System.currentTimeMillis();`错了,它应该是`startTime = endTime;`. (5认同)
  • 使用此代码,您没有恒定的FPS.在我的比赛中,我在30到20 fps之间振荡.真正的方法是EGL eglSwapInterval调用,但它没有在Android设备上实现. (4认同)

Lio*_*ior 9

使用GLSurfaceView时,在Renderer的onDrawFrame中执行绘图,该绘图由GLSurfaceView在单独的线程中处理.只需确保每次调用onDrawFrame都需要(1000/[帧])毫秒,在你的情况下需要33毫秒.

为此:(在您的onDrawFrame中)

  1. 使用System.currentTimeMillis测量开始绘图之前的当前时间(让我们称之为startTime)
  2. 执行绘图
  3. 再次测量时间(让我们称之为endTime)
  4. deltaT = endTime - starTime
  5. 如果deltaT <33,睡眠(33-deltaT)

而已.