API reference

FramePhasePll Class

Modifiers: final
Pure (Android-free) phase-locked-loop math for FramePhaseController.
This class holds all of the controller's PLL and drop-rejection state and decisions but performs no scheduling, no wall-clock reads, and no tracing. Every time value is passed in by the caller. That separation lets the algorithm be exercised deterministically by JVM unit tests with a virtual clock (see FramePhasePllTest), covering normal cadence as well as extreme situations (frame-rate changes, long commits that span multiple frames, missed commit/presync deadlines, and loss/return of valid OpenXR timing).
  • Fallback (FrameTiming invalid): reproduces the historical Choreographer behavior, including the errorMs budget that rejects 0 / sub-rate callbacks. The default frame rate (when the confirmed rate is unavailable) is FramePhasePll.Companion.DEFAULT_FRAME_RATE, matching the engine's historical 90Hz maximum update velocity.
  • Locked / pre-sync (FrameTiming valid for FramePhasePll.Companion.LOCK_ON_VALID_FRAMES consecutive frames): drives an absolute schedule timeline so the realized lead (commit end -> next predicted-display grid line) converges to FramePhasePll.targetLeadUs using a slew-rate-limited proportional correction. The grid spacing is derived from the current confirmed refresh rate each frame, so dynamic frame-rate changes are tracked automatically. Only the grid phase comes from predictedDisplayTime, so any constant epoch offset between XrTime and the caller's clock is absorbed into FramePhasePll.targetLeadUs.
  • Locked / post-sync midpoint schedules against xrWaitFrame return timing when available and targets commit completion midway between consecutive returns.
Not thread-safe; the caller (FramePhaseController) confines all use to the main thread.

Signature

class FramePhasePll(var targetLeadUs: Long = DEFAULT_TARGET_LEAD_US, var damping: Float = DEFAULT_DAMPING, var maxSlewUs: Long = DEFAULT_MAX_SLEW_US, var lockedScheduleMode: FramePhasePll.LockedScheduleMode = DEFAULT_LOCKED_SCHEDULE_MODE, var enabled: Boolean = true)

Constructors

FramePhasePll ( targetLeadUs , damping , maxSlewUs , lockedScheduleMode , enabled )
Signature
constructor(targetLeadUs: Long = DEFAULT_TARGET_LEAD_US, damping: Float = DEFAULT_DAMPING, maxSlewUs: Long = DEFAULT_MAX_SLEW_US, lockedScheduleMode: FramePhasePll.LockedScheduleMode = DEFAULT_LOCKED_SCHEDULE_MODE, enabled: Boolean = true)
Parameters
targetLeadUs: Long
damping: Float
maxSlewUs: Long
lockedScheduleMode: FramePhasePll.LockedScheduleMode
enabled: Boolean

Properties

damping : Float
[Get][Set]
Fraction of the measured phase error corrected per frame (proportional gain).
Signature
var damping: Float
enabled : Boolean
[Get][Set]
Master switch for phase-locking. When true (default) the loop phase-locks to the predicted-display clock where support is available (valid timing); it automatically stays in the Choreographer fallback where it is not. When false the loop never locks and behaves exactly like the historical free-running Choreographer schedule.
Signature
var enabled: Boolean
lockedScheduleMode : FramePhasePll.LockedScheduleMode
[Get][Set]
Scheduling policy used after the loop phase-locks to OpenXR timing.
Signature
var lockedScheduleMode: FramePhasePll.LockedScheduleMode
maxSlewUs : Long
[Get][Set]
Maximum schedule correction applied in a single frame, in microseconds (slew limit).
Signature
var maxSlewUs: Long
mode : FramePhasePll.Mode
[Get]
Current loop mode.
Signature
var mode: FramePhasePll.Mode
targetLeadUs : Long
[Get][Set]
Target lead (us) from commit end to the next predicted-display grid line.
Signature
var targetLeadUs: Long

Methods

