Wrong Import Settings are Killing Your Unity Game [Part 2]

There are many things that may go wrong with your game development. Your models may have too many triangles for your target platform to handle, your algorithms may be too expensive for your CPU, and also you may be using too many materials so batching won’t work efficiently. These are difficult issues, and you as a game developer should always remember to keep good balance between visuals and performance. Yet, there are some things so simple that we often forget about their existence, but these can have a serious impact on your game performance.

Last time, in Part 1, we talked about how texture import settings can kill your game performance. This time we will talk about sound import settings and why it matters.

Audio Clip Import Settings

When working with Unity many things can keep their default settings set and everything will be working just fine. Of course, defaults are not optimal in most cases, but your game should be working OK. This rule unfortunately does not apply to Audio Clip Import Settings.

Audio Clip (sound files) importing is working very similar to texture importing. Unity supports many different audio formats, but in the end it converts them all to preferred (by the engine) format. Currently, in Unity 5.2.1 this can be PCM, ADPCM, Vorbis/MP3 and HEVAG. Note that not each platform can handle all of these compression formats, and some platforms have only one format available (e.g. WebGL can work only with AAC audio clips).

Memory matters

All Audio Clips are imported by default with “Decompress On Load” Load Type and “Vorbis” Compression Format.

These are default import settings.

These are default import settings.

You should be very careful with this setting, because using it on all your audio clips (Unity does it by default!) may consume large amount of your game’s memory! Do you see the info box on the screenshot? Original file size is computed to 35.9 MB and the imported size to 10.7 MB. This means that this Audio Clip will increase your game (archive) size by 10 megabytes, but playing it will require nearly 36 megabytes of RAM! This does not sound too scary if you’re building a game for PC where it is quite common to have 8 gigabytes of RAM, but mobile devices are still very limited on that manner.

When I should use specific Load Type?

Let’s get this straight. Each Load Type and Compression Format combination can be used and you’re the one who knows best which one should be chosen. There are three Load Types:

  • Compressed In Memory – Audio Clip will be stored in RAM and will be uncompressed when played. Does not require additional memory for playing.
  • Streaming – Audio Clip will be stored on a device persistent memory (hard drive, flash drive etc) and streamed when played. Does not require RAM for storing and playing (at least this value is not significant).
  • Decompress On Load – Audio Clip will be stored in RAM uncompressed. This option requires the most memory but playing it won’t require so much CPU power as the rest.

So, which one to use? It depends…

Music and/or Ambient Sounds

Music is stored in long Audio Clips so it can consume a lot of memory. For sure, we don’t want music to be decompressed into the memory then played. You have two options here:

  1. Use Load Type “Streaming” and Compression Format “Vorbis”. This combination will use the least amount of memory but will require some CPU power and disk I/O throughput.
  2. Use Load Type “Compressed In Memory” and Compression Format “Vorbis”. The only difference from the first solution is that it will exchange the disk I/O with some memory requirement. Note that you can adjust the Quality slider to decrease compressed clip size in exchange of sound quality. Usually 100 percent is a way too high. I would recommend something around 70 percent.

Note that if you have more than 2 music/ambient sounds clips playing like this, it can consume a serious amount of CPU power.

Sound Effects

Sounds effects are usually short or medium Audio Clips. Also these can be played frequently or rarely. Here are some rules:

  1. For frequently played and short Audio Clips use Decompress On Load and PCM or ADPCM Compression Format. When PCM is chosen, no decompression is needed and if audio clip is short it will load very quickly. You can also use ADPCM. It requires decompression, but it is much lighter to decompress than Vorbis.
  2. For frequently played but medium Audio Clips use Compressed In Memory and ADPCM Compression Format. ADPCM is around 3.5 times smaller than raw PCM and decompression algorithm will not consume as much CPU as Vorbis.
  3. For rarely played and short Audio Clips use Compressed In Memory and ADPCM. For the same reason as described in point 2.
  4. For rarely played and medium Audio Clips use Compressed In Memory  and Vorbis Compression Format. This SFX might be too long to be stored using ADPCM and played too rarely, therefore additional CPU power required to decompress wouldn’t be a such pain.

Summary

Always remember to check your Audio Clip Import Settings. These are silent performance killers of your game. Set these right, and you will get additional CPU power for things that matters.

Also please take a look at the manual for technical information about import settings.

Mobile Optimization with Unity Profiler

Mobile Optimization – Unity Profiler

In the previous Mobile Optimization series post we talked about how important the batching is. We talked about how to use Unity Profiler in order to inspect how many batches are actually made. Now we will talk a little more about the Profiler itself. If you already know about it you may learn something new!

The idea

