Sei sulla pagina 1di 26

Porting Your VR Game to Oculus Quest

Lessons Learned from Porting Creed: Rise to Glory




ALEX SILKIN

Co-Founder / Chief Technology Officer
Key Takeaways
1. Overcoming common pitfalls

2. Recommended workflows

3. Examples of “performant” tricks


About The Game
Understanding the Target Hardware
Capabilities & Limitations
Tiled Based Renderer

Fragment
Shader

Cache

Slow System Memory


Rough Target
● 300K Verts (shipped with ~200K)
● 100 - 150 Draw Calls (shipped with ~70)
● 13.8 ms / 72fps
Tools and Debug Environment
● OVR Metrics Tool
● RenderDoc
● SnapDragon Profiler
● Android Studio
● Set UE4 to -OpenGL -FeatureLevelES31
First Time Boot Up
Crash!!!!!????
Out of Memory?
● 2.75GB of RAM for Quest applications
● Console command “memreport -full”
● Textures were blowing us way past the budget
• Temporarily globally clamp textures to a small size
• Use ASTC compression
Break-up those messy reference chains!
● Console command “obj refs name=[object_name]”
● UMG / UI is usual culprit
• UI textures do not stream!
● Unnecessary hard references to assets
● Avoid blueprint dependencies
•Casting to a BP class is hard reference - use an interface or move
referenced function/variable to C++
Optimization Time
Let the fun begin!
Let’s Find the Bottleneck
● Console command “Stat unit”
● CPU?
• Pause the game using “pause” or keybinding
● Fill rate?
• Decrease resolution with “r.screenpercentage .1”
● Shaders?
• Disable material rendering with “show materials”
● Draw Calls?
• Hide objects using “show X” like “show staticmeshes” and show “skeltalmeshes”
Drilling Into the Stats
● Stat RHI
● Stat scenerendering
● Stat system overhead!
• Stat system affects perf,
distorts the numbers it reports
• CPU overhead can push

game thread beyond 13ms


•Stat rendering increases
draw calls
Custom Stats and Budgeting
● Lightweight slate widget
•Rendered to a rendertexture and composed on screen
using UDebugDrawService
● Average and max values
● INI defines budget for text color coding
● Existing cached engine values
• GOcclusionQueryCount
• GNumDrawCallsRHI

• GNumPrimitivesDrawnRHI

● Modified engine for additional values


• World Tick Time
CPU
● Session Fronted - “stat
startfile / stat stopfile”

● Unreal Insights in
4.23+
CPU
● Moving components
• Detach hidden/disabled scene components
• Avoid using built-in overlaps

● Ticking
• Disable ticking when not needed
• Tick interval

● Nativize as much BP logic as possible


● Actor pooling
● UMG Invalidation Box
Draw Calls
● Use Multi View
● Merge Geometry
• Manually or using Unreal’s “Merge Actors”
• Minimize material count

● Instance as much as you can


● Not all draw calls are equal!
• Complexity of mesh affects draw call cost
Merging Level Geo

● Stadium divided in 5-7 pieces

● ~3 Shared texture atlases

● D2 Textures - Diffuse and


Lightmap
GPU
● Disable Early Z Pass
● Don’t use Alpha Test
● Get rid of specular
● Disable Post Processing
● Stay away from Dynamic Lights
• Bake as much as you can
GPU
● Fake blooms and lights
•Use transparent
sprites as bloom

•Project circular
patterns in materials to
stimulate spot lights
GPU
● Use texture atlases
● Minimize texture sampling (2-3 max for environment)
● ASTC Compression
● Dependent vs. Independent Texture Reads
● Texture dimensions power of 2 (mipmap + streaming)
GPU
● Use MSAA
• Cheap(er) on Tiles Based Renderers
● Avoiding shader hitches
• r.SaveShaderCache
• PSO Caching on 4.21+

● Fixed Foveated Rendering


● Avoid long thin triangles
Memory
● Shared Bandwidth
• Be careful with memory operations, they affect CPU and GPU

● Memory stomp tracking

adb shell setprop libc.debug.malloc 1


adb shell stop
adb shell start
adb shell setprop wrap.com.survios.Creed '"LIBC_DEBUG_MALLOC_OPTIONS=fill"'
adb shell "logcat | grep malloc"
Memory
E malloc_debug: +++ ALLOCATION 0x7ef7ba6fc0 SIZE 16 HAS A CORRUPTED
REAR GUARD
E malloc_debug: allocation[16] = 0x04 (expected 0xbb)
E malloc_debug: Backtrace at time of failure:
E malloc_debug: #00 pc 00000000000441b4 data/app/com.survios.Creed-1/
lib/arm64/libOVRPlugin.so (OVR::Util::CompositorVRAPI::State::Reset()+576)
General Tips
● Load up time
• Load into an empty room first
• Break reference chains

● Audio
• AndroidAudio (Default) does not spatialize audio
• Use AudioMixerAndroid or other third party plugins
Questions?

Potrebbero piacerti anche