Performance Tips

Mobile

Modern desktop computers are very powerful. Generally the main problem with performance is getting your game to run well on mobiles and tablets. It's more difficult to get good performance on these devices because they often have much weaker hardware: slower CPUs, slower graphics chips, and less memory - often by a factor of 10 or more compared to a desktop computer.

You must test on mobile from the start. Since your computer may be well over ten times faster than your mobile device, you may inadvertently design a game that has no hope of running well on a mobile device and not find out until later. To avoid surprises test regularly on the intended device to make sure it is still running fast enough. The Preview on LAN feature can make this quick and easy. You should aim to design simpler games for mobile devices to match their lower speed and resources.

The following tips can help you achieve best performance for mobile devices:

  1. Make sure WebGL is enabled, since on devices that support it, it usually significantly improves performance.
  2. Avoid using too many objects or particles, since mobile devices have lower limits to what desktop computers can handle.
  3. Place objects using the same blend modes or effects on the same layer. For example, if you have a lot of objects using the Additive blend mode (commonly used for explosions, lasers and other effects), make sure all those objects are placed on their own layer. Also make sure they are created on that layer if the objects are spawned or created at runtime. Switching between effects can reduce performance, and doing this will ensures all objects using the same effect are drawn at the same time. This is described in more detail in the blog post How the Construct 2 WebGL renderer works.
  4. Avoid objects with large areas of transparency. Transparent pixels still take up rendering time, even though they do not visually appear. Crop all images you use to remove wasteful transparent space. (Shift+Crop in the animation editor will crop the entire animation.) Splitting up large objects with large transparent areas in to a series of smaller objects can also increase the rendering performance and save memory. For example, adding a window border using a screen-sized transparent sprite with borders drawn at the edges will perform poorly as it still has to fill a large transparent area in the middle; splitting it in to four separate objects for each edge is much more efficient.
  5. Avoid large areas of overlap between objects. The renderer works back-to-front, and if objects have a lot of overlap, the overlapped area will have the pixels rendered to over and over again. This can use up the fill rate capacity of a mobile GPU pretty quickly.
  6. If you have an opaque background, set Clear background to No in Project Properties. This avoids redundantly clearing the entire screen every frame when it would be cleared anyway by rendering the opaque background.

Common causes of poor performance

Some of the most common things causing slowdowns are listed below. This list is not exhaustive. There may be other reasons your game is running slowly not listed here.

No hardware acceleration
Usually even the slower Canvas 2D renderer is still hardware accelerated by the GPU (Graphics Processing Unit). However some devices have unstable graphics drivers and browser makers turn off the use of the GPU to avoid crashes (referred to as "GPU blacklisting"). On very old devices GPU acceleration may simply not be supported. See the section below on Identifying GPU blacklisting in Chrome below for more information.

Changing Text objects every tick
Change the size or text of a Text object every tick - even just for an animation or transition - will likely produce poor performance, especially on mobile devices. The problem is even worse if the text object is large. Text rendering is very fast as long as the object is not changing, but upon changing the object must do a relatively expensive redraw of the text and replacement of the cached texture. Try to use small Text objects that do not change regularly. If you must change text regularly, consider using a Sprite Font instead, which is fast even when it changes every tick.

Inappropriate usage of the Tilemap object
It is not appropriate to use the Tilemap object to display large images. The tilemap object draws tile-by-tile, but can optimise if there are areas of the same tile. This is described in the blog post Tilemap tidbits. If you paste a large image in to the Tilemap object, and then stamp a grid of tiles to display the large image, every tile is different. Therefore no optimisation is possible, and a draw call must be issued for each tile. If the image needs a 10x10 grid of tiles to display, then it will need to issue 100 draw calls. A single sprite or Tiled Background, by comparison, takes a single draw call each. Therefore this type of use of the Tilemap object can be hundreds of times less efficient than using another object. The Tilemap object should only be used for tile based games, where a single tile is a useful level design block by itself, rather than part of a larger image.

Too many objects using Physics
The Physics behavior is very CPU intensive. Using too many objects with the Physics behavior can cause considerable slowdown. You should design your games to use a few large Physics objects rather than many small Physics objects.

Creating too many objects
While modern computers are very fast, they still have a limited processing capacity. Creating over 1000 objects will probably cause your game to slow down. Try to design your game to use fewer objects. The system expression objectcount can tell you how many objects you are using.

Using too many effects
Effects are visually impressive, but can slow down the game's performance considerably if over-used, especially on mobile. Using an effect on objects with many instances is especially slow - often it is much more efficient to place all the objects with the effect on their own layer, then apply the effect to that layer instead. This allows the effect to process everything in one go, rather than having to inefficiently re-run the effect for a small object over and over again. Some effects also have more performance impact than others: blurs and glows tend to be the slowest, distortion having a medium impact, and the color blends (like multiply and screen) being the easiest for the GPU to process.

Unnecessary use of effects
Never use effects to process a static effect on an object. For example, do not use the 'Grayscale' effect to make an object always appear grayscale. This will degrade performance when you could simply import a grayscale image to the object and not use any effects at all.

Using too many particles
The Particles object can easily create hundreds of particles. Each particle is like a sprite, so it can rapidly use up available processing power. Avoid using more than a couple of hundred particles if possible - generally the lower the particle rate you can set, the better. Use the ParticleCount expression to help count how many particles you have created.

Using Sprites instead of Tiled Backgrounds
Creating too many objects can cause slowdowns, and a common mistake is to use grids of Sprite objects instead of Tiled Background objects. This is similar to using tilemaps inappropriately. For example, a 20x20 grid of sprites has 400 objects, which is a significant impact on the object count. A single tiled background can replace the grid of sprites and it only counts as a single object. Tiled backgrounds are specially optimised for repeating their texture so in this case it is literally 400 times more efficient than the grid of sprites. Always use Tiled Backgrounds instead of repeating Sprites wherever possible.

Not placing all used objects in the layout
If objects are not placed in a layout but are created by events, Construct 2 will load the textures for those objects the moment you create them. This can cause a momentary pause or "jank" and make the game feel less responsive. This can be avoided by placing any used objects in the layout. They can be placed off-screen and destroyed on startup to avoid interfering with the gameplay. Then Construct 2 will preload all their textures when the layout starts, avoiding any "jank" as they are created and destroyed at runtime.

Using too many loops
This is rarer, but using too many loops like For, For Each and Repeat can cause the game to slow down. Nested loops are especially likely to cause this. To test if this is the problem, try temporarily disabling the looping events.

Common misconceptions

The following things are often accused of affecting performance (as in, the framerate at runtime), but probably have little or no effect:

Off-screen objects are not still rendered. Construct 2 does not issue draw calls for objects that do not appear in the window, and the GPU is also smart enough to know not to render any content that appears outside the window - even when a single image is only partially on-screen.

Image formats (e.g. JPEG, PNG-8, PNG-32) affect the download size but have no effect on runtime performance or memory use (they are all decompressed to 32-bit bitmap on startup).

Audio formats also only affect the download size but have no effect on runtime performance.

Number of layers usually has no effect, unless most of the layers have changed their opacity, have effects applied, have a blend mode other than 'Normal', or use 'force own texture'. However typically there is no performance impact from using multiple layers with default settings.

Number of layouts also is unlikely to have any effect other than the download size. The layout size also does not have any direct effect; larger layouts do not use more memory or require more processing, unless you use more objects.

Angle or opacity of sprites/tiled backgrounds and floating-point positions (e.g. positioning a sprite at X = 10.5) generally has no effect, since modern graphics chips are very good at handling this, even on mobiles. Very large sprites can still slow down mobile devices, but on desktop they can often still be rendered just as fast as smaller sprites.

More advice

For more information and advice on performance, see the blog post Optimisation: don't waste your time. There are also some useful tips about keeping your events efficient in the blog post Common mis-used events and gotchas.