The idea behind the Profiler is to provide as much timing, memory, and statistical information as possible. You can learn:

  • how long your game needs to compute and render a frame
  • What takes so long? (scripts, physics, graphics etc.)
  • the cause of spikes (short moments when your game fps is dropping)
  • what is generating garbage
  • how much memory the game allocates
  • and many more…

To access all this data you need to:

  1. Open the Profiler window from Windows -> Profiler main menu.
  2. Make sure that the Record button is enabled.
  3. Press the Play button and pause (or disable the Record button) when you want to analyze the collected data.

profiler record button

Note that it’s highly recommended to profile your game on target platform rather than in the Unity editor. You can do so by building a Development Build and by selecting Autoconnect Profiler in the build window. Although the second is not required, it will automatically start the profiling when the game is launched.

autoconnect profiler

Be aware that you’re required to own Android Pro or iOS Pro licenses to profile on Android or iOS platforms.

Deep look onto the Profiler Window

Let’s have a look at the Profiler window. You will learn everything that you need to know from the Unity manual, but we will now look at some part of it.

profiler window

  1. 1-3 are categories of profiling methods. There is more, but these three will be the most interesting. The first one is CPU Usage. Here you will learn the total time needed for your frame to compute and render. Times are categorized to Rendering, Scripts, Physics, etc.
  2.  Rendering category shows you information about Batches, SetPass Calls (formerly draw calls), Triangles and Vertices count.
  3. Memory category informs you about memory statistics. Be sure that your game is not consuming too much!
  4. This is CPU usage profiling section. Here you will find a lot more information about theUnity internals and your own scripts performance. This is information only about a single frame, so you have to click anywhere on the graph to select a frame. By default you’re able to expand some method calls only to level 1; enable Deep Profile (button at the bottom) to browse the script calls more deeply. Be careful with deep profiling. It requires a lot of memory and it makes your game run significantly slower.

The spikes

Let’s talk about spikes. This is usual term for situations when your game fps is significantly dropping for a split second. Why this is called a “spike”? That’s because in Profiler it looks just like a spike standing out the ground.

profiler spikes

Spikes are telling you that something caused, in this exact moment, that your frame is computed longer than usual. And you should inspect it.

 

I will list most known cause of spikes:

Garbage collector

If you know .NET platform well enough then most probably you’re aware of the garbage collector. If you don’t, imagine that all the memory that is allocated by your game at the runtime must be freed at some point, and this is also done at the runtime. This process is called garbage collection and it freezes your game until it is finished. Usually it can take only a fraction of a second, but this is more than enough to make your game feel laggy and unpleasant. The only way to target this issue is to prevent garbage collection from happening. We will look deeper into this matter in another blog post.

GameObject.Instantiate()

Instantiating objects during the game is one of the most expensive operations. When you’re instantiating an object, you are instantiating all its children including all the components. All script components requires to be properly initialized. This is easy way to generate quite a large spike.

To prevent this from happening, learn about object pooling. Simply talking you need to instantiate all possible needed objects at the beginning and hide them until needed. There are some pool scripts on the asset store that will help you handling that issue.

Scripts and expensive algorithms

Sometimes spikes will be generated by your own scripts. Maybe you’re doing too expensive operation that could be optimized or should be done in separate thread.

This kind of spikes are usually the easiest to fix, but most probably you will need to enable Deep Profile mode to make the Profiler to generate more information about your scripts performance. Many algorithms may be optimized. Those that cannot may be executed in coroutines or separate threads. Be aware that if you will decide to move your code to a separate thread, you shouldn’t call Unity API from within that thread. Instead you should use components like Dispatcher from UnityToolbag that will dispatch Unity API calls to the main thread.

Background processes and operating system itself

Sometimes you may experience spikes that are not your game’s fault. These spikes are displayed with a large amount of time assigned to Other category. This can be seen on operating systems that are allowing too many apps to run in the background (desktop operating systems or Android). This is not something that you can do about it, so kill as many background apps as possible, keep your Profiler open and observe if the spikes will go away. You can always try profiling it on a different device.

More tips

Mobile optimization is such a broad topic that it cannot be exhausted in a single blog post. Keep watching for new blog posts tagged with Mobile Optimization tag. There will be more! Next time we will talk about garbage collecting!

Wrong Import Settings are Killing Your Unity Game [Part 1]

There are many things that may go wrong with your game development. Your models may have too much triangles than your target platform can handle, your algorithms may be too expensive for your CPU, and also you may be using too many materials so batching won’t work efficiently. These are difficult issues, and you as a game developer should always remember to keep a good balance between visuals and performance. Yet, there are some things so simple that we often forget about their existence, but these can have a serious impact on your game performance.

