nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : Util_Render_Stereo.h nuclear@0: Content : Sample stereo rendering configuration classes. nuclear@0: Created : October 22, 2012 nuclear@0: Authors : Michael Antonov, Tom Forsyth nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: *************************************************************************************/ nuclear@0: nuclear@0: #ifndef OVR_Util_Render_Stereo_h nuclear@0: #define OVR_Util_Render_Stereo_h nuclear@0: nuclear@0: #include "../OVR_Stereo.h" nuclear@0: #include "../Tracking/Tracking_SensorStateReader.h" nuclear@0: nuclear@0: namespace OVR { namespace Util { namespace Render { nuclear@0: nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // **** Useful debug functions. nuclear@0: // nuclear@0: // Purely for debugging - the results are not very end-user-friendly. nuclear@0: char const* GetDebugNameEyeCupType ( EyeCupType eyeCupType ); nuclear@0: char const* GetDebugNameHmdType ( HmdTypeEnum hmdType ); nuclear@0: nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // **** Higher-level utility functions. nuclear@0: nuclear@0: Sizei CalculateRecommendedTextureSize ( HmdRenderInfo const &hmd, nuclear@0: bool bRendertargetSharedByBothEyes, nuclear@0: float pixelDensityInCenter = 1.0f ); nuclear@0: nuclear@0: FovPort CalculateRecommendedFov ( HmdRenderInfo const &hmd, nuclear@0: StereoEye eyeType, nuclear@0: bool bMakeFovSymmetrical = false); nuclear@0: nuclear@0: StereoEyeParams CalculateStereoEyeParams ( HmdRenderInfo const &hmd, nuclear@0: StereoEye eyeType, nuclear@0: Sizei const &actualRendertargetSurfaceSize, nuclear@0: bool bRendertargetSharedByBothEyes, nuclear@0: bool bRightHanded = true, nuclear@0: float zNear = 0.01f, float zFar = 10000.0f, nuclear@0: Sizei const *pOverrideRenderedPixelSize = NULL, nuclear@0: FovPort const *pOverrideFovport = NULL, nuclear@0: float zoomFactor = 1.0f ); nuclear@0: nuclear@0: Vector3f CalculateEyeVirtualCameraOffset(HmdRenderInfo const &hmd, nuclear@0: StereoEye eyeType, bool bMonoRenderingMode ); nuclear@0: nuclear@0: nuclear@0: // These are two components from StereoEyeParams that can be changed nuclear@0: // very easily without full recomputation of everything. nuclear@0: struct ViewportScaleAndOffset nuclear@0: { nuclear@0: Recti RenderedViewport; nuclear@0: ScaleAndOffset2D EyeToSourceUV; nuclear@0: }; nuclear@0: nuclear@0: // Three ways to override the size of the render view dynamically. nuclear@0: // None of these require changing the distortion parameters or the regenerating the distortion mesh, nuclear@0: // and can be called every frame if desired. nuclear@0: ViewportScaleAndOffset ModifyRenderViewport ( StereoEyeParams const ¶ms, nuclear@0: Sizei const &actualRendertargetSurfaceSize, nuclear@0: Recti const &renderViewport ); nuclear@0: nuclear@0: ViewportScaleAndOffset ModifyRenderSize ( StereoEyeParams const ¶ms, nuclear@0: Sizei const &actualRendertargetSurfaceSize, nuclear@0: Sizei const &requestedRenderSize, nuclear@0: bool bRendertargetSharedByBothEyes = false ); nuclear@0: nuclear@0: ViewportScaleAndOffset ModifyRenderDensity ( StereoEyeParams const ¶ms, nuclear@0: Sizei const &actualRendertargetSurfaceSize, nuclear@0: float pixelDensity = 1.0f, nuclear@0: bool bRendertargetSharedByBothEyes = false ); nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** StereoConfig nuclear@0: nuclear@0: // StereoConfig maintains a scene stereo state and allow switching between different nuclear@0: // stereo rendering modes. To support rendering, StereoConfig keeps track of HMD nuclear@0: // variables such as screen size, eye-to-screen distance and distortion, and computes nuclear@0: // extra data such as FOV and distortion center offsets based on it. Rendering nuclear@0: // parameters are returned though StereoEyeParams for each eye. nuclear@0: // nuclear@0: // Beyond regular 3D projection, this class supports rendering a 2D orthographic nuclear@0: // surface for UI and text. The 2D surface will be defined by CreateOrthoSubProjection(). nuclear@0: // The (0,0) coordinate corresponds to eye center location. nuclear@0: // nuclear@0: // Applications are not required to use this class, but they should be doing very nuclear@0: // similar sequences of operations, and it may be useful to start with this class nuclear@0: // and modify it. nuclear@0: nuclear@0: struct StereoEyeParamsWithOrtho nuclear@0: { nuclear@0: StereoEyeParams StereoEye; nuclear@0: Matrix4f OrthoProjection; nuclear@0: }; nuclear@0: nuclear@0: struct ViewportScaleAndOffsetBothEyes nuclear@0: { nuclear@0: ViewportScaleAndOffset Left; nuclear@0: ViewportScaleAndOffset Right; nuclear@0: }; nuclear@0: nuclear@0: class StereoConfig nuclear@0: { nuclear@0: public: nuclear@0: nuclear@0: // StereoMode describes rendering modes that can be used by StereoConfig. nuclear@0: // These modes control whether stereo rendering is used or not (Stereo_None), nuclear@0: // and how it is implemented. nuclear@0: enum StereoMode nuclear@0: { nuclear@0: Stereo_None = 0, // Single eye nuclear@0: Stereo_LeftRight_Multipass = 1, // One frustum per eye nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: StereoConfig(StereoMode mode = Stereo_LeftRight_Multipass); nuclear@0: nuclear@0: //--------------------------------------------------------------------------------------------- nuclear@0: // *** Core functions - every app MUST call these functions at least once. nuclear@0: nuclear@0: // Sets HMD parameters; also initializes distortion coefficients. nuclear@0: void SetHmdRenderInfo(const HmdRenderInfo& hmd); nuclear@0: nuclear@0: // Set the physical size of the rendertarget surface the app created, nuclear@0: // and whether one RT is shared by both eyes, or each eye has its own RT: nuclear@0: // true: both eyes are rendered to the same RT. Left eye starts at top-left, right eye starts at top-middle. nuclear@0: // false: each eye is rendered to its own RT. Some GPU architectures prefer this arrangement. nuclear@0: // Typically, the app would call CalculateRecommendedTextureSize() to suggest the choice of RT size. nuclear@0: // This setting must be exactly the size of the actual RT created, or the UVs produced will be incorrect. nuclear@0: // If the app wants to render to a subsection of the RT, it should use SetRenderSize() nuclear@0: void SetRendertargetSize (Size const rendertargetSize, nuclear@0: bool rendertargetIsSharedByBothEyes ); nuclear@0: nuclear@0: // Returns full set of Stereo rendering parameters for the specified eye. nuclear@0: const StereoEyeParamsWithOrtho& GetEyeRenderParams(StereoEye eye); nuclear@0: nuclear@0: nuclear@0: nuclear@0: //--------------------------------------------------------------------------------------------- nuclear@0: // *** Optional functions - an app may call these to override default behaviours. nuclear@0: nuclear@0: const HmdRenderInfo& GetHmdRenderInfo() const { return Hmd; } nuclear@0: nuclear@0: // Returns the recommended size of rendertargets. nuclear@0: // If rendertargetIsSharedByBothEyes is true, this is the size of the combined buffer. nuclear@0: // If rendertargetIsSharedByBothEyes is false, this is the size of each individual buffer. nuclear@0: // pixelDensityInCenter may be set to any number - by default it will match the HMD resolution in the center of the image. nuclear@0: // After creating the rendertargets, the application MUST call SetRendertargetSize() with the actual size created nuclear@0: // (which can be larger or smaller as the app wishes, but StereoConfig needs to know either way) nuclear@0: Sizei CalculateRecommendedTextureSize ( bool rendertargetSharedByBothEyes, nuclear@0: float pixelDensityInCenter = 1.0f ); nuclear@0: nuclear@0: // Sets a stereo rendering mode and updates internal cached nuclear@0: // state (matrices, per-eye view) based on it. nuclear@0: void SetStereoMode(StereoMode mode) { Mode = mode; DirtyFlag = true; } nuclear@0: StereoMode GetStereoMode() const { return Mode; } nuclear@0: nuclear@0: // Sets the fieldOfView that the 2D coordinate area stretches to. nuclear@0: void Set2DAreaFov(float fovRadians); nuclear@0: nuclear@0: // Really only for science experiments - no normal app should ever need to override nuclear@0: // the HMD's lens descriptors. Passing NULL removes the override. nuclear@0: // Supply both = set left and right. nuclear@0: // Supply just left = set both to the same. nuclear@0: // Supply neither = remove override. nuclear@0: void SetLensOverride ( LensConfig const *pLensOverrideLeft = NULL, nuclear@0: LensConfig const *pLensOverrideRight = NULL ); nuclear@0: nuclear@0: // Override the rendered FOV in various ways. All angles in tangent units. nuclear@0: // This is not clamped to the physical FOV of the display - you'll need to do that yourself! nuclear@0: // Supply both = set left and right. nuclear@0: // Supply just left = set both to the same. nuclear@0: // Supply neither = remove override. nuclear@0: void SetFov ( FovPort const *pfovLeft = NULL, nuclear@0: FovPort const *pfovRight = NULL ); nuclear@0: nuclear@0: void SetFovPortRadians ( float horizontal, float vertical ) nuclear@0: { nuclear@0: FovPort fov = FovPort::CreateFromRadians(horizontal, vertical); nuclear@0: SetFov( &fov, &fov ); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // This forces a "zero IPD" mode where there is just a single render with an FOV that nuclear@0: // is the union of the two calculated FOVs. nuclear@0: // The calculated render is for the left eye. Any size & FOV overrides for the right nuclear@0: // eye will be ignored. nuclear@0: // If you query the right eye's size, you will get the same render nuclear@0: // size & position as the left eye - you should not actually do the render of course! nuclear@0: // The distortion values will be different, because it goes to a different place on the framebuffer. nuclear@0: // Note that if you do this, the rendertarget does not need to be twice the width of nuclear@0: // the render size any more. nuclear@0: void SetZeroVirtualIpdOverride ( bool enableOverride ); nuclear@0: nuclear@0: // Allows the app to specify near and far clip planes and the right/left-handedness of the projection matrix. nuclear@0: void SetZClipPlanesAndHandedness ( float zNear = 0.01f, float zFar = 10000.0f, nuclear@0: bool rightHandedProjection = true ); nuclear@0: nuclear@0: // Allows the app to specify how much extra eye rotation to allow when determining the visible FOV. nuclear@0: void SetExtraEyeRotation ( float extraEyeRotationInRadians = 0.0f ); nuclear@0: nuclear@0: // The dirty flag is set by any of the above calls. Just handy for the app to know nuclear@0: // if e.g. the distortion mesh needs regeneration. nuclear@0: void SetDirty() { DirtyFlag = true; } nuclear@0: bool IsDirty() { return DirtyFlag; } nuclear@0: nuclear@0: // An app never needs to call this - GetEyeRenderParams will call it internally if nuclear@0: // the state is dirty. However apps can call this explicitly to control when and where nuclear@0: // computation is performed (e.g. not inside critical loops) nuclear@0: void UpdateComputedState(); nuclear@0: nuclear@0: // This returns the projection matrix with a "zoom". Does not modify any internal state. nuclear@0: Matrix4f GetProjectionWithZoom ( StereoEye eye, float fovZoom ) const; nuclear@0: nuclear@0: nuclear@0: //--------------------------------------------------------------------------------------------- nuclear@0: // The SetRender* functions are special. nuclear@0: // nuclear@0: // They do not require a full recalculation of state, and they do not change anything but the nuclear@0: // ViewportScaleAndOffset data for the eyes (which they return), and do not set the dirty flag! nuclear@0: // This means they can be called without regenerating the distortion mesh, and thus nuclear@0: // can happily be called every frame without causing performance problems. Dynamic rescaling nuclear@0: // of the rendertarget can help keep framerate up in demanding VR applications. nuclear@0: // See the documentation for more details on their use. nuclear@0: nuclear@0: // Specify a pixel density - how many rendered pixels per pixel in the physical display. nuclear@0: ViewportScaleAndOffsetBothEyes SetRenderDensity ( float pixelsPerDisplayPixel ); nuclear@0: nuclear@0: // Supply the size directly. Will be clamped to the physical rendertarget size. nuclear@0: ViewportScaleAndOffsetBothEyes SetRenderSize ( Sizei const &renderSizeLeft, Sizei const &renderSizeRight ); nuclear@0: nuclear@0: // Supply the viewport directly. This is not clamped to the physical rendertarget - careful now! nuclear@0: ViewportScaleAndOffsetBothEyes SetRenderViewport ( Recti const &renderViewportLeft, Recti const &renderViewportRight ); nuclear@0: nuclear@0: private: nuclear@0: nuclear@0: // *** Modifiable State nuclear@0: nuclear@0: StereoMode Mode; nuclear@0: HmdRenderInfo Hmd; nuclear@0: nuclear@0: float Area2DFov; // FOV range mapping to the 2D area. nuclear@0: nuclear@0: // Only one of these three overrides can be true! nuclear@0: enum SetViewportModeEnum nuclear@0: { nuclear@0: SVPM_Density, nuclear@0: SVPM_Size, nuclear@0: SVPM_Viewport, nuclear@0: } SetViewportMode; nuclear@0: // ...and depending which it is, one of the following are used. nuclear@0: float SetViewportPixelsPerDisplayPixel; nuclear@0: Sizei SetViewportSize[2]; nuclear@0: Recti SetViewport[2]; nuclear@0: nuclear@0: // Other overrides. nuclear@0: bool OverrideLens; nuclear@0: LensConfig LensOverrideLeft; nuclear@0: LensConfig LensOverrideRight; nuclear@0: Sizei RendertargetSize; nuclear@0: bool OverrideTanHalfFov; nuclear@0: FovPort FovOverrideLeft; nuclear@0: FovPort FovOverrideRight; nuclear@0: bool OverrideZeroIpd; nuclear@0: float ZNear; nuclear@0: float ZFar; nuclear@0: float ExtraEyeRotationInRadians; nuclear@0: bool IsRendertargetSharedByBothEyes; nuclear@0: bool RightHandedProjection; nuclear@0: nuclear@0: bool DirtyFlag; // Set when any if the modifiable state changed. Does NOT get set by SetRender*() nuclear@0: nuclear@0: // Utility function. nuclear@0: ViewportScaleAndOffsetBothEyes setupViewportScaleAndOffsets(); nuclear@0: nuclear@0: // *** Computed State nuclear@0: nuclear@0: public: // Small hack for the config tool. Normal code should never read EyeRenderParams directly - use GetEyeRenderParams() instead. nuclear@0: // 0/1 = left/right main views. nuclear@0: StereoEyeParamsWithOrtho EyeRenderParams[2]; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Distortion Mesh Rendering nuclear@0: // nuclear@0: nuclear@0: // Stores both texture UV coords, or tan(angle) values. nuclear@0: // Use whichever set of data the specific distortion algorithm requires. nuclear@0: // This struct *must* be binary compatible with CAPI ovrDistortionVertex. nuclear@0: struct DistortionMeshVertexData nuclear@0: { nuclear@0: // [-1,+1],[-1,+1] over the entire framebuffer. nuclear@0: Vector2f ScreenPosNDC; nuclear@0: // [0.0-1.0] interpolation value for timewarping - see documentation for details. nuclear@0: float TimewarpLerp; nuclear@0: // [0.0-1.0] fade-to-black at the edges to reduce peripheral vision noise. nuclear@0: float Shade; nuclear@0: // The red, green, and blue vectors in tan(angle) space. nuclear@0: // Scale and offset by the values in StereoEyeParams.EyeToSourceUV.Scale nuclear@0: // and StereoParams.EyeToSourceUV.Offset to get to real texture UV coords. nuclear@0: Vector2f TanEyeAnglesR; nuclear@0: Vector2f TanEyeAnglesG; nuclear@0: Vector2f TanEyeAnglesB; nuclear@0: }; nuclear@0: nuclear@0: // If you just want a single point on the screen transformed. nuclear@0: DistortionMeshVertexData DistortionMeshMakeVertex ( Vector2f screenNDC, nuclear@0: bool rightEye, nuclear@0: const HmdRenderInfo &hmdRenderInfo, nuclear@0: const DistortionRenderDesc &distortion, const ScaleAndOffset2D &eyeToSourceNDC ); nuclear@0: nuclear@0: void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, nuclear@0: int *pNumVertices, int *pNumTriangles, nuclear@0: const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo ); nuclear@0: nuclear@0: // Generate distortion mesh for a eye. nuclear@0: // This version requires less data then stereoParms, supporting dynamic change in render target viewport. nuclear@0: void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, nuclear@0: int *pNumVertices, int *pNumTriangles, nuclear@0: bool rightEye, nuclear@0: const HmdRenderInfo &hmdRenderInfo, nuclear@0: const DistortionRenderDesc &distortion, const ScaleAndOffset2D &eyeToSourceNDC ); nuclear@0: nuclear@0: void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices ); nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Heightmap Mesh Rendering nuclear@0: // nuclear@0: nuclear@0: // Stores both texture UV coords, or tan(angle) values. nuclear@0: // This struct *must* be binary compatible with CAPI ovrHeightmapVertex. nuclear@0: struct HeightmapMeshVertexData nuclear@0: { nuclear@0: // [-1,+1],[-1,+1] over the entire framebuffer. nuclear@0: Vector2f ScreenPosNDC; nuclear@0: // [0.0-1.0] interpolation value for timewarping - see documentation for details. nuclear@0: float TimewarpLerp; nuclear@0: // The vectors in tan(angle) space. nuclear@0: // Scale and offset by the values in StereoEyeParams.EyeToSourceUV.Scale nuclear@0: // and StereoParams.EyeToSourceUV.Offset to get to real texture UV coords. nuclear@0: Vector2f TanEyeAngles; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, nuclear@0: int *pNumVertices, int *pNumTriangles, nuclear@0: const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo ); nuclear@0: nuclear@0: // Generate heightmap mesh for a eye. This version requires less data then stereoParms, supporting nuclear@0: // dynamic change in render target viewport. nuclear@0: void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices, nuclear@0: int *pNumVertices, int *pNumTriangles, bool rightEye, nuclear@0: const HmdRenderInfo &hmdRenderInfo, const ScaleAndOffset2D &eyeToSourceNDC ); nuclear@0: nuclear@0: void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices ); nuclear@0: nuclear@0: nuclear@0: nuclear@0: //----------------------------------------------------------------------------------- nuclear@0: // ***** Prediction and timewarp. nuclear@0: // nuclear@0: nuclear@0: struct PredictionValues nuclear@0: { nuclear@0: // All values in seconds. nuclear@0: // These are the times in seconds from a present+flush to the relevant display element. nuclear@0: // The time is measured to the middle of that element's visibility window, nuclear@0: // e.g. if the device is a full-persistence display, the element will be visible for nuclear@0: // an entire frame, so the time measures to the middle of that period, i.e. half the frame time. nuclear@0: float PresentFlushToRenderedScene; // To the overall rendered 3D scene being visible. nuclear@0: float PresentFlushToTimewarpStart; // To when the first timewarped scanline will be visible. nuclear@0: float PresentFlushToTimewarpEnd; // To when the last timewarped scanline will be visible. nuclear@0: float PresentFlushToPresentFlush; // To the next present+flush, i.e. the ideal framerate. nuclear@0: nuclear@0: bool WithTimewarp; nuclear@0: bool WithVsync; nuclear@0: }; nuclear@0: nuclear@0: // Calculates the values from the HMD info. nuclear@0: PredictionValues PredictionGetDeviceValues ( const HmdRenderInfo &hmdRenderInfo, nuclear@0: bool withTimewarp = true, nuclear@0: bool withVsync = true ); nuclear@0: nuclear@0: // Pass in an orientation used to render the scene, and then the predicted orientation nuclear@0: // (which may have been computed later on, and thus is more accurate), and this nuclear@0: // will return the matrix to pass to the timewarp distortion shader. nuclear@0: // TODO: deal with different handedness? nuclear@0: Matrix4f TimewarpComputePoseDelta ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&hmdToEyeViewOffset ); nuclear@0: Matrix4f TimewarpComputePoseDeltaPosition ( Matrix4f const &renderedViewFromWorld, Matrix4f const &predictedViewFromWorld, Matrix4f const&hmdToEyeViewOffset ); nuclear@0: nuclear@0: nuclear@0: nuclear@0: // TimewarpMachine helps keep track of rendered frame timing and nuclear@0: // handles predictions for time-warp rendering. nuclear@0: class TimewarpMachine nuclear@0: { nuclear@0: public: nuclear@0: TimewarpMachine(); nuclear@0: nuclear@0: // Call this on and every time something about the setup changes. nuclear@0: void Reset ( HmdRenderInfo& renderInfo, bool vsyncEnabled, double timeNow ); nuclear@0: nuclear@0: // The only reliable time in most engines is directly after the frame-present and GPU flush-and-wait. nuclear@0: // This call should be done right after that to give this system the timing info it needs. nuclear@0: void AfterPresentAndFlush(double timeNow); nuclear@0: // But some engines queue up the frame-present and only later find out when it actually happened. nuclear@0: // They should call these two at those times. nuclear@0: void AfterPresentWithoutFlush(); nuclear@0: void AfterPresentFinishes(double timeNow); nuclear@0: nuclear@0: // The "average" time the rendered frame will show up, nuclear@0: // and the predicted pose of the HMD at that time. nuclear@0: // You usually only need to call one of these functions. nuclear@0: double GetViewRenderPredictionTime(); nuclear@0: bool GetViewRenderPredictionPose(Tracking::SensorStateReader* reader, Posef& transform); nuclear@0: nuclear@0: nuclear@0: // Timewarp prediction functions. You usually only need to call one of these three sets of functions. nuclear@0: nuclear@0: // The predicted times that the first and last pixel will be visible on-screen. nuclear@0: double GetVisiblePixelTimeStart(); nuclear@0: double GetVisiblePixelTimeEnd(); nuclear@0: // Predicted poses of the HMD at those first and last pixels. nuclear@0: bool GetPredictedVisiblePixelPoseStart(Tracking::SensorStateReader* reader, Posef& transform); nuclear@0: bool GetPredictedVisiblePixelPoseEnd(Tracking::SensorStateReader* reader, Posef& transform); nuclear@0: // The delta matrices to feed to the timewarp distortion code, nuclear@0: // given the pose that was used for rendering. nuclear@0: // (usually the one returned by GetViewRenderPredictionPose() earlier) nuclear@0: bool GetTimewarpDeltaStart(Tracking::SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform); nuclear@0: bool GetTimewarpDeltaEnd(Tracking::SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform); nuclear@0: nuclear@0: // Just-In-Time distortion aims to delay the second sensor reading & distortion nuclear@0: // until the very last moment to improve prediction. However, it is a little scary, nuclear@0: // since the delay might wait too long and miss the vsync completely! nuclear@0: // Use of the JustInTime_* functions is entirely optional, and we advise allowing nuclear@0: // users to turn it off in their video options to cope with odd machine configurations. nuclear@0: nuclear@0: // What time should the app wait until before starting distortion? nuclear@0: double JustInTime_GetDistortionWaitUntilTime(); nuclear@0: nuclear@0: // Used to time the distortion rendering nuclear@0: bool JustInTime_NeedDistortionTimeMeasurement() const; nuclear@0: void JustInTime_BeforeDistortionTimeMeasurement(double timeNow); nuclear@0: void JustInTime_AfterDistortionTimeMeasurement(double timeNow); nuclear@0: double JustInTime_AverageDistortionTime(); // Just for profiling - use JustInTime_GetDistortionWaitUntilTime() for functionality. nuclear@0: nuclear@0: private: nuclear@0: bool VsyncEnabled; nuclear@0: HmdRenderInfo RenderInfo; nuclear@0: PredictionValues CurrentPredictionValues; nuclear@0: nuclear@0: enum { NumDistortionTimes = 100 }; nuclear@0: int DistortionTimeCount; nuclear@0: double DistortionTimeCurrentStart; nuclear@0: float DistortionTimes[NumDistortionTimes]; nuclear@0: float DistortionTimeAverage; nuclear@0: nuclear@0: // Pose at which last time the eye was rendered. nuclear@0: Posef EyeRenderPoses[2]; nuclear@0: nuclear@0: // Absolute time of the last present+flush nuclear@0: double LastFramePresentFlushTime; nuclear@0: // Seconds between present+flushes nuclear@0: float PresentFlushToPresentFlushSeconds; nuclear@0: // Predicted absolute time of the next present+flush nuclear@0: double NextFramePresentFlushTime; nuclear@0: nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: nuclear@0: }}} // OVR::Util::Render nuclear@0: nuclear@0: #endif