Why hello there! I’m Cristiano Ferreira, one of the Developer Relations Engineers at Oculus. One of my team’s primary responsibilities is to help game developers optimize their games to run as efficiently as possible on all of our hardware. I have helped ship quite a few of our Oculus Quest launch titles and RenderDoc has been one of the most important tools on my tool belt for getting at the truth of what is causing performance problems. With this 3-part series I will share how you can easily start integrating
RenderDoc into your workflow, the fundamentals, and a few of the more advanced topics that will enable you to leverage this helpful tool in the future.
RenderDoc is a great tool for peering behind the curtain of your application’s rendering scheme to verify that what you intended is actually happening. With commercial game engines, actual rendering code is either hidden or just plain hard to decipher with the various built-in subsystems optimizing in the background. Wouldn’t it be nice to see how the engine determined how your scene should be rendered within a single frame? Welcome to RenderDoc!
When you take a frame capture with RenderDoc, it records all graphics API commands and resources for a single frame in the order they are issued, then replays them so that you can verify that what you want to be doing is what’s happening on the hardware. RenderDoc also allows you to get a rough idea of how long draws and logical groups of draws (denoted by debug markers) are taking to execute on the GPU. The numbers themselves are not 100% accurate due to the nature of tile-based rendering, but they are accurate enough relative to each other. So, instead of saying “this draw call took 1.34 milliseconds” you can look through all draws and see that the 1.34 ms draw took longer than a 0.2 ms draw that covers a similar amount of pixels, then determine that the assets and pipeline state used to produce that draw are as optimized as possible. We’ll go deeper into the specifics about tile-based rendering later.
One more critically important detail about RenderDoc is that it’s completely free and open source licensed. You should always make sure you are on the latest public stable release to make sure you are up to date with all of the new features, bug fixes and optimizations. Download a copy for your specific platform at the
official RenderDoc downloads page.
Note: This article is intended to be a living document and will be added to in the future. Bookmark it and keep your eye on the
Oculus Developer Blog to track updates!
Getting a RenderDoc Capture on the Oculus Quest
Let’s take a quick look at the basic window after you open RenderDoc for the first time. Above the main checkerboarded window, you’ll see a number of tabs. Here’s a brief overview of each:
RenderDoc basic window functionality
Timeline
Displays a visual representation of how much time is spent during various stages (opaques, transparents, skybox, early-z, shadow pass, etc.). Will also show render target reads/writes so you can quickly see if the way you generate your frame incurs an expensive resolve cost (more on this in the following article).
Event Browser
Lists all API calls that went into the frame along with debug marker labels to separate logical draw groups. Selecting draws here contextually populates/updates all other tabs (texture viewer, mesh viewer, etc.).
RenderDoc tabbed functionality
Texture Viewer
Displays input textures and output textures (RTs) for the selected draw. Click on individual textures to see their formats/resolutions/ available MIPS/MSAA level, etc.
Pipeline State
Select any pipeline state to view all properties of the bound resources and material properties (transparency/blend state, textures/samplers, z-testing conditions, bound shaders, etc.)
Mesh Viewer
View the input mesh in local space to determine what the draw you have selected is drawing. You can also see vertex count (which is useful for verifying LOD systems), the post-projected view in screen space and the vertex attributes, etc.
Launch Application
Select which application to run and attach to with the RenderDoc host. If your selected context is Local you’ll be able to point to your application executable on your computer. If your selected context is Remote: Oculus Quest, you’ll get a list of available packages on your device.
Resource Inspector
Shows a list of all resources bound on the GPU within the frame and when they are used (via EID - event ID). You can quickly find render targets, temporary buffers, textures, shaders, meshes, etc.
Statistics
Displays your draw count, gpu memory usage, etc. Good first place to look!
Attaching RenderDoc to Oculus Quest
Make sure it enumerates when you run the adb devices command in a command prompt. The first time you connect your Oculus Quest via USB cable, you will likely be prompted inside the headset to allow access from the host computer (if you have connection issues, make sure this isn’t the reason why). I also recommend using a USB 2.0 A to USB-C or an Oculus Link cable (when released) for general connection stability. If you see your device, it should be available on the context menu in the lower left corner of the RenderDoc window. Select Oculus Quest from the list and wait a few seconds for the RenderDoc capture layer APKs to transfer to the device and for the client to connect to the remote context’s server.
Launching and attaching RenderDoc to your game/application
To launch your application, go to the aptly named tab Launch Application and click the breadcrumbs (…) next to Executable Path. This will open a file browser where you can navigate to your executable file or if you’re on Oculus Quest it will show all available APKs on your device. If you’re in a local context (PC), you can also set the working directory if it differs from the default.
Click the Launch button at the right to launch the application with RenderDoc attached. (Note: You’ll need to be a Development Build of your project to attach).
Taking a frame capture
To take a frame capture, just hit the Capture Frame(s) Immediately button. RenderDoc will then intercept all calls, assets, etc. made to the graphics context and save them in a .rdc file. A quick tip here is to make sure that you cover the proximity sensor near the forehead of the device if you have issues. Sometimes I keep a piece of tape over mine so it stays on while I’m analyzing and optimizing. If you take a frame capture while the proximity sensor detects the headset is off, it will result in an empty frame being generated. The file you generate will appear in the Captures collected section. I always make it a habit to save out my captures to the desktop to later reload if I exit RenderDoc. If you’re capturing on an Oculus Quest, the .rdc file will need to transfer to your host PC, so it may take a bit longer.
Note: if you’re developing for Oculus Quest and your application crashes when you take a capture it typically means you’ve run out of system memory (you can take a look at the RenderDoc logs to be sure what the issue is).To take a RenderDoc capture on the device, there has to be enough available memory to support your application’s memory requirements, the renderdoc capture layer’s memory requirements and the memory required to hold your generated.rdc file. Below are some tips for decreasing memory footprint in your game to get a capture:
- Set build settings to use as low of a texture resolution cap as possible.
- Unity has a global option to use ⅛ texture size & enable texture streaming.
- This may affect your per-draw call timings, but again only consider the timings relative to one-another not as absolute timings.
- Remove additive loading of scenes in place of full unload and full load during optimization phase.
- Remove all audio if possible.
Investigating your capture
1.) Get an Overview
I usually start by opening the Statistics tab to see how many draw calls I'm issuing to get a rough idea of how hard I'm hitting the render / main thread. This will also tell me how much GPU memory I'm using with a nice breakdown.
2.) Visualize Draws / Timings
Next, I open the Texture Viewer tab, turn on the Highlight Draw Call option in the Overlay menu, click the Gather Timings (clock) button and finally select the Render Target in the Output texture section.
Doing this will give me relative timings for each draw call and allow me to find which draws are taking the most time. I can click any of those draw calls in the Event Browser and have it appear highlighted on the Render Target viewer.
The event browser will have your engine’s debug markers (if available) showing labeled sections of draws for greater verbosity / understanding.
Notice in the picture I can see where GPU skinning, shadow pass, opaques and transparent objects are drawn in the Event Browser.
3.) Optimize!
At this point, I will look for the draw calls with the highest timings relative to each other and try and find out why. Are the shaders super complex? Did input resource properties not get set correctly? Is my rendering order out of whack?
RenderDoc video walkthrough
If you prefer learning by watching video tutorials, feel free to check out the walkthrough I put together below. In the video, I provide an overview of the tool and review all of the points outlined above.
Conclusion
Now that we’ve covered the basics of attaching and capturing RenderDoc to your Oculus Quest game or application we’re ready to move on to more advanced topics. We will soon publish part 2 and 3 of this series, giving you a deeper understanding about the hardware and software stack, as well as proper rendering methods and settings for your application to work best with mobile VR hardware. If you’d like to dig into more RenderDoc resources, be sure to check out the
official RenderDoc site and
documentation. There are additional starting resources you may also find handy including an
introduction,
quick start guide and
Android usage guide provided within the documentation.
Lastly, be sure to check out the remainder of this 4-part series on RenderDoc:
Thanks for reading!
- Cristiano Ferreira