Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit framerate when using Android's GLSurfaceView.RENDERMODE_CONTINUOUSLY?

Tags:

I have a C++ game running through JNI in Android. The frame rate varies from about 20-45fps due to scene complexity. Anything above 30fps is silly for the game; it's just burning battery. I'd like to limit the frame rate to 30 fps.

  • I could switch to RENDERMODE_WHEN_DIRTY, and use a Timer or ScheduledThreadPoolExecutor to requestRender(). But that adds a whole mess of extra moving parts that might or might not work consistently and correctly.
  • I tried injecting Thread.sleep() when things are running quickly, but this doesn't seem to work at all for small time values. And it may just be backing events into the queue anyway, not actually pausing.

Is there a "capFramerate()" method hiding in the API? Any reliable way to do this?

like image 707
grinliz Avatar asked Jan 23 '11 07:01

grinliz


2 Answers

The solution from Mark is almost good, but not entirely correct. The problem is that the swap itself takes a considerable amount of time (especially if the video driver is caching instructions). Therefore you have to take that into account or you'll end with a lower frame rate than desired. So the thing should be:

somewhere at the start (like the constructor):

startTime = System.currentTimeMillis(); 

then in the render loop:

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

This way you will take into account the time it takes to swap the buffers and the time to draw the frame.

like image 80
Fili Avatar answered Sep 28 '22 07:09

Fili


When using GLSurfaceView, you perform the drawing in your Renderer's onDrawFrame which is handled in a separate thread by the GLSurfaceView. Simply make sure that each call to onDrawFrame takes (1000/[frames]) milliseconds, in your case something like 33ms.

To do this: (in your onDrawFrame)

  1. Measure the current time before your start drawing using System.currentTimeMillis (Let's call it startTime)
  2. Perform the drawing
  3. Measure time again (Let's call it endTime)
  4. deltaT = endTime - starTime
  5. if deltaT < 33, sleep (33-deltaT)

That's it.

like image 39
Lior Avatar answered Sep 28 '22 09:09

Lior