ovr_sdk

annotate LibOVR/Src/CAPI/CAPI_FrameTimeManager.h @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 Filename : CAPI_FrameTimeManager.h
nuclear@0 4 Content : Manage frame timing and pose prediction for rendering
nuclear@0 5 Created : November 30, 2013
nuclear@0 6 Authors : Volga Aksoy, Michael Antonov
nuclear@0 7
nuclear@0 8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 9
nuclear@0 10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 11 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 12 which is provided at the time of installation or download, or which
nuclear@0 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 14
nuclear@0 15 You may obtain a copy of the License at
nuclear@0 16
nuclear@0 17 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 18
nuclear@0 19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 20 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 22 See the License for the specific language governing permissions and
nuclear@0 23 limitations under the License.
nuclear@0 24
nuclear@0 25 ************************************************************************************/
nuclear@0 26
nuclear@0 27 #ifndef OVR_CAPI_FrameTimeManager_h
nuclear@0 28 #define OVR_CAPI_FrameTimeManager_h
nuclear@0 29
nuclear@0 30 #include "../OVR_CAPI.h"
nuclear@0 31 #include "../Kernel/OVR_Timer.h"
nuclear@0 32 #include "../Kernel/OVR_Math.h"
nuclear@0 33 #include "../Util/Util_Render_Stereo.h"
nuclear@0 34
nuclear@0 35 namespace OVR { namespace CAPI {
nuclear@0 36
nuclear@0 37
nuclear@0 38 //-------------------------------------------------------------------------------------
nuclear@0 39 // ***** TimeDeltaCollector
nuclear@0 40
nuclear@0 41 // Helper class to collect median times between frames, so that we know
nuclear@0 42 // how long to wait.
nuclear@0 43 struct TimeDeltaCollector
nuclear@0 44 {
nuclear@0 45 TimeDeltaCollector() : Median(-1.0), Count(0), ReCalcMedian(true) { }
nuclear@0 46
nuclear@0 47 void AddTimeDelta(double timeSeconds);
nuclear@0 48 void Clear() { Count = 0; }
nuclear@0 49
nuclear@0 50 double GetMedianTimeDelta() const;
nuclear@0 51 double GetMedianTimeDeltaNoFirmwareHack() const;
nuclear@0 52
nuclear@0 53 double GetCount() const { return Count; }
nuclear@0 54
nuclear@0 55 enum { Capacity = 12 };
nuclear@0 56 private:
nuclear@0 57 double TimeBufferSeconds[Capacity];
nuclear@0 58 mutable double Median;
nuclear@0 59 int Count;
nuclear@0 60 mutable bool ReCalcMedian;
nuclear@0 61 };
nuclear@0 62
nuclear@0 63
nuclear@0 64 //-------------------------------------------------------------------------------------
nuclear@0 65 // ***** FrameLatencyTracker
nuclear@0 66
nuclear@0 67 // FrameLatencyTracker tracks frame Present to display Scan-out timing, as reported by
nuclear@0 68 // the DK2 internal latency tester pixel read-back. The computed value is used in
nuclear@0 69 // FrameTimeManager for prediction. View Render and TimeWarp to scan-out latencies are
nuclear@0 70 // also reported for debugging.
nuclear@0 71 //
nuclear@0 72 // The class operates by generating color values from GetNextDrawColor() that must
nuclear@0 73 // be rendered on the back end and then looking for matching values in FrameTimeRecordSet
nuclear@0 74 // structure as reported by HW.
nuclear@0 75
nuclear@0 76 class FrameLatencyTracker
nuclear@0 77 {
nuclear@0 78 public:
nuclear@0 79
nuclear@0 80 enum { FramesTracked = Util::LT2_IncrementCount-1 };
nuclear@0 81
nuclear@0 82 FrameLatencyTracker();
nuclear@0 83
nuclear@0 84 // DrawColor == 0 is special in that it doesn't need saving of timestamp
nuclear@0 85 unsigned char GetNextDrawColor();
nuclear@0 86
nuclear@0 87 void SaveDrawColor(unsigned char drawColor, double endFrameTime,
nuclear@0 88 double renderIMUTime, double timewarpIMUTime );
nuclear@0 89
nuclear@0 90 void MatchRecord(const Util::FrameTimeRecordSet &r);
nuclear@0 91
nuclear@0 92 bool IsLatencyTimingAvailable();
nuclear@0 93 void GetLatencyTimings(float& latencyRender, float& latencyTimewarp, float& latencyPostPresent);
nuclear@0 94
nuclear@0 95 void Reset();
nuclear@0 96
nuclear@0 97 public:
nuclear@0 98
nuclear@0 99 struct FrameTimeRecordEx : public Util::FrameTimeRecord
nuclear@0 100 {
nuclear@0 101 bool MatchedRecord;
nuclear@0 102 double RenderIMUTimeSeconds;
nuclear@0 103 double TimewarpIMUTimeSeconds;
nuclear@0 104 };
nuclear@0 105
nuclear@0 106 // True if rendering read-back is enabled.
nuclear@0 107 bool TrackerEnabled;
nuclear@0 108
nuclear@0 109 enum SampleWaitType {
nuclear@0 110 SampleWait_Zeroes, // We are waiting for a record with all zeros.
nuclear@0 111 SampleWait_Match // We are issuing & matching colors.
nuclear@0 112 };
nuclear@0 113
nuclear@0 114 SampleWaitType WaitMode;
nuclear@0 115 int MatchCount;
nuclear@0 116 // Records of frame timings that we are trying to measure.
nuclear@0 117 FrameTimeRecordEx FrameEndTimes[FramesTracked];
nuclear@0 118 int FrameIndex;
nuclear@0 119 // Median filter for (ScanoutTimeSeconds - PostPresent frame time)
nuclear@0 120 TimeDeltaCollector FrameDeltas;
nuclear@0 121 // Latency reporting results
nuclear@0 122 double RenderLatencySeconds;
nuclear@0 123 double TimewarpLatencySeconds;
nuclear@0 124 double LatencyRecordTime;
nuclear@0 125 };
nuclear@0 126
nuclear@0 127
nuclear@0 128
nuclear@0 129 //-------------------------------------------------------------------------------------
nuclear@0 130 // ***** FrameTimeManager
nuclear@0 131
nuclear@0 132 // FrameTimeManager keeps track of rendered frame timing and handles predictions for
nuclear@0 133 // orientations and time-warp.
nuclear@0 134
nuclear@0 135 class FrameTimeManager
nuclear@0 136 {
nuclear@0 137 public:
nuclear@0 138 FrameTimeManager(bool vsyncEnabled);
nuclear@0 139
nuclear@0 140 // Data that affects frame timing computation.
nuclear@0 141 struct TimingInputs
nuclear@0 142 {
nuclear@0 143 // Hard-coded value or dynamic as reported by FrameTimeDeltas.GetMedianTimeDelta().
nuclear@0 144 double FrameDelta;
nuclear@0 145 // Screen delay from present to scan-out, as potentially reported by ScreenLatencyTracker.
nuclear@0 146 double ScreenDelay;
nuclear@0 147 // Negative value of how many seconds before EndFrame we start timewarp. 0.0 if not used.
nuclear@0 148 double TimewarpWaitDelta;
nuclear@0 149
nuclear@0 150 TimingInputs()
nuclear@0 151 : FrameDelta(0), ScreenDelay(0), TimewarpWaitDelta(0)
nuclear@0 152 { }
nuclear@0 153 };
nuclear@0 154
nuclear@0 155 // Timing values for a specific frame.
nuclear@0 156 struct Timing
nuclear@0 157 {
nuclear@0 158 TimingInputs Inputs;
nuclear@0 159
nuclear@0 160 // Index of a frame that started at ThisFrameTime.
nuclear@0 161 unsigned int FrameIndex;
nuclear@0 162 // Predicted absolute times for when this frame will show up on screen.
nuclear@0 163 // Generally, all values will be >= NextFrameTime, since that's the time we expect next
nuclear@0 164 // vsync to succeed.
nuclear@0 165 double ThisFrameTime;
nuclear@0 166 double TimewarpPointTime;
nuclear@0 167 double NextFrameTime;
nuclear@0 168 double MidpointTime;
nuclear@0 169 double EyeRenderTimes[2];
nuclear@0 170 double TimeWarpStartEndTimes[2][2];
nuclear@0 171
nuclear@0 172 Timing()
nuclear@0 173 {
nuclear@0 174 memset(this, 0, sizeof(Timing));
nuclear@0 175 }
nuclear@0 176
nuclear@0 177 void InitTimingFromInputs(const TimingInputs& inputs, HmdShutterTypeEnum shutterType,
nuclear@0 178 double thisFrameTime, unsigned int frameIndex);
nuclear@0 179 };
nuclear@0 180
nuclear@0 181
nuclear@0 182 // Called on startup to provided data on HMD timing.
nuclear@0 183 void Init(HmdRenderInfo& renderInfo);
nuclear@0 184
nuclear@0 185 // Called with each new ConfigureRendering.
nuclear@0 186 void ResetFrameTiming(unsigned frameIndex,
nuclear@0 187 bool dynamicPrediction, bool sdkRender);
nuclear@0 188
nuclear@0 189 void SetVsync(bool enabled) { VsyncEnabled = enabled; }
nuclear@0 190
nuclear@0 191 // BeginFrame returns time of the call
nuclear@0 192 // TBD: Should this be a predicted time value instead ?
nuclear@0 193 double BeginFrame(unsigned frameIndex);
nuclear@0 194 void EndFrame();
nuclear@0 195
nuclear@0 196 // Thread-safe function to query timing for a future frame
nuclear@0 197 Timing GetFrameTiming(unsigned frameIndex);
nuclear@0 198
nuclear@0 199 // if eye == ovrEye_Count, timing is for MidpointTime as opposed to any specific eye
nuclear@0 200 double GetEyePredictionTime(ovrEyeType eye, unsigned int frameIndex);
nuclear@0 201 ovrTrackingState GetEyePredictionTracking(ovrHmd hmd, ovrEyeType eye, unsigned int frameIndex);
nuclear@0 202 Posef GetEyePredictionPose(ovrHmd hmd, ovrEyeType eye);
nuclear@0 203
nuclear@0 204 void GetTimewarpPredictions(ovrEyeType eye, double timewarpStartEnd[2]);
nuclear@0 205 void GetTimewarpMatrices(ovrHmd hmd, ovrEyeType eye, ovrPosef renderPose, ovrMatrix4f twmOut[2],double debugTimingOffsetInSeconds = 0.0);
nuclear@0 206
nuclear@0 207 // Used by renderer to determine if it should time distortion rendering.
nuclear@0 208 bool NeedDistortionTimeMeasurement() const;
nuclear@0 209 void AddDistortionTimeMeasurement(double distortionTimeSeconds);
nuclear@0 210
nuclear@0 211
nuclear@0 212 // DK2 Latency test interface
nuclear@0 213
nuclear@0 214 // Get next draw color for DK2 latency tester (3-byte RGB)
nuclear@0 215 void GetFrameLatencyTestDrawColor(unsigned char outColor[3])
nuclear@0 216 {
nuclear@0 217 outColor[0] = ScreenLatencyTracker.GetNextDrawColor();
nuclear@0 218 outColor[1] = ScreenLatencyTracker.IsLatencyTimingAvailable() ? 255 : 0;
nuclear@0 219 outColor[2] = ScreenLatencyTracker.IsLatencyTimingAvailable() ? 0 : 255;
nuclear@0 220 }
nuclear@0 221
nuclear@0 222 // Must be called after EndFrame() to update latency tester timings.
nuclear@0 223 // Must pass color reported by NextFrameColor for this frame.
nuclear@0 224 void UpdateFrameLatencyTrackingAfterEndFrame(unsigned char frameLatencyTestColor[3],
nuclear@0 225 const Util::FrameTimeRecordSet& rs);
nuclear@0 226
nuclear@0 227 void GetLatencyTimings(float& latencyRender, float& latencyTimewarp, float& latencyPostPresent)
nuclear@0 228 {
nuclear@0 229 return ScreenLatencyTracker.GetLatencyTimings(latencyRender, latencyTimewarp, latencyPostPresent);
nuclear@0 230 }
nuclear@0 231
nuclear@0 232 const Timing& GetFrameTiming() const { return FrameTiming; }
nuclear@0 233
nuclear@0 234 private:
nuclear@0 235 double calcFrameDelta() const;
nuclear@0 236 double calcScreenDelay() const;
nuclear@0 237 double calcTimewarpWaitDelta() const;
nuclear@0 238
nuclear@0 239 //Revisit dynamic pre-Timewarp delay adjustment logic
nuclear@0 240 /*
nuclear@0 241 void updateTimewarpTiming();
nuclear@0 242
nuclear@0 243
nuclear@0 244
nuclear@0 245 // TimewarpDelayAdjuster implements a simple state machine that reduces the amount
nuclear@0 246 // of time-warp waiting based on skipped frames.
nuclear@0 247 struct TimewarpDelayAdjuster
nuclear@0 248 {
nuclear@0 249 enum StateInLevel
nuclear@0 250 {
nuclear@0 251 // We are ok at this level, and will be waiting for some time before trying to reduce.
nuclear@0 252 State_WaitingToReduceLevel,
nuclear@0 253 // After decrementing a level, we are verifying that this won't cause skipped frames.
nuclear@0 254 State_VerifyingAfterReduce
nuclear@0 255 };
nuclear@0 256
nuclear@0 257 enum {
nuclear@0 258 MaxDelayLevel = 5,
nuclear@0 259 MaxInfiniteTimingLevel = 3,
nuclear@0 260 MaxTimeIndex = 6
nuclear@0 261 };
nuclear@0 262
nuclear@0 263 StateInLevel State;
nuclear@0 264 // Current level. Higher levels means larger delay reduction (smaller overall time-warp delay).
nuclear@0 265 int DelayLevel;
nuclear@0 266 // Index for the amount of time we'd wait in this level. If attempt to decrease level fails,
nuclear@0 267 // with is incrementing causing the level to become "sticky".
nuclear@0 268 int WaitTimeIndexForLevel[MaxTimeIndex + 1];
nuclear@0 269 // We skip few frames after each escalation to avoid too rapid of a reduction.
nuclear@0 270 int InitialFrameCounter;
nuclear@0 271 // What th currect "reduction" currently is.
nuclear@0 272 double TimewarpDelayReductionSeconds;
nuclear@0 273 // When we should try changing the level again.
nuclear@0 274 double DelayLevelFinishTime;
nuclear@0 275
nuclear@0 276 public:
nuclear@0 277 TimewarpDelayAdjuster() { Reset(); }
nuclear@0 278
nuclear@0 279 void Reset();
nuclear@0 280
nuclear@0 281 void UpdateTimewarpWaitIfSkippedFrames(FrameTimeManager* manager,
nuclear@0 282 double measuredFrameDelta,
nuclear@0 283 double nextFrameTime);
nuclear@0 284
nuclear@0 285 double GetDelayReduction() const { return TimewarpDelayReductionSeconds; }
nuclear@0 286 };
nuclear@0 287 */
nuclear@0 288
nuclear@0 289
nuclear@0 290 HmdRenderInfo RenderInfo;
nuclear@0 291 // Timings are collected through a median filter, to avoid outliers.
nuclear@0 292 TimeDeltaCollector FrameTimeDeltas;
nuclear@0 293 TimeDeltaCollector DistortionRenderTimes;
nuclear@0 294 FrameLatencyTracker ScreenLatencyTracker;
nuclear@0 295
nuclear@0 296 // Timing changes if we have no Vsync (all prediction is reduced to fixed interval).
nuclear@0 297 bool VsyncEnabled;
nuclear@0 298 // Set if we are rendering via the SDK, so DistortionRenderTimes is valid.
nuclear@0 299 bool DynamicPrediction;
nuclear@0 300 // Set if SDk is doing the rendering.
nuclear@0 301 bool SdkRender;
nuclear@0 302 // Direct to rift.
nuclear@0 303 bool DirectToRift;
nuclear@0 304
nuclear@0 305 // Total frame delay due to VsyncToFirstScanline, persistence and settle time.
nuclear@0 306 // Computed from RenderInfor.Shutter.
nuclear@0 307 double VSyncToScanoutDelay;
nuclear@0 308 double NoVSyncToScanoutDelay;
nuclear@0 309 double ScreenSwitchingDelay;
nuclear@0 310
nuclear@0 311 //Revisit dynamic pre-Timewarp delay adjustment logic
nuclear@0 312 //TimewarpDelayAdjuster TimewarpAdjuster;
nuclear@0 313
nuclear@0 314 // Current (or last) frame timing info. Used as a source for LocklessTiming.
nuclear@0 315 Timing FrameTiming;
nuclear@0 316 // TBD: Don't we need NextFrame here as well?
nuclear@0 317 LocklessUpdater<Timing, Timing> LocklessTiming;
nuclear@0 318
nuclear@0 319 // IMU Read timings
nuclear@0 320 double RenderIMUTimeSeconds;
nuclear@0 321 double TimewarpIMUTimeSeconds;
nuclear@0 322 };
nuclear@0 323
nuclear@0 324
nuclear@0 325 }} // namespace OVR::CAPI
nuclear@0 326
nuclear@0 327 #endif // OVR_CAPI_FrameTimeManager_h