Showdown is a PC VR demo built by Epic with UE4. First shown at Oculus Connect 2014, Showdown presents an action cinematic in bullet-time slow motion and was originally
released for the Oculus Rift.
We converted the Showdown demo to run on Quest 2 with the goal of maintaining the visual fidelity of the PC version as closely as possible. The finished project runs on Quest 2 at a consistent 90 FPS. To reach that mark, we had to significantly optimize CPU and GPU performance for the mobile renderer.
In this article—the first of two—we will examine how Application SpaceWarp (AppSW) improved the performance of Showdown and demonstrate how you can profile the impact of AppSW and other render settings yourself.
Project source code is available in the
Oculus fork of UE4.27, though it is not necessary for anything we discuss here. We recommend VR developers stay on the Oculus fork of UE4.27 until our support for VR in UE5 is ready for production use. See our documentation on
how to gain access to the Oculus fork and what it includes. Showdown for Quest depends on the forked version of Unreal Engine as it includes AppSW and the mobile tonemap subpass. These features have not been upstreamed to Epic’s repo at the time of this post’s publication.
Please note that while the Showdown demo does run on Quest 1, all profiling and performance data in this doc were collected on Quest 2.
Application SpaceWarpAppSW provides a big performance boost for little effort. It allows an app to render at half-rate (i.e. 36 FPS vs 72 FPS) while the system still synthesizes at the full refresh-rate to display, allowing substantially more time for both CPU and GPU each frame. AppSW can help your app get from 72 to 90 FPS (or 60 to 72 FPS). In Showdown, AppSW allowed us the headroom needed to handle more effects from the PC version while still hitting 90 FPS. These effects include the color LUT (utilizing the vulkan tonemap subpass) and significantly more particles for bullet collisions and explosions.
Now let's take a look at Showdown and see how AppSW and other render settings affect performance.
OVR MetricsOpen ODH
Select Downloads > Applications > OVR Metrics Tool
Click Download
Now configure the tool:
In ODH, go to the Device Manager
Under “Device Actions” enable “Metrics HUD”
Click the Metrics HUD settings gear
Here we can choose which stats and graphs to display. Configure it like this:

Now launch the Showdown demo.
We’ve included a feature in Showdown we call “head lock mode.” It provides a static camera that’s useful when profiling different render settings. Enter this mode by clicking the right thumb stick. It will pause the scene and lock the camera position and orientation so each frame rendered is identical. Click the stick again when you want to unlock the camera and unpause.
Once you lock in a frame you would like to profile, press B to open the render settings menu. Select a menu item with right trigger (up) and right grip trigger (down). Press A to toggle the selected menu option. These include:
AppSW (on/off)
CPU/GPU level (1/2/3/4)
FFR (off/low/med/high/hightop)
Framerate (72/80/90)
Pixel density (1.0/0.9/0.2)
Tonemap subpass (on/off)
MSAA (1/2/4/8)
Render Settings Menu

Press B again to hide the render settings menu.
OVR Metrics HUD

In this screenshot, you can see how FPS and GPU utilization changed when toggling AppSW off and back on again. Note that OVR Metrics will report half your target framerate when AppSW is enabled.
Take some time to observe how each option in the menu affects CPU and GPU utilization. You can also experiment with 120 FPS support to see how it affects performance with various render settings.
To enable 120 FPS in headset:
Click the clock on the Quest system menu to open Quick Settings
Click the Settings button in the top right
Choose Experimental
Toggle on “120 Hz Refresh Rate”
To toggle the same render settings in your own app, you can use equivalent adb commands:
ASW
adb shell "am broadcast -a android.intent.action.RUN -e cmd 'r.Mobile.Oculus.SpaceWarp.Enable 1'"
CPU/GPU level
adb shell setprop debug.oculus.gpuLevel 3
adb shell setprop debug.oculus.cpuLevel 3
FFR
adb shell setprop debug.oculus.foveation.dynamic 0
adb shell setprop debug.oculus.foveation.level 2
Framerate
adb shell setprop debug.oculus.refreshRate 90
Pixel density
adb shell "am broadcast -a android.intent.action.RUN -e cmd 'vr.PixelDensity 1.0'"
Tonemap subpass
adb shell "am broadcast -a android.intent.action.RUN -e cmd 'r.Mobile.TonemapSubpass 0'"
MSAA
adb shell "am broadcast -a android.intent.action.RUN -e cmd 'r.MobileMSAA 1'"
Additional info on Oculus system properties can be found
here.
PerfettoWith OVR Metrics, we were able to see the performance benefit of AppSW. Next let's look even closer with Perfetto render stage tracing to see how it works.
To collect render stage trace data with Perfetto, you need to modify the default configuration.
Inside ODH, open the Performance Analyzer
Click the “…” next to the Record button on the top right and choose “Perfetto Settings”.
Select Custom
Replace the existing linux.ftrace block with:
{
"config": {
"name": "linux.ftrace",
"ftraceConfig": {
"ftraceEvents": [
"sched/sched_switch",
"power/suspend_resume",
"sched/sched_wakeup",
"sched/sched_wakeup_new",
"sched/sched_waking",
"sched/sched_process_exit",
"sched/sched_process_free",
"task/task_newtask",
"task/task_rename",
"ftrace/print"
],
"atraceCategories": [
"gfx",
"view",
"webview",
"camera",
"dalvik",
"power"
],
"atraceApps": [
"com.oculus.samples.ShowdownQuest"
]
}
}
},
Notice the package identifier in the atraceApps sections. You’ll need to add any other apps you want to trace here as well.
Click Save
Start the app on device
Click the Record button in the Performance Analyzer
Perform any actions in game you wish to profile (i.e. toggle AppSW off / on)
Click the Stop button
Once the Perfetto browser window opens, you’ll want to star a few traces to focus on.
Note: Some of these are listed twice. Pick the colorful ones, not the green ones.
com.oculus.samples.ShowdownQuest
RenderThread
RHIThread
GameThread
FenceChecker
com.oculus.vrruntimeservice
Here we show two screenshots of perfetto trace data with AppSW off and on. Notice with AppSW enabled, we have twice as much time between frames. While we can’t use all of this time due to some overhead, it does provide significantly more time for both CPU and GPU processing.

AppSW off

AppSW on
Now that you’ve seen how we used Application SpaceWarp to improve Showdown, you should have a better understanding of how AppSW works, be familiar with some tools available to profile your app, and be able to identify several render settings that can affect app performance.
In our next blog post, we’ll take a look at the numerous other optimizations used in our Showdown port and describe how and when to use each of them.
Additional resources