We received a question in the forum that prompted us to write a detailed explanation of what things you should have in mind when developing games for mobile hardware.
Here’s the question by xero in our forum:
In earlier posts you mentioned to keep the number of canvases tight. However, it is a common technique in browsers to use multiple layered canvases to gain performance boost, since only some part of the content gets redrawn. What are you’re suggestions about that? Are CocoonJS canvases more expensive than browser ones? Will I benefit from having to redraw less stuff or will the overhead (memory, CPU?) of managing additional canvases by CocoonJS overweight all possible performance gains?
The first thing you must understand to develop for mobile platforms is those devices have very low performance compared to what you can expect in a modern PC. On the other hand, while most mobile browsers draw everything using the CPU, CocoonJS uses the GPU to draw shapes and images really fast, so the picture is more complex than it would initially appear. Mobile devices are slower, but we’re squeezing every last bit of performance out of them.
In this case, the performance optimization mentioned by xero is generally useful in run-off-the-mill browsers because blending several images in a canvas is pretty slow there. In CocoonJS however, image blending is done by the GPU, so it’s a lot cheaper.
The optimization does usually work, however, if you intend to draw lots of static images into a canvas, and then reuse that canvas during lots of frames. In effect, you’ll be creating a “cache” with that image to reuse it later. This can be very useful if you want to display, say, 500 objects which won’t change for a long time.
The thing is, drawing from that “cached” canvas to the final screen isn’t free either, so you must make sure the original draws are actually slower than drawing the “cache” canvas will be. For example, using a canvas to cache a simple static background probably won’t get you any performance improvement compared to just drawing the background itself.
More to the point, drawing full-screen canvases can easily exhaust what in GPU jargon is called “fill-rate”. Fill-rate, usually expressed in MPixels/s, is the speed at which a GPU can paint pixels. A mid-range GPU nowadays has about 500 MPixels/s of fill-rate. If you intend to run at 60fps, that means you get ~8.3 MPixels/frame. If your screen has a resolution of 1280 by 720 (pretty standard nowadays), each fullscreen canvas you draw takes 0.92 Mpixels of fill-rate. That means if you have 5 canvases you’re already exhausting more than half the fill-rate your GPU is capable of delivering.
Some devices have such a small fill-rate/screen-size ratio that you can only get about 2-3 fullscreen draws before you hit the GPU’s max drawing capacity. This is unfortunately a hardware limitation you’ll have to think about in your games if you want to deploy to low-power mobile devices.
So, to sum everything up, if you want to optimize your game you’re gonna have to know a bit about the hardware, test your assumptions and measure results. CocoonJS provides you with a powerful time profiling mechanism you can use to track how much CPU each part of your game is using.
In the case of the optimization mentioned by xero, how well it works will depend on how many canvases are used, how much work is saved by drawing to a canvas, how powerful is the hardware, and if fill-rate is actually the bottleneck for you! The only way to be sure is trying the technique in your game and measuring performance. Always measure!