3

I'm developing an android game and I'm using SurfaceView. I have a method that will be called every 16ms (I want to have 60fps)

public void myDraw(SurfaceHolder holder) {
    Canvas c = null;
    long start = System.currentMillis();    
    try {
        synchronized(holder) {
            c = holder.lockCanvas();
            if (c != null) {
                c.drawColor(Color.GREEN);
            }    
        }
    } finally {
        if (c != null) {
            holder.unlockCanvas(c);
        }
    }
    Log.i(TAG, "total time:" + (System.currentMillis() - start));
}

When I run my app, the output from LogCat is:

total time:30
total time:23
total time:6
total time:39
total time:17

Why does the lock/unlock of canvas takes too much time? Are there any better approach to my problem? (that is, to have a 60 fps app)

Thanks!

racumin
  • 69
  • 1
  • 7

2 Answers2

6

I had a similar FPS issue with low FPS on the Samsung Intercept. I was getting only 12FPS with nothing more than a blank screen. I found that the issue was related to Android doing auto-scaling on the canvas and draw functions. In the AndroidManifest.xml if you add the line

<supports-screens android:anyDensity="true">

then Android won't auto-scale the canvas and draw functions. The default is "false" which will enable auto-scaling. With android:anyDensity="true" I was able to get 40+ FPS! The downside to all this is that you now have to do all of the math yourself to match the different screen sizes out there. But that should not be that hard. Hope this helps anyone with similar problems. It took me 5+ hours to figure this little bugger out.

Andro Selva
  • 53,910
  • 52
  • 193
  • 240
0

In my understanding, a lockCanvas() might be very expensive, depending on the underlying HW implementation.

The goal is to provide you with a buffer you have direct access to. This buffer can exist directly within the graphics hardware or it can be an OpenGL texture or something else.

Now if you call lockCanvas() the system must provide you with a buffer to that data, which might involve data transfer from GPU to memory and also an image format conversion (e.g. yuv to rgb).

Once you are finished editing you data buffer, the operation must be communicated the other way around, back to the original HW dependent format.

All of this can be quite expensive, especially on a mobile device :(

A good way to avoid is is to modify the data using API functions (drawRect() instead of copyRect()) but it's not always possible.

KPK
  • 467
  • 3
  • 9