我在我的Android游戏中经常会遇到精灵卡顿的问题。这是一个相当简单的2D OpenGL ES 2.0游戏。(这是一个我已经多次重复访问的持续性问题)。
在我的游戏循环中,我有两个“计时器” - 一个将记录上一秒钟的帧数,另一个将计算从当前onDrawFrame迭代结束到下一个迭代开始的时间(以毫秒为单位)。
这是我找到的东西:
当没有渲染任何东西时,我得到60 fps(在大多数情况下),每次调用onDrawFrame时,它都报告自己花费了超过16.667ms的时间。现在,如果我渲染一些东西(无论是1个四边形还是100个四边形,结果都是相同的),我可以得到60fps(在大多数情况下),但现在只有约20%的onDrawFrame调用报告自己与上次调用相比需要超过16.667ms的时间。
我真的不明白为什么会发生这种情况,首先,为什么当onDrawFrame什么都不做时,它被称为“缓慢” - 更重要的是,为什么任何GL调用(一个简单的四边形)仍然会导致onDrawFrame调用之间的时间超过16.667ms(虽然发生得不那么频繁)。
我应该说,当onDrawFrame报告从上一次迭代花费超过16.667ms的时间时,它几乎总是伴随着FPS下降(到58或59),但并非每次都是如此。反之亦然,有时候FPS下降时,onDrawFrame会在上一个迭代完成后的16.667毫秒内调用。
所以......
我正在尝试修复我的游戏循环并消除这些“卡顿”-还要注意以下几点:
当我进行方法分析时,它显示glSwapBuffers有时需要很长时间
当我进行GL跟踪时,大多数情况下,它说在不到1ms的时间内呈现场景,但有时候奇怪的帧需要3.5-4ms-相同的场景。没有改变除了花费的时间之外。
每次丢失一帧或onDrawFrame报告长时间延迟(或两者均有)时,几乎都会出现视觉故障,但不是每次。大的视觉故障似乎与多个“延迟”的onDrawFrame调用和/或丢帧同时发生。
我认为这不是一个场景复杂性问题,原因有两个:1)即使我渲染场景两次,它也不会使问题变得更糟,我仍然在大多数情况下得到60FPS,只是偶尔会有一些掉帧,就像以前一样。2)即使我把场景剥离出来,我仍然会遇到问题。
显然,我误解了某些东西,所以需要指点迷津。
在我的游戏循环中,我有两个“计时器” - 一个将记录上一秒钟的帧数,另一个将计算从当前onDrawFrame迭代结束到下一个迭代开始的时间(以毫秒为单位)。
这是我找到的东西:
当没有渲染任何东西时,我得到60 fps(在大多数情况下),每次调用onDrawFrame时,它都报告自己花费了超过16.667ms的时间。现在,如果我渲染一些东西(无论是1个四边形还是100个四边形,结果都是相同的),我可以得到60fps(在大多数情况下),但现在只有约20%的onDrawFrame调用报告自己与上次调用相比需要超过16.667ms的时间。
我真的不明白为什么会发生这种情况,首先,为什么当onDrawFrame什么都不做时,它被称为“缓慢” - 更重要的是,为什么任何GL调用(一个简单的四边形)仍然会导致onDrawFrame调用之间的时间超过16.667ms(虽然发生得不那么频繁)。
我应该说,当onDrawFrame报告从上一次迭代花费超过16.667ms的时间时,它几乎总是伴随着FPS下降(到58或59),但并非每次都是如此。反之亦然,有时候FPS下降时,onDrawFrame会在上一个迭代完成后的16.667毫秒内调用。
所以......
我正在尝试修复我的游戏循环并消除这些“卡顿”-还要注意以下几点:
当我进行方法分析时,它显示glSwapBuffers有时需要很长时间
当我进行GL跟踪时,大多数情况下,它说在不到1ms的时间内呈现场景,但有时候奇怪的帧需要3.5-4ms-相同的场景。没有改变除了花费的时间之外。
每次丢失一帧或onDrawFrame报告长时间延迟(或两者均有)时,几乎都会出现视觉故障,但不是每次。大的视觉故障似乎与多个“延迟”的onDrawFrame调用和/或丢帧同时发生。
我认为这不是一个场景复杂性问题,原因有两个:1)即使我渲染场景两次,它也不会使问题变得更糟,我仍然在大多数情况下得到60FPS,只是偶尔会有一些掉帧,就像以前一样。2)即使我把场景剥离出来,我仍然会遇到问题。
显然,我误解了某些东西,所以需要指点迷津。
@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();
}
上面的游戏循环是在这篇优秀的文章中介绍的。
onDrawFrame()
开始时间进行相当好的处理,但正如我的答案链接文章中提到的那样,它是基于队列反压而不是VSYNC,因此会有些变化。话虽如此,我在Android Breakout(https://github.com/fadden/android-breakout)中使用了`onDrawFrame()`时间,看起来很好。 - fadden