Texture Import Settings

When you’re adding a texture into your project, the Unity works magic with it – the texture is converted to a suitable format based on current texture import settings. For most cases default settings will be good enough, but the Unity cannot tell if something looks good enough for the player so it cannot change it without your knowledge. It’s where you step in.

To access Texture Import Settings just select one or more textures that you want to change. Your inspector will look more or less like this:

texture import settings basicThere are 3 main things that you should keep an eye out.

Texture Type

texture type

Texture Type is a way to tell Unity what this texture will be used for. All this options besides Advanced will adjust your texture internal settings to be optimal as possible for the selected purpose. Note that texture of type Texture is a simple diffuse texture used in 3D space and for 3D game should be used the most. Types descriptions can be found in the official manual.

The risk: Setting the wrong texture type may be not noticeable at first and you will get a performance loss. Some types are required for shaders to work correctly (like Normal map type must be set for a texture that will be used for bump mapping).

Size

texture size and compression

This is where you can decide how big your texture should be and how it should be stored in the device memory. Noticed that there’s a Max Size instead of Size? This is simply because you can reduce all the textures resolution for your game in Quality Settings.

quality settings texture quality

Also setting the 2048 as Max Size won’t guarantee that this texture will be of that size even if Quality Settings are set to the highest. The texture resolution will be lower if your original texture file is not big enough. Knowing that, it is a good practice to prepare textures bigger than you need them to be, because you can always scale them down.

The Risk: Some models may be small on screen and those models’ textures can have large resolutions. You can identify these objects by setting your Scene shading to Mipmaps:

scene shading

Format

The texture Format is another thing that may be something confusing.

texture format

When your Texture Type is set to anything else than Advanced you will have 4 options.

  • Compressed – It trades a little of GPU power for a much lower texture size. Compressed option will use the most suitable compressing algorithm for your target platforms.
  • 16 bits – Saves the texture without a compression but it is using 16 bit color palette. Good for textures with small amount of colors.
  • Truecolor – Saves the texture using uncompressed 32 bit color palette. Looks great, but large 2048×2048 texture will require almost 17 megs of memory.
  • Crunched – Compressed using compression format suitable for the GPU and then compressed again using compression format that can be handled only by the CPU.  Good for downloadable asset bundles.

As you can see, you’re trading here texture size for texture quality. My advice is to always set the format as Compressed until you will see that something is not right with the textures in your game.

There’s one more Texture Type option that we haven’t described. If you set your Texture Type to advanced, you will gain access to many more texture formats including more compression methods. Be aware of that not all compression formats may be supported by your target platform (e.g. many Android devices have different texture compression formats support, but all should support ETC).

The Risk: Compressed textures may look ugly for some kind of textures, but textures set to 16 bits or Truecolor may take up too much space. You can find textures that are taking up to much space looking at editor.log after building your game.

You can learn more about texture compression formats here.

Verifying

texture import information

The last thing you want to do is to verify your texture import information. Here at the bottom of your texture preview you will learn about:

  • Used texture size
  • Used compression format
  • Result texture size

Keep in mind that sometimes you will need to build your game before you will see it’s target size.

Continued in Part 2 here

Side note: You may be wondering why textures sizes are power-of-two numbers. If you’re curious why, please read this discussion.

Mobile Optimization – Batching in Unity

Do you know what batching is? You may want to check out the Nvidia presentation Batch, Batch, Batch for some more details but long story short, batching the graphics data means to wrap it up into a single package and send it to the GPU in a single pass. Why does that matter to us? That’s because when we’re dealing with mobile devices we are seriously limited on how many of these packages can we send per second. And there’s something we can actually do about it!

What is batching?

What is batching? Imagine you’re doing some weekend’s shopping. You’re buying milk, bread, butter and you go to the checkout. You have just paid and the phone rings. You answer and you hear:

I’m sorry, I forgot to tell you that you need to get some eggs. Are you still in the shop?

A bit irritated, you put your things into the car’s trunk and you’re back in the shop to get the eggs. When you’re done with the checkout, you hear the phone ringing once again:

I’m really, really sorry, but can you also get some tomatoes?

OK, that what the batching is not.

When you put a mesh object into your scene, you’re saying to Unity: „Hey, draw for me a car mesh here and use this material that I gave you!” and Unity will listen. It will:

  1. Read all vertices including colors, uv, normals, tangents etc.
  2. Read the material shader, texture.
  3. Speak with the GPU: „Hey GPU, please use these vertices, this shader and those textures for the next object!”
  4. And the GPU does as told.

one car

