Testing and Performance Analysis
Updated: Sep 4, 2024
This guide describes basic testing and performance analysis for Meta Quest development in Unreal Engine.
VR application debugging is a matter of getting insight into how the application is structured and executed, gathering data to evaluate actual performance, evaluating it against expectation, and then methodically isolating and eliminating problems.
When analyzing or debugging, it is crucial to proceed in a controlled way so that you know what changes provided you with positive outcomes. Focus on bottlenecks first. Only compare similar aspects of your app and change one thing at a time—for example, resolution, hardware, quality, and configuration.
Always be sure to profile, as systems are full of surprises. We recommend starting with simple code and optimizing as you go. Don’t try to optimize too early.
- Media applications can aim for 60 FPS.
- Interactive applications must achieve a minimum of 72 FPS.
Various factors influence the number of draw calls you can execute per frame on the Meta Quest devices. These include:
- Pipeline state changes: This involves changing shaders, textures, meshes, and such between draws.
- Share meshes and instance meshes wherever possible.
- Use global texture arrays if you can.
- Use a minimal set of unified shaders that don’t generate variants.
- Main and render thread capacity: Consider the available resources on the render thread and on the main thread which is preparing and supplying data to the render thread.
- Processes such as animation, skinning, and networking, can delay the start of the render thread and reduce the number of draw calls that can be executed within the target FPS.
- Graphics API and usage:
- Vulkan vs. OpenGL ES.
- Multi-threaded Rendering--low latency vs. frame-behind.
- Usage of bindless textures and indirect draws.
The following table provides example draw call ranges. Your results may vary based on the factors mentioned above.
Platform | Draw Calls | Description |
---|
Quest 1 | 50-150 | Busy Simulation |
Quest 1 | 150-250 | Medium Simulation |
Quest 1 | 200-400 | Light Simulation |
Quest 2, Quest Pro | 80-200 | Busy Simulation |
Quest 2, Quest Pro | 200-300 | Medium Simulation |
Quest 2, Quest Pro | 400-600 | Light Simulation |
Quest 3, Quest 3S | 200-300 | Busy Simulation |
Quest 3, Quest 3S | 400-600 | Medium Simulation |
Quest 3, Quest 3S | 700-1000 | Light Simulation |
- Busy Simulation: Applications with extensive simulations, VoIP, networking, animation, and skinning from other players or many NPCs. For example, multi-player shooters and populated social apps.
- Medium Simulation: Medium-sized worlds with fewer players or NPCs, such as single-player shooters and medium-populated social games. Most apps fall into this category.
- Light Simulation: Applications with minimal pipeline state changes such as escape room games, puzzle games, and co-op games.
Triangle budgets are similar to draw call budgets, as they fluctuate based on frame-to-frame factors. in that it’s hard to determine how many you can get away with. Triangle count budgets are even more fluid and depend on factors that can change from frame to frame (see
How Tile-based Rendering Works for more information).
- Triangles spanning multiple tiles: These cost more.
- A triangle’s vertex shader runs three times (once per vertex) per tile it covers.
- Larger triangles statistically cover more tiles, though predicting tile boundaries is challenging.
- Memory access patterns of your vertex attributes: These affect vertex shader speeds.
- Dedicate a vertex attribute array for position data, skinning weights, and anything else used to calculate output position. Place anything else into a separate interleaved vertex attribute array. This setup improves the speed of the binning phase that focuses on attributes affecting output position.
- Vertex attributes: Monitor the number and precision of vertex attributes submitted to your vertex shader.
- Remove unused channels such as NORMAL, TANGENT, or TEXCOORD*, or combined channels if possible, to boost performance.
- Only the POSITION channel typically needs full-precision. Experiment with compressing other channels to half-precision and see if you can still maintain visual quality.
Below are some internally-recommended ranges, but results may vary depending on the factors listed above.
Platform | Triangle Count |
---|
Quest 1 | 350k-500k |
Quest 2, Quest Pro | 750k-1m |
Quest 3, Quest 3S | 1.3m-1.8m |
The Unreal Editor provides a built-in
Profiler Tool that shows performance metrics for your app.
Meta has added the ‘System Metrics’ section of the Profiler Tool to provide real-time VR-specific metrics.
The following metrics are available:
- App GPU Time (ms)
- Compositor Dropped Frames
- Compositor GPU Time (ms)
- System CPU Util Avg%
- System CPU Util Worst%
- System CPU Util Util%
When optimizing your app’s performance, the first step is determining whether the bottleneck is on the CPU or GPU. This task can be difficult in Android applications due to the difficulty of obtaining GPU timing. When you run the application with the Profiler Tool, you can read the GPU cost of the application and the VR compositor. The application is likely GPU-bound if the total GPU time is close to or equal to the frame time. Otherwise, the bottleneck is the CPU.
Applications can use multiple cores simultaneously. The Profiler Tool gathers the utility percentage on the most occupied CPU core and the average utility percentage among all CPU cores. If the “System CPU Util Worst%” is very high but the “System CPU Util Avg%” is relatively low, there may be an opportunity to optimize the application by rebalancing workload among threads.
OVR Metrics Tool reports application frame rate, heat, GPU and CPU throttling values, and the number of tears and stale frames per second. It is available for download from our
Downloads page.
The OVR Metrics Tool has two modes. Report Mode displays a performance report about your VR session after completion. You can also export report data as CSV files or PNG graphs.
In Performance HUD Mode, the OVR Metrics Tool renders performance graphs as a VR overlay over any Horizon OS application.
Unreal Engine supports debugging using the Android Game Development Extension (AGDE) Plugin for Visual Studio. This plugin allows you to profile and debug your code in Visual Studio instead of switching environments to Android Studio. If you’re developing on the Windows platform, ADGE is the recommended debugging environment for Android projects in Unreal Engine.
Meta provides another debugging tool, ndk-gdb, which you can find in Meta branches of Unreal Engine. This tool is a small shell script wrapped around GNU GDB and included with the Android NDK.
Using ndk-gdb from the command line adds convenient features to your debugging workflow by allowing, for example, adding breakpoints, stepping through code, and inspecting variables with a command line interface.
To use ndk-gdb for debugging:
- Enable remote port forwarding to link your target mobile port to a PC port: adb forward tcp:$port tcp:$port
- Set your device to Developer Mode, as described in Device Setup.
- Launch the application you wish to debug.
- Start
gdbserver
on the mobile device with the following Unreal console command: gdbserver $port
where $port
is your port number. You application should freeze, and will now be ready for debugging. - Launch the ndk-gdb client from the command line on your computer with the command
gdb.exe
. When it launches, type target remote :$port
in the GDB command line to attach to your mobile device.
- RenderDoc: Use for GPU frame captures and profiling. For more information, see RenderDoc.
- Systrace: Reports complete Android system utilization. For more information, see Use GPU Systrace for Render Stage Tracing and Overview of System Tracing.
- Snapdragon Profiler: Meta Quest uses a Qualcomm chipset, so you can use the Snapdragon Profiler to analyze CPU, GPU, DSP, memory, power, thermal, and network data.
- Unreal Insights: Use for detailed profiling of the engine. For more information, see Unreal Insights.
- APITrace: Use to trace API calls. For more information, see apitrace.
For detailed information about Meta Quest development, go to: