Cómo limitar framerate cuando se utiliza GLSurfaceView.RENDERMODE_CONTINUOUSLY de Android?

Tengo un juego de C ++ corriendo a través de JNI en Android. La velocidad de fotogramas varía de unos 20-45 fps debido a la complejidad de la escena. Cualquier cosa por encima de 30fps es tonto para el juego; Es sólo la quema de la batería. Me gustaría limitar la velocidad de fotogramas a 30 fps.

  • Podría cambiar a RENDERMODE_WHEN_DIRTY, y utilizar un temporizador o ScheduledThreadPoolExecutor a requestRender (). Pero eso agrega un lío entero de piezas móviles adicionales que pudieron o no pudieron trabajar constantemente y correctamente.
  • Intenté inyectar Thread.sleep () cuando las cosas están funcionando rápidamente, pero esto no parece trabajar en absoluto para los valores de tiempo pequeños. Y es posible que sólo esté respaldando eventos en la cola de todos modos, no deteniéndose en realidad.

¿Existe un método de "capFramerate ()" que se oculta en la API? Cualquier forma fiable de hacer esto?

La solución de Mark es casi buena, pero no totalmente correcta. El problema es que el swap en sí toma una cantidad considerable de tiempo (especialmente si el controlador de vídeo está almacenando en caché las instrucciones). Por lo tanto, tiene que tener en cuenta o terminará con una velocidad de fotogramas inferior a la deseada. Así que la cosa debe ser:

En algún lugar al comienzo (como el constructor):

startTime = System.currentTimeMillis(); 

Luego en el bucle render:

 public void onDrawFrame(GL10 gl) { endTime = System.currentTimeMillis(); dt = endTime - startTime; if (dt < 33) Thread.Sleep(33 - dt); startTime = System.currentTimeMillis(); UpdateGame(dt); RenderGame(gl); } 

De esta manera tendrá en cuenta el tiempo que tarda en intercambiar los búferes y el tiempo para dibujar el marco.

Cuando se utiliza GLSurfaceView, se realiza el dibujo en OnDrawFrame de su procesador que se maneja en un hilo independiente por el GLSurfaceView. Simplemente asegúrese de que cada llamada a onDrawFrame toma (1000 / [frames]) milisegundos, en su caso algo como 33ms.

Para hacer esto: (en su onDrawFrame)

  1. Mida la hora actual antes de empezar a dibujar utilizando System.currentTimeMillis (vamos a llamar startTime)
  2. Realizar el dibujo
  3. Medir de nuevo el tiempo (Vamos a llamarlo endTime)
  4. DeltaT = endTime – starTime
  5. Si el deltaT <33, el sueño (33-deltaT)

Eso es.

Respuesta de Fili se veía muy bien para mí, mal tristemente limitado el FPS en mi dispositivo Android a 25 FPS, a pesar de que pidió 30. Me di cuenta de que Thread.sleep() funciona con bastante precisión y duerme más de lo que debería.

Encontré esta implementación del proyecto LWJGL para hacer el trabajo: https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/opengl/Sync.java

La solución de Fili está fallando para algunas personas, así que sospecho que está durmiendo hasta inmediatamente después de la próxima vsync en lugar de inmediatamente antes. También siento que mover el sueño hasta el final de la función daría mejores resultados, porque allí puede rellenar el fotograma actual antes del siguiente vsync, en lugar de intentar compensar el anterior. Thread.sleep () es inexacto, pero afortunadamente solo necesitamos que sea preciso al periodo vsync más cercano de 1 / 60s. El código de LWJGL tyrondis publicado un enlace a parece demasiado complicado para esta situación, probablemente está diseñado para cuando vsync está deshabilitado o no disponible, lo que no debería ser el caso en el contexto de esta pregunta.

Yo intentaría algo como esto:

 private long lastTick = System.currentTimeMillis(); public void onDrawFrame(GL10 gl) { UpdateGame(dt); RenderGame(gl); // Subtract 10 from the desired period of 33ms to make generous // allowance for overhead and inaccuracy; vsync will take up the slack long nextTick = lastTick + 23; long now; while ((now = System.currentTimeMillis()) < nextTick) Thread.sleep(nextTick - now); lastTick = now; } 

También puede intentar reducir la prioridad del hilo de onSurfaceCreated ():

 Process.setThreadPriority(Process.THREAD_PRIORITY_LESS_FAVORABLE); 
  • Programación de gráficos Android 2D
  • Android: GLES20: Se llama API OpenGL ES no implementada
  • Android ejecuta OpenGL ES 1.1 o 1.0?
  • Nunca obtuvo 480 * 800 total cuando se utiliza la proyección ortogonal 2D en opengl-es
  • Previsualización y procesamiento simultáneo de la cámara
  • XML FrameLayout ha bajado mi framerate OpenGL SurfaceView (fps)
  • Necesita ayuda para OpenGL de Android
  • ¿Cuál sería un método para crear un contador de números en Android?
  • Conversión de GLSurfaceView a TextureView (a través de GLTextureView)
  • Android: Limpiar correctamente después de OpenGL
  • ¿Cómo dibujo una malla wireframe con líneas ocultas eliminadas en OpenGL ES?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.