Measuring and testing performance

From the start of your project you should use a framerate indicator and keep an eye on performance, particularly testing regularly on mobile devices. This allows you to notice if a particular change you have made has seriously affected performance on a weaker device than your desktop development machine.

Test your project on as many devices and browsers as possible.

If you think something is causing performance problems in your project, it is usually easy to test the theory: back up your project, delete the thing in question, and see if the framerate has improved. If it improves, the thing you deleted was the cause; if not, it must be something else. Alternatively use the profiler tab of the debugger to see if a disproportionate amount of CPU time is being spent in one area of the game.

Always measure performance. Computer systems are highly complex, and there are many unexpected or counter-intuitive results in performance. The only way to know what effect something has on performance is to measure it. If you cannot measure a difference, it probably has no serious effect on performance.

How to measure performance

The best way to see a breakdown of which parts of the game are using CPU time is to look at the Profiler tab of the debugger. If the game is bottlenecked on CPU logic and not GPU rendering, then this should help you quickly identify the part of the project that is using the most CPU time.

There are three system expressions that are also important for indicating performance:

fps - returns the current frames per second rate. Usually the top speed is 60 frames per second, but it can change depending on the system.

cpuutilisation - returns the current estimated utilisation of the Javascript main thread. This is an approximation of how much of the available CPU time for Javascript processing is used. It ranges from 0 to 1, so the expression round(cpuutilisation * 100) will return a percentage. Despite the name this does not report the overall system CPU usage, and can be inaccurate since it's an estimation made from timing measurements in Javascript, so don't rely too heavily on it.

renderer - returns either canvas2d or webgl depending on the renderer in use. The WebGL renderer is usually significantly faster than Canvas2D, but only if the browser supports it and has not blacklisted the GPU. For more information see the Technology section.

You can create an in-game display of these values with a Text object to keep an eye on performance while testing your game, using an action to update it Every tick:

Set text to fps & " FPS, " & round(cpuutilisation * 100) & "% CPU (" & renderer & ")"

This will display a string like 60 FPS, 30% CPU (webgl) indicating the framerate, approximate CPU time and renderer.

Identifying GPU blacklisting in Chrome

One of the most common causes of poor performance is the GPU support being turned off due to unstable drivers. This causes the game to revert to software rendering, which can cripple performance on low-end devices. The Google Chrome browser provides some diagnostics you can use to check for this on Windows, Mac, Linux and Android devices.

Hardware acceleration status

To view which features are hardware accelerated in Chrome, visit chrome://gpu via the address bar. Under Graphics Feature Status you should be able to see whether Canvas (the canvas2d renderer) and WebGL are hardware accelerated. It should say Hardware accelerated in green if so, otherwise Software only or a similar message about hardware acceleration being disabled in orange or red.

Hardware-accelerated WebGL will provide best performance. If WebGL is not hardware accelerated but Canvas is, performance should still be good. If not even Canvas is hardware accelerated, performance will likely be poor on that device.

Note browser makers maintain their blacklists separately. Just because Chrome isn't using hardware acceleration doesn't mean other browsers will follow suit. Switching to an alternative like Firefox can provide better performance if it can use GPU acceleration.

Forcing hardware acceleration enabled

If a device cannot use hardware acceleration, it's possible to force it enabled to test the full performance capability of the device's hardware. Note however that browser makers usually blacklist devices for a good reason, and forcing it enabled can result in crashes, hangs, or even device lockups (which on mobile mean you must remove and replace the battery to reset it).

To force hardware acceleration enabled in Chrome, visit chrome://flags via the address bar. Near the top should be an item called Override software rendering list. Press Enable. Note that your changes will not take effect until you press the Relaunch now button that appears at the bottom of the screen after changing the option.

After relaunching, the device should be able to make full use of GPU acceleration, including with WebGL support. This allows you to test the realistic hardware capabilities of the device without suffering poor performance due to the blacklist.

Tags: