Enable Phase Sync for Native Mobile Apps (Deprecated)
Updated: Sep 29, 2022
Mobile SDK Deprecation
As of August 31, 2022, Mobile SDK and the VrApi library are no longer supported. Future updates will be delivered through OpenXR extensions and our OpenXR Mobile SDK, not through any new updates to Meta Mobile or PC APIs. - New apps must use OpenXR unless a waiver is granted.
- New apps will not have access to Meta Native Mobile APIs, but existing apps can continue using them.
- No assistance will be provided for creating new apps with Meta Native APIs. You will find recommendations for migrating existing apps to OpenXR in the developer guides.
- Only critical security, privacy, or safety issues in Meta Native APIs will be addressed.
- Any testing of Meta Native Mobile will be restricted to automated QA tests, only to ensure core features remain functional.
Phase Sync is a frame timing management technique used to manage latency adaptively. It is available for native Meta Quest and Meta Quest 2 apps as an option in the latest Mobile SDK release.
Phase Sync offers an alternative to the fixed-latency mode for managing frame timing in Meta Quest apps. In fixed-latency mode, frames are composited as early as possible to avoid missing the current frame and reusing a stale one. Stale frames can negatively affect the user experience.
Unlike fixed-latency, Phase Sync adapts frame timing based on the app’s workload. Its goal is to complete frame rendering just before the compositor needs it, reducing rendering latency without missing frames.
The following image shows the difference between a fixed latency and when Phase Sync is enabled for a typical multi-threaded VR app.
Note the following when Phase Sync is enabled:
- No additional performance overhead: Phase Sync does not increase an app’s performance demands.
- Sensitive to workload fluctuations: If the app’s workload fluctuates or spikes frequently, Phase Sync might cause more stale frames.
- Complements late-latching: Phase Sync and late-latching often work well together.
- Extra latency mode: If both extra latency mode and Phase Sync are enabled, the extra latency mode will be ignored.
Ensure the Frame Loop is Correct
To enable Phase Sync, call vrapi_WaitFrame
and vrapi_BeginFrame
each frame.
vrapi_WaitFrame
marks a new frame’s start and automatically adjusts the frame start time to reduce pose prediction latency. In doing so, vrapi_WaitFrame
may block the application’s calling thread.
- For multi-threaded applications,
vrapi_WaitFrame
must be called from the main (simulation) thread. - For single-threaded applications,
vrapi_WaitFrame
may be called from the render thread before calling vrapi_BeginFrame
.
vrapi_BeginFrame
is called prior to the start of frame rendering and marks a new render frame’s start. Applications must guarantee that vrapi_BeginFrame
is only called after a corresponding call to vrapi_WaitFrame
has completed. vrapi_BeginFrame
should be called from the same thread as vrapi_SubmitFrame2
.- Correspondingly,
vrapi_SubmitFrame2
should be called from the same thread as vrapi_BeginFrame
(render thread) as it indicates the render frame’s completion.
The following image shows the required frame API ordering for multi-threaded apps:
The following image shows the required frame API ordering for single-threaded apps:
Note: It is the app developer’s responsibility to do external synchronization and make sure these APIs are being called from the proper thread and with the correct order. Otherwise, the behavior is undefined.
After the correct frame API ordering is in place, Phase Sync can be successfully enabled. To do so, the app needs to set the VrApi mode flag VRAPI_MODE_FLAG_PHASE_SYNC
to enable Phase Sync explicitly, as in this example:
ovrModeParms parms = vrapi_DefaultModeParms(&app->Java);
// Enable Phase Sync
parms.Flags |= VRAPI_MODE_FLAG_PHASE_SYNC;
app->Ovr = vrapi_EnterVrMode(&parms);
After enabling Phase Sync in your app, you can verify that it is active and see how much latency it has saved by examining the logcat logs.
- If Phase Sync is not active, the Lat value is Lat=0 or Lat=1, indicating extra latency mode.
- If Phase Sync is active, the Lat value is Lat=-1, indicating the latency is managed dynamically.
The Prd value indicates the render latency as measured by the runtime. To calculate how much latency Phase Sync has saved, compare the Prd values between when Phase Sync is active and not active. For example, if the Prd with Phase Sync is 35ms and the Prd without is 45ms, you saved 10ms of latency with Phase Sync.
To more easily compare performance with and without Phase Sync, you can turn it on and off with an adb shell setprop. You must restart the app after changing the setprop for the change to have effect.
- Turn off:
adb shell setprop debug.oculus.phaseSync 0
- Turn on:
adb shell setprop debug.oculus.phaseSync 1
If you don’t see Lat=-1 after enabling Phase Sync, it is most likely you didn’t call vrapi_WaitFrame
, vrapi_BeginFrame
, and vrapi_SubmitFrame
in the proper sequence. For example, if vrapi_WaitFrame
was missed in a certain frame, the runtime will turn off Phase Sync automatically in this app session, and logcat will print something like the following:
VrApi : Phase sync mode isn't allowed on app [your package name] since WaitFrame / BeginFrame APIs weren't invoked explicitly