Search code examples
androidopengl-essurfaceviewframe-rate

The slower FPS on the faster Android devices


I use SurfaceView for my 2D Android game which I have almost completed. It's based on JBox2D. It is perfectly running on Samsung Galaxy S2, its FPS is 60. It is also running smoothly on HTC Explorer, its FPS is about 54. I thought that if my game was working well in these relatively old devices, it would be working better in the newer ones. But I was wrong! I saw yesterday the FPS value of my game on Galaxy Note 4 is varied between 22 and 45 depending on the number of game objects.

After investigating on this issue in Google and StackOverflow, I deduced that the new devices like Galaxy Note 4 which has higher resolutions (1440 x 2560) could not handle with their large images whereas the little ones can handle with their own smaller images (Galaxy s2:480 x 800, HTC Explorer:320 x 480). Yes, the new devices are surely faster than the older ones, but I think their huge resolutions of the newer devices are the reason of the slowness on the SurfaceView. Of course, this is valid under SurfaceView conditions. If I used OpenGL for my game, it would not be a problem for the new devices having high resolutions.

My bitmaps are designed for 800 x 1280 devices. According to the different device resolutions, my game rescales the images when they are loaded at the beginning of the each level by using createScaledBitmap.

I couldn't transform my game from SurfaceView to OpenGL platform because my game is about to finish and I didn't have enough knowledge about OpenGL.

What should I do?


Solution

  • I believe you have correctly identified the problem: newer devices have pixel counts like you'd find on a 27" monitor (2560x1440), because the manufacturers are chasing screen resolution like they do camera megapixels. The result is that rendering a full screen takes longer, especially when you're doing it in software. Faster CPUs and increased bus bandwidth can help, but full-screen software rendering is problematic.

    The solution for Android is to make the Surface smaller, and let the hardware scale it up as it's being scanned out. This is significantly easier (and more efficient) than scaling up each individual item. You do this with the SurfaceHolder#setFixedSize() method. For example, for a 2560x1440 display, you could set the Surface size to 1280x720, and only render a quarter of the pixels. The display performs the pixel doubling (with bilinear filtering).

    You can find a blog post here, and can see this in action in Grafika's "hardware scaler exerciser" activity (youtube demo video).

    The various examples use GLES -- which also benefits from having fewer pixels to fill -- but applies to Canvas rendering as well.