Некоторое время я испытывал периодическое «заикание» спрайтов, которые находятся в движении в моей игре для Android. Это очень простая 2D-игра OpenGL ES 2.0. (Это постоянная проблема, к которой я возвращался много раз).
В моем игровом цикле у меня есть 2 «таймера» — один, который будет регистрировать количество кадров за предыдущую секунду, а другой, который подсчитывает время (в миллисекундах) от конца текущей итерации onDrawFrame до начала следующей.
Вот что я нашел:
Когда ничего не рендерится, я получаю 60 кадров в секунду (по большей части), и каждый раз, когда вызывается onDrawFrame, он сообщает, что занимает больше 16,667 мс. Теперь, если я что-то визуализирую (неважно, 1 квадрат или 100 квадратов, результат тот же), я получаю 60 кадров в секунду (по большей части), но теперь только около 20% вызовов onDrawFrame сообщают о том, что они занимают больше времени. чем 16,667 мс от последнего вызова.
Я действительно не понимаю, почему это происходит, во-первых, почему, когда onDrawFrame ничего не делает, он называется так "медленно" - и, что более важно, почему любой вызов GL (один простой quad), все еще делает время между onDrawFrame вызывает дольше 16,667 мс (хотя и гораздо реже).
Я должен сказать, что когда onDrawFrame сообщает о том, что прошло больше 16,667 мс с последней итерации, это почти всегда сопровождается падением FPS (до 58 или 59), но не всегда, иногда FPS остается постоянным. И наоборот, иногда, когда FPS падает, onDrawFrame вызывается в течение 16,667 мс после завершения последней итерации.
So......
Я пытаюсь исправить свой игровой цикл и устранить эти «заикания» — еще несколько вещей, на которые следует обратить внимание:
- Когда я выполняю профилирование метода, он показывает glSwapBuffers, что иногда занимает много времени.
- Когда я делаю GL Trace, большинство сцен, по его словам, рендерятся менее чем за 1 мс, но иногда нечетный кадр занимает 3,5-4 мс - та же сцена. Ничего не меняется, кроме времени, которое требуется
- Почти каждый раз, когда кадр пропускается или onDrawFrame сообщает о большой задержке (или и то, и другое), возникает визуальный сбой, но не каждый раз. Большие визуальные сбои, по-видимому, совпадают с многочисленными «отложенными» вызовами onDrawFrame и/или пропущенными кадрами.
- Я не думаю, что это проблема сложности сцены по двум причинам: 1) даже если я рендерю свою сцену дважды, это не усугубляет проблему, я по-прежнему по большей части получаю 60 кадров в секунду со случайным падением, просто как и раньше и 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();
}
Этот игровой цикл описан в отличной статье.
if (frameTime > 0.25)
на самом деле влияет только на операторframeTime = 0.25;
, однако ваш отступ предполагает обратное. - person c.s.   schedule 30.07.2016onDrawFrame()
, но, как упоминалось в статье, связанной с моим ответом, это основано на обратном давлении очереди, а не на VSYNC, и будет немного отличаться. Тем не менее, я использовалonDrawFrame()
раза в Android Breakout (github.com/fadden/android-breakout ) и выглядело нормально. - person fadden   schedule 31.07.2016onDrawFrame
вызовами и фактически от конца одного кадра до начала следующего. Чтобы эта продолжительность составляла 1/60, ваш код не должен занимать нулевое время. Если ваш код занимает ненулевое время, это значение всегда должно быть ‹ 1/60. Тот факт, что вы наблюдаете большие значения (насколько именно большие?), означает, что система просто задерживает вызов вашего кода, а не то, что ваш кадр работает медленно. Ожидается, что некоторые кадры будут занимать больше времени (например, первый кадр, отрисованный GL, кажется медленнее), но я ожидаю, что сбой, вероятно, будет связан с неправильной интеграцией. - person c.s.   schedule 31.07.2016