Android: Descripción de OnDrawFrame, FPS y VSync (OpenGL ES 2.0)

Por un tiempo ahora he experimentado una intermitente "tartamudeo" de los sprites que están en movimiento dentro de mi Android Juego. Es un simple juego 2D OpenGL ES 2.0. (Este es un problema constante que he visitado muchas veces).

En mi bucle de juego, tengo 2 'temporizadores' – uno que registrará el número de fotogramas en el segundo anterior, y otro que cuenta el tiempo (en milisegundos) desde el final de la iteración onDrawFrame actual al inicio de la siguiente.

Esto es lo que he encontrado:

Cuando no estoy prestando nada, obtengo 60fps (en su mayor parte), y cada vez que se llama onDrawFrame, se informa que tarda más que 16.667ms. Ahora, si hago algo (no importa si es 1 cuádruple o 100 cuádruples, el resultado es el mismo), obtengo 60fps (en su mayor parte) pero ahora, sólo alrededor del 20% de las llamadas onDrawFrame reportan que toman más tiempo De 16.667ms desde la última llamada.

Realmente no entiendo por qué esto sucede, en primer lugar, por qué, cuando onDrawFrame no está haciendo nada, se llama así "lentamente" – y lo que es más importante, ¿por qué cualquier llamada GL (un quad simple), todavía hacer el tiempo entre OnDrawFrame llama por más de 16.667ms (aunque mucho menos frecuentemente).

Debo decir que cuando onDrawFrame reporta tomar más de 16.667ms de la última iteración, casi siempre se acompaña de una caída en FPS (a 58 o 59), pero no todo el tiempo, a veces, el FPS se mantiene constante. Y a la inversa, a veces cuando el FPS cae, onDrawFrame se llama dentro de 16.667ms de la última iteración que completa.

Asi que……

Estoy tratando de arreglar mi juego de bucle y erradicar estos 'tartamudos' – algunas otras cosas a tener en cuenta:

  • Cuando hago el método de perfiles, muestra glSwapBuffers, a veces toma mucho tiempo
  • Cuando hago un GL Trace, la mayoría de las escenas que dice se renderizan en menos de 1 ms, pero a veces el marco impar toma 3.5-4ms – la misma escena. Nada cambia aparte del tiempo que toma
  • Casi cada vez que un marco se deja caer, o onDrawFrame informa un retraso largo (o ambos), hay un fallo visual, pero no cada vez. Los fallos visuales grandes parecen coincidir con múltiples llamadas "onDrawFrame" retardadas y / o fotogramas perdidos.
  • No creo que esto sea un problema de complejidad de escena por 2 razones: 1) incluso si presento mi escena dos veces, no empeora el problema, todavía en su mayor parte, obtengo 60FPS con la caída ocasional, solo Como antes y 2), incluso si me desnudo la escena, todavía tengo el problema.

Obviamente estoy malentendido algo, por lo que un empujón en la dirección correcta sería apreciado.

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

Este lazo del juego arriba es el ofrecido en este artículo excelente.

Algunos pensamientos:

  • No utilice System.currentTimeMillis() para sincronizar las cosas. Se basa en el reloj de pared, que puede ser actualizado por la red. Utilice System.nanoTime() , que se basa en el reloj monótono.
  • Consulte este apéndice para ver algunas notas sobre los bucles de juego. Queue-relleno está bien para muchas cosas, pero entiendo que usted no está exactamente trabajando fuera de VSYNC, por lo que los tiempos tienden a ser inexactos.
  • Algunos dispositivos (sobre todo los basados ​​en SOCs qcom) reducen la velocidad de la CPU cuando piensan que están inactivos. Tome siempre los tiempos mientras mueve activamente su dedo en la pantalla táctil.
  • Si desea depurar problemas de velocidad de fotogramas, debe utilizar systrace . El perfil de traceview no es tan útil aquí.

Vea la "aplicación de registro de GL" de Grafika para ver un ejemplo de una sencilla aplicación de GLES que descarta fotogramas, pero ajusta la animación de tal manera que rara vez se nota.

  • Android MotionEvent ACTION_MOVE eficiencia. ¿Cómo mejorar el rendimiento?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.