Then you decided to put the same car mesh next to it. By doing so you’re saying to Unity: „Hey, could you draw the same car mesh with the same materials next to it?”. Unity won’t complain and it will do it too, but how exactly? Do you see that this situation is similar to previous shopping example?

How Unity knows what to batch?

Since Unity is a well designed engine, it does not start any rendering before you decide what objects should be included into the scene and what not. You can make the decision in every Update(), FixedUpdate() or LateUpdate() function by changing objects positions or enabled state. You can learn more about the frame execution order here.

When Unity knows exactly what should be rendered, it creates batches. A batch is a package with data that will be send to the GPU. Usually, the fewer packages there are, the better. But Unity cannot pack everything into a single batch. It can batch together quite large amount of geometry vertices, but it can set the material only once per batch. This means that it can batch objects only with the same material. Here’s our car mesh example that will batch:

two cars

Now Unity will do the following:

  1. Read all the vertices (that’s not entirely true, but let’s imagine it that way).
  2. Read the material shader and texture.
  3. Speak with the GPU: „Hey GPU, please use these vertices, this shader, those textures and draw it here and there!”
  4. And the GPU does as told.

Practically Unity just rendered two objects with the cost of one. How cool is that?!

How to prepare the scene?

To make batching work you have to prepare your scene objects in a specific way. First, you need to know that there are two kinds of batching methods in Unity. First, there is a…

Dynamic batching

This is the simplest possible batching done by Unity. All objects that may be batched dynamically should share the same material (copies of the same material do not apply) and fulfill the following criteria:

  • Mesh should contain less than 900 vertex attributes per total. For instance, if shader uses vertex position, normal and single UV, then you can batch up to 300 verts.
  • Object should be using the same transform scale.
  • Object is not lightmapped or is pointing to the same lightmap location.
  • Material is using single-pass shader.
  • Object is not receiving real-time shadows.

Static batching

On the other hand, static batching allows the engine to reduce draw calls for geometry of any size. The requirement about the material still does apply and you need to make sure your object will not move by making it static.

object static

Static batching will require more memory than dynamic batching, but it does not require any additional CPU power to do the batching.

More details about those batching methods you can find in Unity documentation.

Debugging

There’s little you can really do to find out why batching is not working as expected until you’re aware of the rules above. Then you can check how many objects have actually been batched.  One way of doing so is by using the Stats window in your Game view.

batching stats window

There are two entries that we want to look at:

  • Batches – this is the total number of batches used to draw the scene that we’re seeing.
  • Saved by batching – number of batches that were merged into other batches.

So without batching this scene would need 12 batches to draw. Remember: the lower, the better!

Profiler

Please try to open the Profiler (Window -> Profiler or Ctrl + 7).  Run your game and then:

  1. Click on the Rendering section
  2. Look at the bottom part of this window.

batching profiler

Profiler will be a little more descriptive about what kind of batching has been done, about the number of batches and the number of tris/vers that has been batched in total.

Frame Debugger

The Frame Debugger is something that can be found only in Unity 5 (and most probably above) and can be opened through Window -> Frame Debugger menu. Frame Debugger allows you to:

  1. Traverse through all the batches and see what is rendered on the scene after each batch.
  2. Locate the actual batch to see what is batched and to verify what may be breaking it.

batching frame debugger

Conclusion

Batching is very important part of making your mobile game animation smooth; ignore it and you will suffer the consequences. You may be curious about reasonable upper limit of batches that your game can produce. From our experience it can be around 150 to 300 but it depends on used shaders, fill rate, vertex density and used Unity version (not mentioning the device performance of course).

This is not everything that you can do about mobile games optimization. You will find more entries of this series in the future. Make sure you click on the Mobile Optimization tag to find all of them!

Profiling Unity Application with Profiler Samples

The Unity Profiler Samples is something that most of Unity users are unaware of. Yet it can be extremely helpful if you want to find out what amount of resources your code takes during the execution.

If you’re already familiar with built-in profiler then you might know that by default it is not profiling all method calls. Also, the Deep Profiling causes large overhead that will significantly slow down your application execution and it even may not be possible to perform the profiling activity at all (Unity can run out of memory). The Profiler Samples are quite useful here.

Profiler Sample is a block of code that starts with Profiler.BeginSample() and ends with Profiler.EndSample() calls. Just like this:

Normally, you would put it before and after the chunk of code that you want to be profiled. Profiler Sample will record the execution time for you and it will be displayed in the Profiler window without the need to use the Deep Profiling.

profiler window

As you can see, there’s a new entry in the Profiler Hierarchy!

Of course you can add as many Profiler Samples as you want. It’s completely up to you! Don’t worry about adding too many samples. These calls have zero overhead when they are deployed in non-development build.