Android:了解OnDrawFrame,FPS和VSync(OpenGL ES 2.0) [英] Android: Understanding OnDrawFrame, FPS and VSync (OpenGL ES 2.0)

查看:308
本文介绍了Android:了解OnDrawFrame,FPS和VSync(OpenGL ES 2.0)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一段时间以来,我经历了Android游戏中运动的小精灵的间歇性停顿".这是一个非常简单的2D OpenGL ES 2.0游戏. (这是一个持续存在的问题,我已经多次访问过.)

For a while now I've experienced an intermittent 'stuttering' of the sprites that are in motion within my Android Game. It's a fiarly simple 2D OpenGL ES 2.0 game. (This is an ongoing problem which I have re-visited many times).

在我的游戏循环中,我有2个计时器"-一个将记录前一秒的帧数,另一个记录从当前onDrawFrame迭代结束到开始的时间(以毫秒为单位).下一个.

In my game loop, I have 2 'timers' - one which will log the number of frames in the previous second, and another which counts the time (in Milliseconds) from the end of the current onDrawFrame iteration to the start of the next.

这是我发现的东西:

当不渲染任何东西时,我得到60fps(大部分情况下),并且每次调用onDrawFrame时,它报告自己花费的时间都长于16.667ms.现在,如果我渲染某些东西(不管是1个四边形还是100个四边形,结果都是一样的),我将获得60fps(大部分情况下),但是现在,只有大约20%的onDrawFrame调用将自己报告为花费更长的时间比上次通话时间长16.667毫秒.

When not rendering anything, I get 60fps (for the most part), and every time onDrawFrame is called, it reports itself as taking longer that 16.667ms. Now, If I render something (doesn't matter if it's 1 quad or 100 quads, the result is the same), I get 60fps (for the most part) but now, only about 20% of onDrawFrame calls report themselves as taking longer than 16.667ms from the last call.

我真的不明白为什么会发生这种情况,首先,为什么当onDrawFrame不执行任何操作时,它为什么被称为缓慢"-更重要的是,为什么任何GL调用(一个简单的四边形)仍然使两次onDrawFrame调用之间的时间超过16.667毫秒(尽管不那么频繁).

I don't really understand why this happens, firstly, why, when onDrawFrame isn't doing anything, is it called so 'slowly' - and more importantly, why does any GL call (one simple quad), still make the time between onDrawFrame calls longer than 16.667ms (albeit much less frequently).

我应该说,当onDrawFrame报告从上次迭代开始花费的时间超过16.667ms时,几乎总是伴随着FPS的下降(降至58或59),但并非始终如此,有时FPS保持不变.相反,有时,当FPS下降时,在最后一次迭代完成后的16.667毫秒内调用onDrawFrame.

I should say that when onDrawFrame reports taking longer than 16.667ms from the last iteration, it is almost always accompanied by a drop in FPS (to 58 or 59), but not all of the time, sometimes, the FPS stays constant. And conversely, sometimes when the FPS drops, onDrawFrame is called within 16.667ms of the last iteration completing.

所以......

我正在尝试修复游戏循环并消除这些口吃"-需要注意的其他事项:

I'm trying to fix my game-loop and eradicate these 'stutters' - some other things to note:

  • 当我进行方法分析时,它会显示glSwapBuffers,有时会花费很长时间
  • 当我执行GL Trace时,大多数场景会在不到1ms的时间内渲染,但有时奇数帧需要3.5-4ms的时间-同一场景.除了所需的时间外,没有任何变化
  • 几乎每次丢帧或onDrawFrame报告长时间延迟(或同时发生这两种情况)时,都会出现视觉故障,但并非每次都有.较大的视觉故障似乎与多个延迟"的onDrawFrame调用和/或掉帧有关.
  • 我不认为这是一个场景复杂性问题,原因有两个:1)即使我两次渲染场景,也不会使问题变得更糟,在大多数情况下,我偶尔还是会获得60FPS就像之前和2)一样,即使我裸露场景,我仍然会遇到问题.

我显然误会了一些东西,所以朝着正确的方向前进将是值得的.

I obviously am misunderstanding something, so a push in the right direction would be appreciated.

OnDrawFrame

@Override
public void onDrawFrame(GL10 gl) {

    startTime = System.nanoTime();        
    fps++;                        
    totalTime = System.nanoTime() - timeSinceLastCalled;    

    if (totalTime > 16667000) {     
        Log.v("Logging","Time between onDrawFrame calls: " + (totalTime /(double)1000000));
    }

    //Grab time
    newTime = System.currentTimeMillis() * 0.001;
    frameTime = newTime - currentTime; //Time the last frame took

    if (frameTime > 0.25)
        frameTime = 0.25;

    currentTime = newTime;
    accumulator += frameTime;

    while (accumulator >= dt){              
      saveGameState();
      updateLogic();
      accumulator -= dt;
    }

    interpolation = (float) (accumulator / dt);

    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);

    render(interpolation);

    if (startTime > lastSecond + 1000000000) {          
        lastSecond = startTime;
        Log.v("Logging","fps: "+fps);
        fps=0;          
    }

    endTime = startTime;
    timeSinceLastCalled = System.nanoTime();        
}

上面的游戏循环是这篇出色的文章中介绍的循环.

This game loop above is the one featured in this excellent article.

推荐答案

一些想法:

  • 请勿使用System.currentTimeMillis()进行计时.它基于挂钟,可以通过网络进行更新.使用基于单调时钟的System.nanoTime().
  • 有关游戏循环的一些说明,请参见本附录.队列填充在很多方面都可以,但要了解您并不是完全在VSYNC上工作,因此时序往往不准确.
  • 某些设备(尤其是基于qcom SOC的设备)在认为自己处于空闲状态时会降低CPU速度.始终在主动在触摸屏上四处移动手指的同时进行计时.
  • 如果要调试帧速率问题,则需要使用 systrace .在这里,traceview概要分析没有太大用处.
  • Don't use System.currentTimeMillis() for timing things. It's based on the wall clock, which can be updated by the network. Use System.nanoTime(), which is based off the monotonic clock.
  • See this appendix for some notes on game loops. Queue-stuffing is fine for many things, but understand that you're not exactly working off of VSYNC, so timings will tend to be inaccurate.
  • Some devices (notably those based on qcom SOCs) reduce CPU speed when they think they're idle. Always take timings while actively moving your finger around on the touch screen.
  • If you want to debug frame rate issues you need to be using systrace. The traceview profiling isn't that useful here.

请参阅 Grafika的记录GL应用程序"活动,以了解一个简单的GLES应用程序掉帧的示例,但调整动画使其很少引起注意.

See Grafika's "record GL app" Activity for an example of a simple GLES app that drops frames, but adjusts the animation such that it's rarely noticeable.

这篇关于Android:了解OnDrawFrame,FPS和VSync(OpenGL ES 2.0)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