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

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

这是我发现的:

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

我真的不明白为什么会发生这种情况,首先,为什么当onDrawFrame不执行任何操作时,它为什么被称为“缓慢”?更重要的是,为什么任何GL调用(一个简单的四边形)仍然使两者之间的时间间隔onDrawFrame调用的时间长于16.667ms(尽管不那么频繁)。

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

所以......

我正在尝试修复游戏循环并消除这些“结结巴结”-需要注意的其他事项:

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

  • 我显然误会了一些东西,因此朝正确方向的插入将不胜感激。

    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();
    }
    

    上面的这个游戏循环就是这个出色的article的特色。

    最佳答案

    一些想法:

  • 不要使用System.currentTimeMillis()计时。它基于挂钟,可以通过网络进行更新。使用基于单调时钟的System.nanoTime()
  • 有关游戏循环的一些说明,请参见this appendix。队列填充在很多方面都可以,但是要了解您并不是完全在VSYNC上工作,因此时序往往不准确。
  • 一些设备(尤其是基于qcom SOC的设备)在认为自己处于空闲状态时会降低CPU速度。始终在主动在触摸屏上移动手指的同时进行计时。
  • 如果要调试帧速率问题,则需要使用systrace。在此,traceview概要分析不是那么有用。

  • 请参阅Grafika's“记录GL应用程序” Activity ,以获取一个简单的GLES应用程序的示例,该应用程序会丢帧,但会调整动画以使其很少引起注意。

    关于android - Android:了解OnDrawFrame,FPS和VSync(OpenGL ES 2.0),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38512936/

    10-10 01:51