ovr_sdk

diff 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
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/CAPI/CAPI_FrameTimeManager.h	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,327 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +Filename    :   CAPI_FrameTimeManager.h
     1.7 +Content     :   Manage frame timing and pose prediction for rendering
     1.8 +Created     :   November 30, 2013
     1.9 +Authors     :   Volga Aksoy, Michael Antonov
    1.10 +
    1.11 +Copyright   :   Copyright 2014 Oculus VR, LLC All Rights reserved.
    1.12 +
    1.13 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
    1.14 +you may not use the Oculus VR Rift SDK except in compliance with the License, 
    1.15 +which is provided at the time of installation or download, or which 
    1.16 +otherwise accompanies this software in either electronic or hard copy form.
    1.17 +
    1.18 +You may obtain a copy of the License at
    1.19 +
    1.20 +http://www.oculusvr.com/licenses/LICENSE-3.2 
    1.21 +
    1.22 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
    1.23 +distributed under the License is distributed on an "AS IS" BASIS,
    1.24 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.25 +See the License for the specific language governing permissions and
    1.26 +limitations under the License.
    1.27 +
    1.28 +************************************************************************************/
    1.29 +
    1.30 +#ifndef OVR_CAPI_FrameTimeManager_h
    1.31 +#define OVR_CAPI_FrameTimeManager_h
    1.32 +
    1.33 +#include "../OVR_CAPI.h"
    1.34 +#include "../Kernel/OVR_Timer.h"
    1.35 +#include "../Kernel/OVR_Math.h"
    1.36 +#include "../Util/Util_Render_Stereo.h"
    1.37 +
    1.38 +namespace OVR { namespace CAPI {
    1.39 +
    1.40 +
    1.41 +//-------------------------------------------------------------------------------------
    1.42 +// ***** TimeDeltaCollector
    1.43 +
    1.44 +// Helper class to collect median times between frames, so that we know
    1.45 +// how long to wait. 
    1.46 +struct TimeDeltaCollector
    1.47 +{
    1.48 +    TimeDeltaCollector() : Median(-1.0), Count(0), ReCalcMedian(true) { }
    1.49 +
    1.50 +    void    AddTimeDelta(double timeSeconds);
    1.51 +    void    Clear() { Count = 0; }
    1.52 +
    1.53 +    double  GetMedianTimeDelta() const;
    1.54 +    double  GetMedianTimeDeltaNoFirmwareHack() const;
    1.55 +
    1.56 +    double  GetCount() const { return Count; }
    1.57 +
    1.58 +    enum { Capacity = 12 };
    1.59 +private:
    1.60 +    double  TimeBufferSeconds[Capacity];
    1.61 +    mutable double  Median;
    1.62 +    int     Count;
    1.63 +    mutable bool    ReCalcMedian;
    1.64 +};
    1.65 +
    1.66 +
    1.67 +//-------------------------------------------------------------------------------------
    1.68 +// ***** FrameLatencyTracker
    1.69 +
    1.70 +// FrameLatencyTracker tracks frame Present to display Scan-out timing, as reported by
    1.71 +// the DK2 internal latency tester pixel read-back. The computed value is used in
    1.72 +// FrameTimeManager for prediction. View Render and TimeWarp to scan-out latencies are
    1.73 +// also reported for debugging.
    1.74 +//
    1.75 +// The class operates by generating color values from GetNextDrawColor() that must
    1.76 +// be rendered on the back end and then looking for matching values in FrameTimeRecordSet
    1.77 +// structure as reported by HW.
    1.78 +
    1.79 +class FrameLatencyTracker
    1.80 +{
    1.81 +public:
    1.82 +
    1.83 +    enum { FramesTracked = Util::LT2_IncrementCount-1 };
    1.84 +
    1.85 +    FrameLatencyTracker();
    1.86 +
    1.87 +    // DrawColor == 0 is special in that it doesn't need saving of timestamp
    1.88 +    unsigned char GetNextDrawColor();
    1.89 +
    1.90 +    void SaveDrawColor(unsigned char drawColor, double endFrameTime,
    1.91 +                       double renderIMUTime, double timewarpIMUTime );
    1.92 +
    1.93 +    void MatchRecord(const Util::FrameTimeRecordSet &r);   
    1.94 +
    1.95 +    bool IsLatencyTimingAvailable();
    1.96 +    void GetLatencyTimings(float& latencyRender, float& latencyTimewarp, float& latencyPostPresent);
    1.97 +
    1.98 +    void Reset();
    1.99 +
   1.100 +public:
   1.101 +
   1.102 +    struct FrameTimeRecordEx : public Util::FrameTimeRecord
   1.103 +    {
   1.104 +        bool    MatchedRecord;
   1.105 +        double  RenderIMUTimeSeconds;
   1.106 +        double  TimewarpIMUTimeSeconds;
   1.107 +    };
   1.108 +
   1.109 +    // True if rendering read-back is enabled.
   1.110 +    bool                  TrackerEnabled;
   1.111 +
   1.112 +    enum SampleWaitType {
   1.113 +        SampleWait_Zeroes, // We are waiting for a record with all zeros.
   1.114 +        SampleWait_Match   // We are issuing & matching colors.
   1.115 +    };
   1.116 +    
   1.117 +    SampleWaitType        WaitMode;
   1.118 +    int                   MatchCount;
   1.119 +    // Records of frame timings that we are trying to measure.
   1.120 +    FrameTimeRecordEx     FrameEndTimes[FramesTracked];
   1.121 +    int                   FrameIndex;
   1.122 +    // Median filter for (ScanoutTimeSeconds - PostPresent frame time)
   1.123 +    TimeDeltaCollector    FrameDeltas;
   1.124 +    // Latency reporting results
   1.125 +    double                RenderLatencySeconds;
   1.126 +    double                TimewarpLatencySeconds;
   1.127 +    double                LatencyRecordTime;
   1.128 +};
   1.129 +
   1.130 +
   1.131 +
   1.132 +//-------------------------------------------------------------------------------------
   1.133 +// ***** FrameTimeManager
   1.134 +
   1.135 +// FrameTimeManager keeps track of rendered frame timing and handles predictions for
   1.136 +// orientations and time-warp.
   1.137 +
   1.138 +class FrameTimeManager
   1.139 +{
   1.140 +public:
   1.141 +    FrameTimeManager(bool vsyncEnabled);
   1.142 +
   1.143 +    // Data that affects frame timing computation.
   1.144 +    struct TimingInputs
   1.145 +    {
   1.146 +        // Hard-coded value or dynamic as reported by FrameTimeDeltas.GetMedianTimeDelta().
   1.147 +        double              FrameDelta;
   1.148 +        // Screen delay from present to scan-out, as potentially reported by ScreenLatencyTracker.
   1.149 +        double              ScreenDelay;
   1.150 +        // Negative value of how many seconds before EndFrame we start timewarp. 0.0 if not used.
   1.151 +        double              TimewarpWaitDelta;
   1.152 +        
   1.153 +        TimingInputs()
   1.154 +            : FrameDelta(0), ScreenDelay(0), TimewarpWaitDelta(0)
   1.155 +        { }
   1.156 +    };
   1.157 +
   1.158 +    // Timing values for a specific frame.
   1.159 +    struct Timing
   1.160 +    {
   1.161 +        TimingInputs        Inputs;
   1.162 +        
   1.163 +        // Index of a frame that started at ThisFrameTime.
   1.164 +        unsigned int        FrameIndex;
   1.165 +        // Predicted absolute times for when this frame will show up on screen.
   1.166 +        // Generally, all values will be >= NextFrameTime, since that's the time we expect next
   1.167 +        // vsync to succeed.
   1.168 +        double              ThisFrameTime;
   1.169 +        double              TimewarpPointTime;
   1.170 +        double              NextFrameTime;        
   1.171 +        double              MidpointTime;
   1.172 +        double              EyeRenderTimes[2];
   1.173 +        double              TimeWarpStartEndTimes[2][2];
   1.174 +
   1.175 +        Timing()
   1.176 +        {
   1.177 +            memset(this, 0, sizeof(Timing));
   1.178 +        }
   1.179 +
   1.180 +        void InitTimingFromInputs(const TimingInputs& inputs, HmdShutterTypeEnum shutterType,
   1.181 +                                  double thisFrameTime, unsigned int frameIndex);
   1.182 +    };
   1.183 +
   1.184 +   
   1.185 +    // Called on startup to provided data on HMD timing.
   1.186 +    void    Init(HmdRenderInfo& renderInfo);
   1.187 +
   1.188 +    // Called with each new ConfigureRendering.
   1.189 +    void    ResetFrameTiming(unsigned frameIndex,
   1.190 +                             bool dynamicPrediction, bool sdkRender);
   1.191 +
   1.192 +    void    SetVsync(bool enabled) { VsyncEnabled = enabled; }
   1.193 +
   1.194 +    // BeginFrame returns time of the call
   1.195 +    // TBD: Should this be a predicted time value instead ?
   1.196 +    double  BeginFrame(unsigned frameIndex);
   1.197 +    void    EndFrame();    
   1.198 +
   1.199 +    // Thread-safe function to query timing for a future frame
   1.200 +    Timing  GetFrameTiming(unsigned frameIndex);
   1.201 + 
   1.202 +    // if eye == ovrEye_Count, timing is for MidpointTime as opposed to any specific eye
   1.203 +    double           GetEyePredictionTime(ovrEyeType eye, unsigned int frameIndex);
   1.204 +    ovrTrackingState GetEyePredictionTracking(ovrHmd hmd, ovrEyeType eye, unsigned int frameIndex);
   1.205 +    Posef            GetEyePredictionPose(ovrHmd hmd, ovrEyeType eye);
   1.206 +
   1.207 +    void    GetTimewarpPredictions(ovrEyeType eye, double timewarpStartEnd[2]); 
   1.208 +    void    GetTimewarpMatrices(ovrHmd hmd, ovrEyeType eye, ovrPosef renderPose, ovrMatrix4f twmOut[2],double debugTimingOffsetInSeconds = 0.0);
   1.209 +
   1.210 +    // Used by renderer to determine if it should time distortion rendering.
   1.211 +    bool    NeedDistortionTimeMeasurement() const;
   1.212 +    void    AddDistortionTimeMeasurement(double distortionTimeSeconds);
   1.213 +
   1.214 +    
   1.215 +    // DK2 Latency test interface
   1.216 +    
   1.217 +    // Get next draw color for DK2 latency tester (3-byte RGB)
   1.218 +    void GetFrameLatencyTestDrawColor(unsigned char outColor[3])
   1.219 +    {
   1.220 +        outColor[0] = ScreenLatencyTracker.GetNextDrawColor();
   1.221 +        outColor[1] = ScreenLatencyTracker.IsLatencyTimingAvailable() ? 255 : 0;
   1.222 +        outColor[2] = ScreenLatencyTracker.IsLatencyTimingAvailable() ? 0 : 255;
   1.223 +    }
   1.224 +
   1.225 +    // Must be called after EndFrame() to update latency tester timings.
   1.226 +    // Must pass color reported by NextFrameColor for this frame.
   1.227 +    void    UpdateFrameLatencyTrackingAfterEndFrame(unsigned char frameLatencyTestColor[3],
   1.228 +                                                    const Util::FrameTimeRecordSet& rs);
   1.229 +
   1.230 +    void    GetLatencyTimings(float& latencyRender, float& latencyTimewarp, float& latencyPostPresent)
   1.231 +    {
   1.232 +        return ScreenLatencyTracker.GetLatencyTimings(latencyRender, latencyTimewarp, latencyPostPresent);
   1.233 +    }
   1.234 +
   1.235 +    const Timing& GetFrameTiming() const { return FrameTiming; }
   1.236 +
   1.237 +private:
   1.238 +    double  calcFrameDelta() const;
   1.239 +    double  calcScreenDelay() const;
   1.240 +    double  calcTimewarpWaitDelta() const;
   1.241 +
   1.242 +    //Revisit dynamic pre-Timewarp delay adjustment logic
   1.243 +    /*
   1.244 +    void    updateTimewarpTiming();
   1.245 +
   1.246 +
   1.247 +    
   1.248 +    // TimewarpDelayAdjuster implements a simple state machine that reduces the amount
   1.249 +    // of time-warp waiting based on skipped frames. 
   1.250 +    struct TimewarpDelayAdjuster
   1.251 +    {
   1.252 +        enum StateInLevel
   1.253 +        {        
   1.254 +            // We are ok at this level, and will be waiting for some time before trying to reduce.
   1.255 +            State_WaitingToReduceLevel,  
   1.256 +            // After decrementing a level, we are verifying that this won't cause skipped frames.
   1.257 +            State_VerifyingAfterReduce
   1.258 +       };
   1.259 +    
   1.260 +        enum {
   1.261 +            MaxDelayLevel          = 5,
   1.262 +            MaxInfiniteTimingLevel = 3,
   1.263 +            MaxTimeIndex           = 6
   1.264 +        };
   1.265 +
   1.266 +        StateInLevel State;   
   1.267 +        // Current level. Higher levels means larger delay reduction (smaller overall time-warp delay).
   1.268 +        int          DelayLevel;
   1.269 +        // Index for the amount of time we'd wait in this level. If attempt to decrease level fails,
   1.270 +        // with is incrementing causing the level to become "sticky". 
   1.271 +        int          WaitTimeIndexForLevel[MaxTimeIndex + 1];
   1.272 +        // We skip few frames after each escalation to avoid too rapid of a reduction.
   1.273 +        int          InitialFrameCounter;
   1.274 +        // What th currect "reduction" currently is.
   1.275 +        double       TimewarpDelayReductionSeconds;
   1.276 +        // When we should try changing the level again.
   1.277 +        double       DelayLevelFinishTime;
   1.278 +
   1.279 +    public:
   1.280 +        TimewarpDelayAdjuster() { Reset(); }
   1.281 +
   1.282 +        void    Reset();
   1.283 +
   1.284 +        void    UpdateTimewarpWaitIfSkippedFrames(FrameTimeManager* manager,
   1.285 +                                                  double measuredFrameDelta,
   1.286 +                                                  double nextFrameTime);
   1.287 +
   1.288 +        double  GetDelayReduction() const { return TimewarpDelayReductionSeconds; }
   1.289 +    };
   1.290 +    */
   1.291 +
   1.292 +    
   1.293 +    HmdRenderInfo       RenderInfo;
   1.294 +    // Timings are collected through a median filter, to avoid outliers.
   1.295 +    TimeDeltaCollector  FrameTimeDeltas;
   1.296 +    TimeDeltaCollector  DistortionRenderTimes;
   1.297 +    FrameLatencyTracker ScreenLatencyTracker;
   1.298 +
   1.299 +    // Timing changes if we have no Vsync (all prediction is reduced to fixed interval).
   1.300 +    bool                VsyncEnabled;
   1.301 +    // Set if we are rendering via the SDK, so DistortionRenderTimes is valid.
   1.302 +    bool                DynamicPrediction;
   1.303 +    // Set if SDk is doing the rendering.
   1.304 +    bool                SdkRender;
   1.305 +    // Direct to rift.
   1.306 +    bool                DirectToRift;
   1.307 +
   1.308 +    // Total frame delay due to VsyncToFirstScanline, persistence and settle time.
   1.309 +    // Computed from RenderInfor.Shutter.
   1.310 +    double              VSyncToScanoutDelay;
   1.311 +    double              NoVSyncToScanoutDelay;
   1.312 +    double              ScreenSwitchingDelay;
   1.313 +
   1.314 +    //Revisit dynamic pre-Timewarp delay adjustment logic
   1.315 +    //TimewarpDelayAdjuster  TimewarpAdjuster;
   1.316 +
   1.317 +    // Current (or last) frame timing info. Used as a source for LocklessTiming.
   1.318 +    Timing                  FrameTiming;
   1.319 +    // TBD: Don't we need NextFrame here as well?
   1.320 +    LocklessUpdater<Timing, Timing> LocklessTiming;
   1.321 +
   1.322 +    // IMU Read timings
   1.323 +    double              RenderIMUTimeSeconds;
   1.324 +    double              TimewarpIMUTimeSeconds;
   1.325 +};
   1.326 +
   1.327 +
   1.328 +}} // namespace OVR::CAPI
   1.329 +
   1.330 +#endif // OVR_CAPI_FrameTimeManager_h