beginFrame ( frameTimeNanos , frameRate , timing , nowNs )
Called at the start of every frame, before the tick.
Signature
fun beginFrame(frameTimeNanos: Long, frameRate: Float, timing: FrameTiming, nowNs: Long): FramePhasePll.BeginResult
Parameters
frameTimeNanos: Long  vsync timestamp (fallback) or nowNs (locked); CLOCK_MONOTONIC ns.
frameRate: Float  confirmed refresh rate (Hz); FramePhasePll.Companion.DEFAULT_FRAME_RATE is used if <= 0.
timing: FrameTiming  latest OpenXR predicted-display snapshot.
nowNs: Long  current monotonic time (ns); used to seed the locked timeline on transition.
Returns
FramePhasePll.BeginResult
endFrame ( commitEndNs , commitDurationNs , frameRate , timing , nowNs , tickToCommitDurationNs )
Called after the tick in locked mode. Computes the delay before the next tick so the realized lead converges to FramePhasePll.targetLeadUs, with phase-preserving catch-up if the callback ran long or was delayed across one or more frame periods.
Signature
fun endFrame(commitEndNs: Long, commitDurationNs: Long, frameRate: Float, timing: FrameTiming, nowNs: Long, tickToCommitDurationNs: Long = commitDurationNs): FramePhasePll.ScheduleResult
Parameters
commitEndNs: Long  monotonic time (ns) at the end of commit().
commitDurationNs: Long  measured duration (ns) of commit().
frameRate: Float  confirmed refresh rate (Hz) for this frame (tracks dynamic changes).
timing: FrameTiming  OpenXR predicted-display snapshot for this frame.
nowNs: Long  current monotonic time (ns) when scheduling the next frame (>= commitEndNs).
tickToCommitDurationNs: Long  measured duration (ns) from tick start through commit end.
Returns
FramePhasePll.ScheduleResult
reset ()
Resets all PLL / drop-rejection state to the fallback bootstrap condition.
Signature
fun reset()

Companion Object

Properties

COMMIT_SMOOTHING : Float
[Get]
Signature
const val COMMIT_SMOOTHING: Float = 0.1f
DEFAULT_DAMPING : Float
[Get]
Signature
const val DEFAULT_DAMPING: Float = 0.25f
DEFAULT_FRAME_RATE : Float
[Get]
Signature
const val DEFAULT_FRAME_RATE: Float = 90.0f
DEFAULT_LOCKED_SCHEDULE_MODE : FramePhasePll.LockedScheduleMode
[Get]
Signature
val DEFAULT_LOCKED_SCHEDULE_MODE: FramePhasePll.LockedScheduleMode
DEFAULT_MAX_SLEW_US : Long
[Get]
Signature
const val DEFAULT_MAX_SLEW_US: Long = 2000
DEFAULT_MINIMUM_TICK_DURATION_US : Long
[Get]
Signature
const val DEFAULT_MINIMUM_TICK_DURATION_US: Long = 2000
DEFAULT_TARGET_LEAD_US : Long
[Get]
Signature
const val DEFAULT_TARGET_LEAD_US: Long = 900
LOCK_ON_VALID_FRAMES : Int
[Get]
Signature
const val LOCK_ON_VALID_FRAMES: Int = 5
MAX_CATCHUP_FRAMES : Int
[Get]
Signature
const val MAX_CATCHUP_FRAMES: Int = 16
MAX_INTERVAL_FRACTION : Float
[Get]
Signature
const val MAX_INTERVAL_FRACTION: Float = 1.5f
MIN_INTERVAL_FRACTION : Float
[Get]
Signature
const val MIN_INTERVAL_FRACTION: Float = 0.5f
MIN_TICK_TO_COMMIT_DURATION_SAMPLES : Int
[Get]
Signature
const val MIN_TICK_TO_COMMIT_DURATION_SAMPLES: Int = 10
STALE_FRAMES : Int
[Get]
Signature
const val STALE_FRAMES: Int = 8
TICK_TO_COMMIT_DURATION_PERCENTILE : Int
[Get]
Signature
const val TICK_TO_COMMIT_DURATION_PERCENTILE: Int = 90
TICK_TO_COMMIT_DURATION_WINDOW_FRAMES : Int
[Get]
Signature
const val TICK_TO_COMMIT_DURATION_WINDOW_FRAMES: Int = 90
UNLOCK_ON_INVALID_FRAMES : Int
[Get]
Signature
const val UNLOCK_ON_INVALID_FRAMES: Int = 3

Inner Classes

BeginResult Class

