Oculus Quest Memory Profiling on Unreal Engine and Unity Engine

An in-depth look at the RAM usage in Oculus Quest for the sake of performance and a comparison between Unity and Unreal’s mobile renderer’s memory usage and texture streaming.

Shahriar Shahrabi
Realities.io
7 min readApr 1, 2020

--

To prepare for our next project, I wanted to get to the bottom of the memory usage in Oculus Quest, especially with games made with UE4. As a point of reference, I compared the results with Unity Engine, to know what numbers sound reasonable and what not.

Here I put together the result of that research, for those who might want to ship a game on the Quest and would like to know if memory might be a bottleneck.

The test is conducted by increasing the amount of textures in an empty scene and recording the memory usage on the Quest.

Some Information on the Quest Hardware

The Oculus quest is powered by the Qualcomm Snapdragon 835 chipset. It has 8 cores, four are fast gold cores, with 2.3 Ghz and four are silver cores. 1 of the four gold cores is reserved for TimeWrapping and System stuff. The 4 silver cores are also reserved for tracking and other system stuff. That leaves 3 gold cores which are accessible to us.

The integrated GPU is a Adreno 540 GPU. This is a 5xx series tiled GPU similar to other mobile gpus in architecture.

Memory: the Adreno has only 4 gb of memory, of which only 2.7 Gb are reserved for application. This is the shared memory between the CPU and the GPU.

Frame rate target is 72 fps. This comes to around 13.8 millisecond of which 2 millisecond is reserved for Time wrap and guardian system. That leaves us with around 11.8 millisecond frame time, similar to 90 fps. Since the Time wrap happens on a separate thread, the actual frame time is closer to the 13.8 ms, but I will leave it at that.

How Much is 2.7 Gb?

2.7 Gb is a lot, but at the same time not all that much. Depends on what assets are being used in the level. Let me give you an example. A mesh that has vertex attributes such as position, uv, tangent and normal will have a size of:

The left side is a vertex size times the total number of vertices and the right side is the total size of the index buffer. For 200k vertices, this number will amount to: 67,200,000 bits which is 8,400,000‬ bytes. or 8.4 mb.

To avoid racing conditions across threads, the engine might decide to duplicate some of the information, so this number might go higher. But all in all, it is an acceptable portion of the 2.7 Gb of free memory.

How about texture? A 4k texture with DXT1 compression, takes 10.6MB of memory. If the DXT5 compression is used, this number will double. That means having 10, 4k textures already takes 100 mb of memory! So as you can see, 2.7 Gb can be used quickly with memory heavy assets.

Snapdragon Profiler

For those who follow me on Twitter, they might have already seen the post I made discussing the base amount of RAM Unreal and Unity Engine use. The number was 1.5 Gb for Unity and 2.0 Gb for UE4. These numbers were unfortunately wrong. I took the numbers directly from the Snap Dragon Profiler, the recommended profiling tool by the Hardware vendor Qualcomm. I have already reported this as a bug at their forum, but so far no insight as to where the extra Gigabyte comes from.

However the proportions were actually correct.

Preparing the Engine for the Tests

The tests will be done in UNREAL ENGINE 4.24.3 and UNITY ENGINE 2018.4.17f1.

Unreal has a lot of crap turned on by default, which we should turn off before testing the memory. These include all the plugins that we don’t need, especially the ones that might allocate memory on run time. Also, I went through the settings and turned off support for the trillion shader permutations which I have never used, support for all platforms except Android, and generally turning things off like early Z pass, occlusion queries and discarding quality levels I don’t need.

In Unity, there isn’t anything that needs to be adjusted. Unity’s approach is bottom up, you need to add things to your scene from the extra features they have for you.

In both engines, there will be a difference if you profile in their development or release mode. That is to be expected. The difference is way higher in Unreal engine. Since I need some of the features in the development mode in the UE4 for debugging, I will profile in development, and then adjust the data by subtracting the extra overhead which development mode has compared to release.

Both engines are set for Forward renderer with MSAA turned off.

Preparing the Assets

The assets will be prepared using our in-house photogrammetry processing pipeline. I have a mesh with 200k vertices, using the pipeline, I will bake out different versions of this mesh, with different number of 4k textures. I will have a version of the mesh with 10, 20, and 30 4k textures.

Profiling Tools

Since Snap Dragon was giving false numbers, I turned to the internal tools UE4 has for memory profiling and the ones which Android shell has for reading memory information.

For Unreal, you need to set up the LLM. LLM requires two things, one is to add -LLM and -LLMCSV (if you want the info saved to a csv file) as a command line argument, second is to add stat LLM, stat LLMFULL, stat LLMPlatform and stat LLMOverhead as console command. For adding command line, you can refer to this article on my medium in the Unreal Insight section. For the Console commands, I am using the “Execute Console Command” in the Level Blue print on the Begin Event to execute all the above console commands.

Beside the LLM I am also going to be using the two memory command mentioned in this stack over flow post. adb shell dumpsys meminfo more specifically the adb shell dumpsys meminfo com.Sha.testing -d command. Replace the com.Sha.testing with your app name.

In Unity I am just using the adb dumpsys to get the numbers I need.

Results

Evaluation

Unreal Engine in shipping mode uses 266 mb on a starter scene. Unity on the other hand 186 mb. Unity Engine itself seems to be more light weighted in terms of how much memory it needs, compared to Unreal. However this difference is quickly caught up by Unreal’s texture streaming, which performs way better.

A quick note, if you want to know what pss and private dirty means, have a look at this documentation for explanation.

The difference between the Shipping and Development mode in UE4 is 73 mb. If we substract that 73 mb from our data for 30, 4k texture, we end up with a total of 308 mb, compared to the 460 mb of RAM which Unity engine uses for the same amount of texture also with texture streaming on. I have to admit the texture streaming from Unreal has surprised me so much, that I spend days trying to find out if there is a mistake in my readings. Without texture streaming, both engines show the expected behavior of 100 mb extra RAM usage per 10, 4k textures.

But How does this Make Sense?

As I mentioned, I spent a while trying to figure out this magic performance by Unreal Engine. My conclusion so far is this: since I am not adding new topology to the scene, just increasing the amount of textures resolution for the same mesh, without actually getting closer to the mesh (distance to mesh is kept consistent across the two engines and for all tests), then amount of texture required on screen space actually doesn’t change. So if a texture streaming algorithm was giving the ideal, 100 percent performance gain, then there shouldn’t be any change in memory usage at all. Only the mip level which we need is loaded in memory, the resolution of this mip level doesn’t change, since neither the mesh topology, nor the distance to the mesh has changed.

Hope you found this article useful, you can follow me on my Twitter: IRCSS

Resources

  1. LLM Documentation: https://docs.unrealengine.com/en-US/Programming/Development/Tools/LowLevelMemoryTracker/index.html
  2. A very detailed answer in Stackoverflow, clearing up a lot of things: https://stackoverflow.com/questions/2298208/how-do-i-discover-memory-usage-of-my-application-in-android
  3. The documentation for the meminfo: https://developer.android.com/studio/command-line/dumpsys
  4. Post on how to pass command line arguments to a build on the oculus quest, section Unreal Insight: https://medium.com/realities-io/oculus-quest-performance-tools-in-unreal-engine-2210f2581c8f

--

--