nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : CAPI_HMDState.h nuclear@0: Content : State associated with a single HMD nuclear@0: Created : January 24, 2014 nuclear@0: Authors : Michael Antonov 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_CAPI_HMDState_h nuclear@0: #define OVR_CAPI_HMDState_h nuclear@0: nuclear@0: #include "../Kernel/OVR_Math.h" nuclear@0: #include "../Kernel/OVR_List.h" nuclear@0: #include "../Kernel/OVR_Log.h" nuclear@0: #include "../OVR_CAPI.h" nuclear@0: nuclear@0: #include "CAPI_FrameTimeManager.h" nuclear@0: #include "CAPI_LatencyStatistics.h" nuclear@0: #include "CAPI_HMDRenderState.h" nuclear@0: #include "CAPI_DistortionRenderer.h" nuclear@0: #include "CAPI_HSWDisplay.h" nuclear@0: nuclear@0: #include "../Service/Service_NetClient.h" nuclear@0: #include "../Net/OVR_NetworkTypes.h" nuclear@0: #include "../Util/Util_LatencyTest2Reader.h" nuclear@0: nuclear@0: struct ovrHmdStruct { }; nuclear@0: nuclear@0: namespace OVR { namespace CAPI { nuclear@0: nuclear@0: nuclear@0: using namespace OVR::Util::Render; nuclear@0: using namespace OVR::Service; nuclear@0: using namespace OVR::Net; nuclear@0: nuclear@0: nuclear@0: //------------------------------------------------------------------------------------- nuclear@0: // ***** ThreadChecker nuclear@0: nuclear@0: // This helper class is used to verify that the API is used according to supported nuclear@0: // thread safety constraints (is not re-entrant for this and related functions). nuclear@0: class ThreadChecker nuclear@0: { nuclear@0: public: nuclear@0: nuclear@0: #ifndef OVR_BUILD_DEBUG nuclear@0: nuclear@0: // In release build, thread checks are disabled. nuclear@0: ThreadChecker() { } nuclear@0: void Begin(const char* functionName) { OVR_UNUSED1(functionName); } nuclear@0: void End() { } nuclear@0: nuclear@0: // Add thread-re-entrancy check for function scope nuclear@0: struct Scope nuclear@0: { nuclear@0: Scope(ThreadChecker*, const char *) { } nuclear@0: ~Scope() { } nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: #else // OVR_BUILD_DEBUG nuclear@0: ThreadChecker() : pFunctionName(0), FirstThread(0) nuclear@0: { } nuclear@0: nuclear@0: void Begin(const char* functionName) nuclear@0: { nuclear@0: if (!pFunctionName) nuclear@0: { nuclear@0: pFunctionName = functionName; nuclear@0: FirstThread = GetCurrentThreadId(); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // pFunctionName may be not null here if function is called internally on the same thread. nuclear@0: OVR_ASSERT_LOG((FirstThread == GetCurrentThreadId()), nuclear@0: ("%s (threadId=%p) called at the same times as %s (threadId=%p)\n", nuclear@0: functionName, GetCurrentThreadId(), pFunctionName, FirstThread) ); nuclear@0: } nuclear@0: } nuclear@0: void End() nuclear@0: { nuclear@0: pFunctionName = 0; nuclear@0: FirstThread = 0; nuclear@0: } nuclear@0: nuclear@0: // Add thread-reentrancy check for function scope. nuclear@0: struct Scope nuclear@0: { nuclear@0: Scope(ThreadChecker* threadChecker, const char *functionName) : pChecker(threadChecker) nuclear@0: { pChecker->Begin(functionName); } nuclear@0: ~Scope() nuclear@0: { pChecker->End(); } nuclear@0: private: nuclear@0: ThreadChecker* pChecker; nuclear@0: }; nuclear@0: nuclear@0: private: nuclear@0: // If not 0, contains the name of the function that first entered the scope. nuclear@0: const char * pFunctionName; nuclear@0: ThreadId FirstThread; nuclear@0: nuclear@0: #endif // OVR_BUILD_DEBUG nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: //------------------------------------------------------------------------------------- nuclear@0: // ***** HMDState nuclear@0: nuclear@0: // Describes a single HMD. nuclear@0: class HMDState : public ListNode, nuclear@0: public ovrHmdStruct, public NewOverrideBase nuclear@0: { nuclear@0: void operator=(const HMDState&) { } // Quiet warning. nuclear@0: nuclear@0: protected: nuclear@0: HMDState(const OVR::Service::HMDNetworkInfo& netInfo, nuclear@0: const OVR::HMDInfo& hmdInfo, nuclear@0: Profile* profile, nuclear@0: Service::NetClient* client); nuclear@0: HMDState(const HMDInfo& src, Profile* profile); nuclear@0: nuclear@0: public: nuclear@0: virtual ~HMDState(); nuclear@0: nuclear@0: static HMDState* CreateHMDState(Service::NetClient* client, const HMDNetworkInfo& netInfo); nuclear@0: static HMDState* CreateHMDState(ovrHmdType hmdType); // Used for debug mode nuclear@0: static const OVR::List& GetHMDStateList(); nuclear@0: nuclear@0: // *** Sensor Setup nuclear@0: nuclear@0: bool ConfigureTracking(unsigned supportedCaps, unsigned requiredCaps); nuclear@0: void ResetTracking(); nuclear@0: void RecenterPose(); nuclear@0: ovrTrackingState PredictedTrackingState(double absTime); nuclear@0: nuclear@0: // Changes HMD Caps. nuclear@0: // Capability bits that are not directly or logically tied to one system (such as sensor) nuclear@0: // are grouped here. ovrHmdCap_VSync, for example, affects rendering and timing. nuclear@0: void SetEnabledHmdCaps(unsigned caps); nuclear@0: unsigned SetEnabledHmdCaps(); nuclear@0: nuclear@0: bool ProcessLatencyTest(unsigned char rgbColorOut[3]); nuclear@0: nuclear@0: // *** Rendering Setup nuclear@0: bool ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2], nuclear@0: const ovrFovPort eyeFovIn[2], nuclear@0: const ovrRenderAPIConfig* apiConfig, nuclear@0: unsigned distortionCaps); nuclear@0: nuclear@0: void UpdateRenderProfile(Profile* profile); nuclear@0: nuclear@0: nuclear@0: void SubmitEyeTextures(const ovrPosef renderPose[2], nuclear@0: const ovrTexture eyeTexture[2]); nuclear@0: nuclear@0: nuclear@0: void sharedInit ( Profile *profile ); nuclear@0: nuclear@0: void applyProfileToSensorFusion(); nuclear@0: nuclear@0: // INlines so that they can be easily compiled out. nuclear@0: // Does debug ASSERT checks for functions that require BeginFrame. nuclear@0: // Also verifies that we are on the right thread. nuclear@0: void checkBeginFrameScope(const char* functionName) nuclear@0: { nuclear@0: OVR_UNUSED1(functionName); // for Release build. nuclear@0: OVR_ASSERT_LOG(BeginFrameCalled == true, nuclear@0: ("%s called outside ovrHmd_BeginFrame.", functionName)); nuclear@0: OVR_DEBUG_LOG_COND(BeginFrameThreadId != OVR::GetCurrentThreadId(), nuclear@0: ("%s called on a different thread then ovrHmd_BeginFrame.", functionName)); nuclear@0: } nuclear@0: nuclear@0: void checkRenderingConfigured(const char* functionName) nuclear@0: { nuclear@0: OVR_UNUSED1(functionName); // for Release build. nuclear@0: OVR_ASSERT_LOG(RenderingConfigured == true, nuclear@0: ("%s called without ovrHmd_ConfigureRendering.", functionName)); nuclear@0: } nuclear@0: nuclear@0: void checkBeginFrameTimingScope(const char* functionName) nuclear@0: { nuclear@0: OVR_UNUSED1(functionName); // for Release build. nuclear@0: OVR_ASSERT_LOG(BeginFrameTimingCalled == true, nuclear@0: ("%s called outside ovrHmd_BeginFrameTiming.", functionName)); nuclear@0: } nuclear@0: nuclear@0: // Get properties by name. nuclear@0: bool getBoolValue(const char* propertyName, bool defaultVal); nuclear@0: bool setBoolValue(const char* propertyName, bool value); nuclear@0: int getIntValue(const char* propertyName, int defaultVal); nuclear@0: bool setIntValue(const char* propertyName, int value); nuclear@0: float getFloatValue(const char* propertyName, float defaultVal); nuclear@0: bool setFloatValue(const char* propertyName, float value); nuclear@0: unsigned getFloatArray(const char* propertyName, float values[], unsigned arraySize); nuclear@0: bool setFloatArray(const char* propertyName, float values[], unsigned arraySize); nuclear@0: const char* getString(const char* propertyName, const char* defaultVal); nuclear@0: bool setString(const char* propertyName, const char* value); nuclear@0: nuclear@0: VirtualHmdId GetNetId() { return NetId; } nuclear@0: nuclear@0: public: nuclear@0: Ptr pProfile; nuclear@0: // Descriptor that gets allocated and returned to the user as ovrHmd. nuclear@0: ovrHmdDesc* pHmdDesc; nuclear@0: // Window handle passed in AttachWindow. nuclear@0: void* pWindow; nuclear@0: nuclear@0: // Network nuclear@0: Service::NetClient* pClient; nuclear@0: VirtualHmdId NetId; nuclear@0: HMDNetworkInfo NetInfo; nuclear@0: nuclear@0: // HMDInfo shouldn't change, as its string pointers are passed out. nuclear@0: HMDInfo OurHMDInfo; nuclear@0: nuclear@0: const char* pLastError; nuclear@0: nuclear@0: // Caps enabled for the HMD. nuclear@0: unsigned EnabledHmdCaps; nuclear@0: nuclear@0: // Caps actually sent to the Sensor Service nuclear@0: unsigned EnabledServiceHmdCaps; nuclear@0: nuclear@0: // These are the flags actually applied to the Sensor device, nuclear@0: // used to track whether SetDisplayReport calls are necessary. nuclear@0: //unsigned HmdCapsAppliedToSensor; nuclear@0: nuclear@0: // *** Sensor nuclear@0: Tracking::CombinedSharedStateReader SharedStateReader; nuclear@0: Tracking::SensorStateReader TheSensorStateReader; nuclear@0: Util::RecordStateReader TheLatencyTestStateReader; nuclear@0: nuclear@0: bool LatencyTestActive; nuclear@0: unsigned char LatencyTestDrawColor[3]; nuclear@0: nuclear@0: bool LatencyTest2Active; nuclear@0: unsigned char LatencyTest2DrawColor[3]; nuclear@0: nuclear@0: // Rendering part nuclear@0: FrameTimeManager TimeManager; nuclear@0: LagStatsCalculator LagStats; nuclear@0: LatencyStatisticsCSV LagStatsCSV; nuclear@0: HMDRenderState RenderState; nuclear@0: Ptr pRenderer; nuclear@0: nuclear@0: // Health and Safety Warning display. nuclear@0: Ptr pHSWDisplay; nuclear@0: nuclear@0: // Last timing value reported by BeginFrame. nuclear@0: double LastFrameTimeSeconds; nuclear@0: // Last timing value reported by GetFrameTime. These are separate since the intended nuclear@0: // use is from different threads. TBD: Move to FrameTimeManager? Make atomic? nuclear@0: double LastGetFrameTimeSeconds; nuclear@0: nuclear@0: // Last cached value returned by ovrHmd_GetString/ovrHmd_GetStringArray. nuclear@0: char LastGetStringValue[256]; nuclear@0: nuclear@0: // Debug flag set after ovrHmd_ConfigureRendering succeeds. nuclear@0: bool RenderingConfigured; nuclear@0: // Set after BeginFrame succeeds, and its corresponding thread id for debug checks. nuclear@0: bool BeginFrameCalled; nuclear@0: ThreadId BeginFrameThreadId; nuclear@0: // Graphics functions are not re-entrant from other threads. nuclear@0: ThreadChecker RenderAPIThreadChecker; nuclear@0: // nuclear@0: bool BeginFrameTimingCalled; nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: nuclear@0: nuclear@0: //I appreciate this isn't an idea place for this function prototype, but needed nuclear@0: //to be seen by OVR_CAPI.cpp and the various SDK renderers of CAPI, nuclear@0: //and have everything defined. Please move to a better place if you know of one. nuclear@0: ovrBool ovrHmd_CreateDistortionMeshInternal( ovrHmdStruct * hmd, nuclear@0: ovrEyeType eyeType, ovrFovPort fov, nuclear@0: unsigned int distortionCaps, nuclear@0: ovrDistortionMesh *meshData, nuclear@0: float overrideEyeReliefIfNonZero=0 ); nuclear@0: nuclear@0: nuclear@0: nuclear@0: nuclear@0: }} // namespace OVR::CAPI nuclear@0: nuclear@0: #endif // OVR_CAPI_HMDState_h