Modifiers: final
Result of FramePhasePll.beginFrame: whether to run the tick this frame and the (possibly updated) mode.

Signature

data class BeginResult(val shouldTick: Boolean, val mode: FramePhasePll.Mode, val modeChanged: Boolean)

Constructors

BeginResult ( shouldTick , mode , modeChanged )
Signature
constructor(shouldTick: Boolean, mode: FramePhasePll.Mode, modeChanged: Boolean)
Parameters
shouldTick: Boolean
mode: FramePhasePll.Mode
modeChanged: Boolean
Returns
FramePhasePll.BeginResult

Properties

mode : FramePhasePll.Mode
[Get]
Signature
val mode: FramePhasePll.Mode
modeChanged : Boolean
[Get]
Signature
val modeChanged: Boolean
shouldTick : Boolean
[Get]
Signature
val shouldTick: Boolean

ScheduleResult Class

Modifiers: final
Result of FramePhasePll.endFrame: the next schedule delay plus diagnostics for tracing/tests.

Signature

data class ScheduleResult(val delayNs: Long, val realizedLeadNs: Long, val correctionNs: Long, val smoothedCommitNs: Long, val skippedFrames: Int, val missedDeadline: Boolean, val nextGridLeadNs: Long = 0, val targetTickNs: Long = 0, val targetGridNs: Long = 0, val estimatedTickToCommitNs: Long = 0)

Constructors

ScheduleResult ( delayNs , realizedLeadNs , correctionNs , smoothedCommitNs , skippedFrames , missedDeadline , nextGridLeadNs , targetTickNs , targetGridNs , estimatedTickToCommitNs )
Signature
constructor(delayNs: Long, realizedLeadNs: Long, correctionNs: Long, smoothedCommitNs: Long, skippedFrames: Int, missedDeadline: Boolean, nextGridLeadNs: Long = 0, targetTickNs: Long = 0, targetGridNs: Long = 0, estimatedTickToCommitNs: Long = 0)
Parameters
delayNs: Long
realizedLeadNs: Long
correctionNs: Long
smoothedCommitNs: Long
skippedFrames: Int
missedDeadline: Boolean
nextGridLeadNs: Long
targetTickNs: Long
targetGridNs: Long
estimatedTickToCommitNs: Long
Returns
FramePhasePll.ScheduleResult

Properties

correctionNs : Long
[Get]
Schedule correction (ns) applied this frame (signed, slew-limited).
Signature
val correctionNs: Long
delayNs : Long
[Get]
Delay (ns) from nowNs until the next tick should start. Always >= 0.
Signature
val delayNs: Long
estimatedTickToCommitNs : Long
[Get]
Rolling p90 tick-start-to-commit-end duration used for midpoint scheduling.
Signature
val estimatedTickToCommitNs: Long = 0
missedDeadline : Boolean
[Get]
True when the commit ended after the grid line it was meant to precede (a miss).
Signature
val missedDeadline: Boolean
nextGridLeadNs : Long
[Get]
Positive distance from commit end to the next OpenXR grid line.
Signature
val nextGridLeadNs: Long = 0
realizedLeadNs : Long
[Get]
Realized lead (ns): commit end to nearest grid line. Negative => commit landed late.
Signature
val realizedLeadNs: Long
skippedFrames : Int
[Get]
Whole grid periods skipped to catch up after a long/late callback (0 when on time).
Signature
val skippedFrames: Int
smoothedCommitNs : Long
[Get]
Low-pass-filtered commit duration (ns), for observability.
Signature
val smoothedCommitNs: Long
targetGridNs : Long
[Get]
Absolute monotonic OpenXR timing line used as the next tick's scheduling anchor.
Signature
val targetGridNs: Long = 0
targetTickNs : Long
[Get]
Absolute monotonic time for the next tick target.
Signature
val targetTickNs: Long = 0

Inner Enums

Mode Enum

Signature

enum Mode : Enum<FramePhasePll.Mode> 

Enumeration Constants

Member
FALLBACK
LOCKED

LockedScheduleMode Enum

Signature

enum LockedScheduleMode : Enum<FramePhasePll.LockedScheduleMode> 

Enumeration Constants

Member
PRE_SYNC
WAITFRAME_MIDPOINT