diff options
Diffstat (limited to 'LibOVR/Src/OVR_CAPI.cpp')
-rwxr-xr-x[-rw-r--r--] | LibOVR/Src/OVR_CAPI.cpp | 1458 |
1 files changed, 792 insertions, 666 deletions
diff --git a/LibOVR/Src/OVR_CAPI.cpp b/LibOVR/Src/OVR_CAPI.cpp index 6d8d711..c530f82 100644..100755 --- a/LibOVR/Src/OVR_CAPI.cpp +++ b/LibOVR/Src/OVR_CAPI.cpp @@ -25,69 +25,86 @@ limitations under the License. ************************************************************************************/ #include "OVR_CAPI.h" +#include "OVR_Version.h" + + #include "Kernel/OVR_Timer.h" -#include "Kernel/OVR_Math.h" #include "Kernel/OVR_System.h" +#include "Kernel/OVR_DebugHelp.h" +#include "Extras/OVR_Math.h" #include "OVR_Stereo.h" #include "OVR_Profile.h" -#include "../Include/OVR_Version.h" #include "CAPI/CAPI_HMDState.h" -#include "CAPI/CAPI_FrameTimeManager.h" +#include "Net/OVR_Session.h" #include "Service/Service_NetClient.h" -#ifdef OVR_SINGLE_PROCESS +#ifdef OVR_PRIVATE_FILE #include "Service/Service_NetServer.h" #endif +#include "Displays/OVR_Display.h" + #if !defined(HEADLESS_APP) -#ifdef OVR_OS_WIN32 +#if defined(OVR_OS_WIN32) #include "Displays/OVR_Win32_ShimFunctions.h" +#include <VersionHelpers.h> #endif #endif /* !defined(HEADLESS_APP) */ +// Forward decl to keep the callback static + +// Note: Removed CaptureHmdDescTrace from non-Win32 due to build warning. +#if !defined(OVR_OS_MAC) && !defined(OVR_OS_LINUX) +static bool CaptureHmdDescTrace(const OVR::CAPI::HMDState *state); +#endif +#define TRACE_STATE_CAPTURE_FUNC OVR::CAPI::HMDState::EnumerateHMDStateList(CaptureHmdDescTrace) +#include "Tracing/Tracing.h" + +#if !defined(OVR_OS_MAC) && !defined(OVR_OS_LINUX) +// EnumerateHMDStateList callback for tracing state capture +static bool CaptureHmdDescTrace(const OVR::CAPI::HMDState* state) +{ + TraceHmdDesc(*state->pHmdDesc); + OVR_UNUSED(state); // Avoid potential compiler warnings. + return true; +} +#endif + +// Produce an invalid tracking state that will not mess up the application too badly. +static ovrTrackingState GetNullTrackingState() +{ + ovrTrackingState nullState = ovrTrackingState(); + nullState.HeadPose.ThePose.Orientation.w = 1.f; // Provide valid quaternions for head pose. + return nullState; +} + +// Produce a null frame timing structure that will not break the calling application. +static ovrFrameTiming GetNullFrameTiming() +{ + ovrFrameTiming nullTiming = ovrFrameTiming(); + nullTiming.DeltaSeconds = 0.013f; // Provide nominal value + return nullTiming; +} + using namespace OVR; using namespace OVR::Util::Render; -using namespace OVR::Tracking; +using namespace OVR::Vision; //------------------------------------------------------------------------------------- // Math namespace OVR { -// ***** FovPort - -// C-interop support: FovPort <-> ovrFovPort -FovPort::FovPort(const ovrFovPort &src) - : UpTan(src.UpTan), DownTan(src.DownTan), LeftTan(src.LeftTan), RightTan(src.RightTan) -{ } - -FovPort::operator ovrFovPort () const -{ - ovrFovPort result; - result.LeftTan = LeftTan; - result.RightTan = RightTan; - result.UpTan = UpTan; - result.DownTan = DownTan; - return result; -} - -// Converts Fov Tan angle units to [-1,1] render target NDC space -Vector2f FovPort::TanAngleToRendertargetNDC(Vector2f const &tanEyeAngle) -{ - ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(*this); - return tanEyeAngle * eyeToSourceNDC.Scale + eyeToSourceNDC.Offset; -} - // ***** SensorDataType SensorDataType::SensorDataType(const ovrSensorData& s) { - Acceleration = s.Accelerometer; - RotationRate = s.Gyro; - MagneticField = s.Magnetometer; - Temperature = s.Temperature; + Acceleration = s.Accelerometer; + RotationRate = s.Gyro; + MagneticField = s.Magnetometer; + Temperature = s.Temperature; AbsoluteTimeSeconds = s.TimeInSeconds; } @@ -95,39 +112,35 @@ SensorDataType::operator ovrSensorData () const { ovrSensorData result; result.Accelerometer = Acceleration; - result.Gyro = RotationRate; - result.Magnetometer = MagneticField; - result.Temperature = Temperature; - result.TimeInSeconds = (float) AbsoluteTimeSeconds; + result.Gyro = RotationRate; + result.Magnetometer = MagneticField; + result.Temperature = Temperature; + result.TimeInSeconds = (float)AbsoluteTimeSeconds; return result; } + + // ***** SensorState TrackingState::TrackingState(const ovrTrackingState& s) { - HeadPose = s.HeadPose; - CameraPose = s.CameraPose; + HeadPose = s.HeadPose; + CameraPose = s.CameraPose; LeveledCameraPose = s.LeveledCameraPose; - RawSensorData = s.RawSensorData; - StatusFlags = s.StatusFlags; - LastVisionProcessingTime = s.LastVisionProcessingTime; - LastVisionFrameLatency = s.LastVisionFrameLatency; - LastCameraFrameCounter = s.LastCameraFrameCounter; + RawSensorData = s.RawSensorData; + StatusFlags = s.StatusFlags; } TrackingState::operator ovrTrackingState() const { ovrTrackingState result; - result.HeadPose = HeadPose; - result.CameraPose = CameraPose; + result.HeadPose = HeadPose; + result.CameraPose = CameraPose; result.LeveledCameraPose = LeveledCameraPose; - result.RawSensorData = RawSensorData; - result.StatusFlags = StatusFlags; - result.LastVisionProcessingTime = LastVisionProcessingTime; - result.LastVisionFrameLatency = LastVisionFrameLatency; - result.LastCameraFrameCounter = LastCameraFrameCounter; + result.RawSensorData = RawSensorData; + result.StatusFlags = StatusFlags; return result; } @@ -138,184 +151,212 @@ TrackingState::operator ovrTrackingState() const using namespace OVR::CAPI; -#ifdef __cplusplus -extern "C" { -#endif - -// Used to generate projection from ovrEyeDesc::Fov -OVR_EXPORT ovrMatrix4f ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, ovrBool rightHanded) +// Helper function to validate the HMD object provided by the API user. +static HMDState* GetHMDStateFromOvrHmd(ovrHmd hmddesc) { - return CreateProjection(rightHanded ? true : false, fov, znear, zfar); + if (!hmddesc || !hmddesc->Handle) + return nullptr; + + return (HMDState*)hmddesc->Handle; } -OVR_EXPORT ovrMatrix4f ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale, - float orthoDistance, float hmdToEyeViewOffsetX) +OVR_PUBLIC_FUNCTION(double) ovr_GetTimeInSeconds() { + return Timer::GetSeconds(); +} - float orthoHorizontalOffset = hmdToEyeViewOffsetX / orthoDistance; - - // Current projection maps real-world vector (x,y,1) to the RT. - // We want to find the projection that maps the range [-FovPixels/2,FovPixels/2] to - // the physical [-orthoHalfFov,orthoHalfFov] - // Note moving the offset from M[0][2]+M[1][2] to M[0][3]+M[1][3] - this means - // we don't have to feed in Z=1 all the time. - // The horizontal offset math is a little hinky because the destination is - // actually [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset] - // So we need to first map [-FovPixels/2,FovPixels/2] to - // [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset]: - // x1 = x0 * orthoHalfFov/(FovPixels/2) + orthoHorizontalOffset; - // = x0 * 2*orthoHalfFov/FovPixels + orthoHorizontalOffset; - // But then we need the same mapping as the existing projection matrix, i.e. - // x2 = x1 * Projection.M[0][0] + Projection.M[0][2]; - // = x0 * (2*orthoHalfFov/FovPixels + orthoHorizontalOffset) * Projection.M[0][0] + Projection.M[0][2]; - // = x0 * Projection.M[0][0]*2*orthoHalfFov/FovPixels + - // orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2]; - // So in the new projection matrix we need to scale by Projection.M[0][0]*2*orthoHalfFov/FovPixels and - // offset by orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2]. - - Matrix4f ortho; - ortho.M[0][0] = projection.M[0][0] * orthoScale.x; - ortho.M[0][1] = 0.0f; - ortho.M[0][2] = 0.0f; - ortho.M[0][3] = -projection.M[0][2] + ( orthoHorizontalOffset * projection.M[0][0] ); - - ortho.M[1][0] = 0.0f; - ortho.M[1][1] = -projection.M[1][1] * orthoScale.y; // Note sign flip (text rendering uses Y=down). - ortho.M[1][2] = 0.0f; - ortho.M[1][3] = -projection.M[1][2]; - - /* - if ( fabsf ( zNear - zFar ) < 0.001f ) - { - ortho.M[2][0] = 0.0f; - ortho.M[2][1] = 0.0f; - ortho.M[2][2] = 0.0f; - ortho.M[2][3] = zFar; - } - else - { - ortho.M[2][0] = 0.0f; - ortho.M[2][1] = 0.0f; - ortho.M[2][2] = zFar / (zNear - zFar); - ortho.M[2][3] = (zFar * zNear) / (zNear - zFar); - } - */ - // MA: Undo effect of sign - ortho.M[2][0] = 0.0f; - ortho.M[2][1] = 0.0f; - //ortho.M[2][2] = projection.M[2][2] * projection.M[3][2] * -1.0f; // reverse right-handedness - ortho.M[2][2] = 0.0f; - ortho.M[2][3] = 0.0f; - //projection.M[2][3]; +//------------------------------------------------------------------------------------- - // No perspective correction for ortho. - ortho.M[3][0] = 0.0f; - ortho.M[3][1] = 0.0f; - ortho.M[3][2] = 0.0f; - ortho.M[3][3] = 1.0f; +// 1. Init/shutdown. - return ortho; -} +static ovrBool CAPI_ovrInitializeCalled = ovrFalse; +static OVR::Service::NetClient* CAPI_pNetClient = nullptr; -OVR_EXPORT double ovr_GetTimeInSeconds() +#if !defined(HEADLESS_APP) +ovrBool ovr_InitializeRenderingShim() { - return Timer::GetSeconds(); + OVR::Display::Initialize(); + + return OVR::Display::GetDirectDisplayInitialized(); } -// Waits until the specified absolute time. -OVR_EXPORT double ovr_WaitTillTime(double absTime) +OVR_PUBLIC_FUNCTION(ovrBool) ovr_InitializeRenderingShimVersion(int requestedMinorVersion) { - double initialTime = ovr_GetTimeInSeconds(); - double newTime = initialTime; + // We ignore the patch and build versions here, as they aren't relevant to compatibility. + // And we don't store them away here, as we do that in ovr_Initialize() instead. - while(newTime < absTime) + if (requestedMinorVersion > OVR_MINOR_VERSION) + return ovrFalse; + + return ovr_InitializeRenderingShim(); +} +#endif /* !defined(HEADLESS_APP) */ + +// Write out to the log where the current running module is located on disk. +static void LogLocationOfThisModule() +{ +#if defined (OVR_OS_WIN32) + // Log out the DLL file path on startup. { - for (int j = 0; j < 5; j++) - OVR_PROCESSOR_PAUSE(); + bool success = false; + + HMODULE hModule = nullptr; + GetModuleHandleEx( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCTSTR)&ovr_Initialize, + &hModule); + if (hModule) + { + wchar_t filename[_MAX_PATH]; + DWORD len = GetModuleFileNameW(hModule, filename, OVR_ARRAY_COUNT(filename)); + if (len > 0 && filename[0]) + { + success = true; + LogText("[CAPI] LibOVR module is located at %ws\n", filename); + } + } - newTime = ovr_GetTimeInSeconds(); + if (!success) + { + LogError("[CAPI] WARNING: Unable to find LibOVR module."); + } } - - // How long we waited - return newTime - initialTime; +#endif // OVR_OS_WIN32 } +// These defaults are also in OVR_CAPIShim.c +static const ovrInitParams DefaultParams = { + ovrInit_RequestVersion, // Flags + OVR_MINOR_VERSION, // RequestedMinorVersion + 0, // LogCallback + 0 // ConnectionTimeoutSeconds +}; -//------------------------------------------------------------------------------------- +// Precondition: params is not null +OVR_PUBLIC_FUNCTION(ovrBool) ovr_Initialize(ovrInitParams const* params) +{ + // TBD: Should we check if the version requested changed and fail here? + if (CAPI_ovrInitializeCalled) // If already initialized... + return ovrTrue; -// 1. Init/shutdown. + TraceInit(); + TraceCall(0); -static ovrBool CAPI_SystemInitCalled = 0; -static ovrBool CAPI_ovrInitializeCalled = 0; + if (!params) + { + params = &DefaultParams; + } -static OVR::Service::NetClient* CAPI_pNetClient = 0; + bool DebugMode = (params->Flags & ovrInit_Debug) != 0; -#if !defined(HEADLESS_APP) -OVR_EXPORT ovrBool ovr_InitializeRenderingShim() -{ - OVR::System::DirectDisplayInitialize(); - return OVR::System::DirectDisplayEnabled(); -} -#endif /* !defined(HEADLESS_APP) */ +#if defined(OVR_BUILD_DEBUG) + // If no debug setting is provided, + if (!(params->Flags & (ovrInit_Debug | ovrInit_ForceNoDebug))) + { + DebugMode = true; + } +#endif -OVR_EXPORT ovrBool ovr_Initialize() -{ - if (CAPI_ovrInitializeCalled) - return 1; + // We ignore the requested patch version and build version, as they are not currently relevant to + // the library compatibility. Our test for minor version compatibility is currently simple: we support + // only older or equal minor versions, and don't change our behavior if the requested minor version + // is older than than OVR_MINOR_VERSION. - // We must set up the system for the plugin to work - if (!OVR::System::IsInitialized()) + if ((params->Flags & ovrInit_RequestVersion) != 0 && + (params->RequestedMinorVersion > OVR_MINOR_VERSION)) { - OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All)); - CAPI_SystemInitCalled = 1; + goto Abort; } - if (!OVR::System::DirectDisplayEnabled() && !OVR::Display::InCompatibilityMode(false)) +#if defined(OVR_OS_WIN32) + // Older than Windows 7 SP1? + if (!IsWindows7SP1OrGreater()) { + MessageBoxA(nullptr, "This software depends on features available starting with \nWindows 7 Service Pack 1, and it cannot start.", "LibOVR: Cannot start", 0); OVR_ASSERT(false); - return 0; + goto Abort; } +#endif // OVR_OS_WIN32 - CAPI_pNetClient = NetClient::GetInstance(); + OVR::Net::RuntimeSDKVersion.SetCurrent(); // Fill in the constant parts of this struct. + OVR::Net::RuntimeSDKVersion.RequestedMinorVersion = (uint16_t)params->RequestedMinorVersion; -#ifdef OVR_SINGLE_PROCESS + // Initialize display subsystem regardless of Allocator initialization. + OVR::Display::Initialize(); - // If the server could not start running, - if (Service::NetServer::GetInstance()->IsInitialized()) + // We must set up the system for the plugin to work + if (!OVR::System::IsInitialized()) { - CAPI_pNetClient->Connect(true); + // TBD: Base this on registry setting? + Allocator::SetLeakTracking(DebugMode); + + OVR::Log* logger = OVR::Log::ConfigureDefaultLog(OVR::LogMask_All); + + // Set the CAPI logger callback + logger->SetCAPICallback(params->LogCallback); + + OVR::System::Init(logger); } - else + + if (!OVR::Display::GetDirectDisplayInitialized() && !OVR::Display::InCompatibilityMode(true)) { - // This normally will happen if the OVRService is running in the background, - // or another SingleProcess-mode app is running in the background. - // In this case, it's using the hardware and we should not also attempt to use - // the hardware. - LogError("{ERR-079} [LibOVR] Server is already running"); + OVR_ASSERT(false); + goto Abort; } -#else - CAPI_pNetClient->Connect(true); -#endif + CAPI_pNetClient = NetClient::GetInstance(); + + // Store off the initialization parameters from ovr_Initialize() + CAPI_pNetClient->ApplyParameters(params); + + // Mark as initialized regardless of whether or not we can connect to the server. CAPI_ovrInitializeCalled = 1; - return 1; + // Log the location of the module after most of the bring-up, as the game + // could do almost anything in response to a log message callback. + LogLocationOfThisModule(); + + // If unable to connect to server and we are not in a debug mode, + if (!CAPI_pNetClient->Connect(true) && !DebugMode) + { + // Then it's a failure when the server is unreachable. + // This means that a DebugHMD cannot be created unless the ovrInit_Debug flag is set. + goto Abort; + } + + // everything is okay + TraceReturn(0); + return ovrTrue; + +Abort: + // clean up and return failure + TraceReturn(0); + TraceFini(); + return ovrFalse; } -OVR_EXPORT void ovr_Shutdown() + +OVR_PUBLIC_FUNCTION(void) ovr_Shutdown() { - // We should clean up the system to be complete - if (OVR::System::IsInitialized() && CAPI_SystemInitCalled) + if (CAPI_ovrInitializeCalled) + { + OVR::Display::Shutdown(); + TraceCall(0); + TraceFini(); + CAPI_ovrInitializeCalled = 0; + } + + if (OVR::System::IsInitialized()) { OVR::System::Destroy(); } - CAPI_SystemInitCalled = 0; - CAPI_ovrInitializeCalled = 0; + OVR::Net::RuntimeSDKVersion.Reset(); + CAPI_pNetClient = nullptr; // Not strictly necessary, but useful for debugging and cleanliness. } @@ -328,10 +369,10 @@ OVR_EXPORT void ovr_Shutdown() // probably check this. // -OVR_EXPORT int ovrHmd_Detect() +OVR_PUBLIC_FUNCTION(int) ovrHmd_Detect() { if (!CAPI_ovrInitializeCalled) - return 0; + return -2; return CAPI_pNetClient->Hmd_Detect(); } @@ -341,7 +382,7 @@ OVR_EXPORT int ovrHmd_Detect() // a relatively light-weight handle that would reference the device going forward and would // survive future ovrHmd_Detect calls. That is once ovrHMD is returned, index is no longer // necessary and can be changed by a ovrHmd_Detect call. -OVR_EXPORT ovrHmd ovrHmd_Create(int index) +OVR_PUBLIC_FUNCTION(ovrHmd) ovrHmd_Create(int index) { if (!CAPI_ovrInitializeCalled) return 0; @@ -355,18 +396,35 @@ OVR_EXPORT ovrHmd ovrHmd_Create(int index) while (!CAPI_pNetClient->Hmd_Create(index, &netInfo) || netInfo.NetId == InvalidVirtualHmdId) { - // If two seconds elapse and still no HMD detected, - if (Timer::GetSeconds() - t0 > 2.) + double waitTime = 2.0; // Default wait time + + if (NetClient::GetInstance()->IsConnected(false, false)) { - if (!NetClient::GetInstance()->IsConnected(false, false)) + NetClient::GetInstance()->SetLastError("No HMD Detected"); + + // If in single process mode, + if (Net::Session::IsSingleProcess()) { - NetClient::GetInstance()->SetLastError("Not connected to service"); + // Wait 8 seconds for HMD to be detected, as this is a single process + // build and we expect that the operator has the system set up properly. + waitTime = 8.0; } else { - NetClient::GetInstance()->SetLastError("No HMD Detected"); + // Wait 1/2 second for HMD to be detected. + waitTime = 0.5; } + } + else + { + NetClient::GetInstance()->SetLastError("Not connected to service"); + // Wait the default amount of time for the service to start up. + } + + // If two seconds elapse and still no HMD detected, + if (Timer::GetSeconds() - t0 > waitTime) + { return 0; } } @@ -384,25 +442,27 @@ OVR_EXPORT ovrHmd ovrHmd_Create(int index) // Reset frame timing so that FrameTimeManager values are properly initialized in AppRendered mode. ovrHmd_ResetFrameTiming(hmds->pHmdDesc, 0); + TraceHmdDesc(*hmds->pHmdDesc); + return hmds->pHmdDesc; } #if !defined(HEADLESS_APP) -OVR_EXPORT ovrBool ovrHmd_AttachToWindow( ovrHmd hmd, void* window, - const ovrRecti* destMirrorRect, - const ovrRecti* sourceRenderTargetRect ) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_AttachToWindow(ovrHmd hmddesc, void* window, + const ovrRecti* destMirrorRect, + const ovrRecti* sourceRenderTargetRect) { - OVR_UNUSED( destMirrorRect ); - OVR_UNUSED( sourceRenderTargetRect ); + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return ovrFalse; + + OVR_UNUSED3(destMirrorRect, sourceRenderTargetRect, hmds); if (!CAPI_ovrInitializeCalled) - return false; + return ovrFalse; - if (!hmd || !hmd->Handle) - return false; #ifndef OVR_OS_MAC - HMDState* hmds = (HMDState*)hmd->Handle; CAPI_pNetClient->Hmd_AttachToWindow(hmds->GetNetId(), window); hmds->pWindow = window; #endif @@ -413,29 +473,29 @@ OVR_EXPORT ovrBool ovrHmd_AttachToWindow( ovrHmd hmd, void* window, OVR_UNUSED(window); #endif - return true; + return ovrTrue; } #endif /* !defined(HEADLESS_APP) */ -OVR_EXPORT ovrHmd ovrHmd_CreateDebug(ovrHmdType type) +OVR_PUBLIC_FUNCTION(ovrHmd) ovrHmd_CreateDebug(ovrHmdType type) { if (!CAPI_ovrInitializeCalled) return 0; - HMDState* hmds = HMDState::CreateHMDState(type); + HMDState* hmds = HMDState::CreateDebugHMDState(type); + if (!hmds) + return nullptr; return hmds->pHmdDesc; } -OVR_EXPORT void ovrHmd_Destroy(ovrHmd hmddesc) +OVR_PUBLIC_FUNCTION(void) ovrHmd_Destroy(ovrHmd hmddesc) { - if (!hmddesc || !hmddesc->Handle) + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) return; - - // TBD: Any extra shutdown? - HMDState* hmds = (HMDState*)hmddesc->Handle; - + { // Thread checker in its own scope, to avoid access after 'delete'. // Essentially just checks that no other RenderAPI function is executing. ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_Destroy"); @@ -457,20 +517,16 @@ OVR_EXPORT void ovrHmd_Destroy(ovrHmd hmddesc) } -OVR_EXPORT const char* ovrHmd_GetLastError(ovrHmd hmddesc) +OVR_PUBLIC_FUNCTION(const char*) ovrHmd_GetLastError(ovrHmd hmddesc) { if (!CAPI_ovrInitializeCalled) - { return "System initialize not called"; - } VirtualHmdId netId = InvalidVirtualHmdId; - if (hmddesc && hmddesc->Handle) - { - HMDState* p = (HMDState*)hmddesc->Handle; - netId = p->GetNetId(); - } + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (hmds) + netId = hmds->GetNetId(); return CAPI_pNetClient->Hmd_GetLastError(netId); } @@ -479,7 +535,7 @@ OVR_EXPORT const char* ovrHmd_GetLastError(ovrHmd hmddesc) // Returns version string representing libOVR version. Static, so // string remains valid for app lifespan -OVR_EXPORT const char* ovr_GetVersionString() +OVR_PUBLIC_FUNCTION(const char*) ovr_GetVersionString() { static const char* version = OVR_VERSION_LIBOVR_PFX OVR_VERSION_STRING; return version + sizeof(OVR_VERSION_LIBOVR_PFX) - 1; @@ -492,21 +548,24 @@ OVR_EXPORT const char* ovr_GetVersionString() // Returns capability bits that are enabled at this time; described by ovrHmdCapBits. // Note that this value is different font ovrHmdDesc::Caps, which describes what // capabilities are available. -OVR_EXPORT unsigned int ovrHmd_GetEnabledCaps(ovrHmd hmddesc) +OVR_PUBLIC_FUNCTION(unsigned int) ovrHmd_GetEnabledCaps(ovrHmd hmddesc) { - HMDState* p = (HMDState*)hmddesc->Handle; - return p ? p->EnabledHmdCaps : 0; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return 0; + + return hmds->EnabledHmdCaps; } // Modifies capability bits described by ovrHmdCapBits that can be modified, // such as ovrHmdCap_LowPersistance. -OVR_EXPORT void ovrHmd_SetEnabledCaps(ovrHmd hmddesc, unsigned int capsBits) +OVR_PUBLIC_FUNCTION(void) ovrHmd_SetEnabledCaps(ovrHmd hmddesc, unsigned int capsBits) { - HMDState* p = (HMDState*)hmddesc->Handle; - if (p) - { - p->SetEnabledHmdCaps(capsBits); - } + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return; + + hmds->SetEnabledHmdCaps(capsBits); } @@ -525,64 +584,50 @@ OVR_EXPORT void ovrHmd_SetEnabledCaps(ovrHmd hmddesc, unsigned int capsBits) // functions that have different rules (all frame access functions // must be on render thread) -OVR_EXPORT ovrBool ovrHmd_ConfigureTracking(ovrHmd hmddesc, unsigned int supportedCaps, - unsigned int requiredCaps) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_ConfigureTracking(ovrHmd hmddesc, unsigned int supportedCaps, + unsigned int requiredCaps) { - if (hmddesc) - { - HMDState* p = (HMDState*)hmddesc->Handle; - return p->ConfigureTracking(supportedCaps, requiredCaps); - } + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return ovrFalse; - return 0; + return hmds->ConfigureTracking(supportedCaps, requiredCaps) ? ovrTrue : ovrFalse; } -OVR_EXPORT void ovrHmd_RecenterPose(ovrHmd hmddesc) + +OVR_PUBLIC_FUNCTION(void) ovrHmd_RecenterPose(ovrHmd hmddesc) { - if (hmddesc) - { - HMDState* p = (HMDState*)hmddesc->Handle; - p->TheSensorStateReader.RecenterPose(); - } + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return; + + hmds->RecenterPose(); } -OVR_EXPORT ovrTrackingState ovrHmd_GetTrackingState(ovrHmd hmddesc, double absTime) +OVR_PUBLIC_FUNCTION(ovrTrackingState) ovrHmd_GetTrackingState(ovrHmd hmddesc, double absTime) { - ovrTrackingState result; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return GetNullTrackingState(); - if (hmddesc) - { - HMDState* p = (HMDState*)hmddesc->Handle; - result = p->PredictedTrackingState(absTime); + return hmds->PredictedTrackingState(absTime); +} - // Instrument data from eye pose - p->LagStats.InstrumentEyePose(result); - } - else - memset(&result, 0, sizeof(result)); -#if !defined(HEADLESS_APP) -#ifdef OVR_OS_WIN32 - // Set up display code for Windows - Win32::DisplayShim::GetInstance().Active = (result.StatusFlags & ovrStatus_HmdConnected) != 0; -#endif -#endif /* !defined(HEADLESS_APP) */ - return result; -} //------------------------------------------------------------------------------------- // *** General Setup // Per HMD -> calculateIdealPixelSize -OVR_EXPORT ovrSizei ovrHmd_GetFovTextureSize(ovrHmd hmddesc, ovrEyeType eye, ovrFovPort fov, - float pixelsPerDisplayPixel) +OVR_PUBLIC_FUNCTION(ovrSizei) ovrHmd_GetFovTextureSize(ovrHmd hmddesc, ovrEyeType eye, + ovrFovPort fov, float pixelsPerDisplayPixel) { - ovrHmdStruct * hmd = hmddesc->Handle; - if (!hmd) return Sizei(0); - - HMDState* hmds = (HMDState*)hmd; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return Sizei(0); + return hmds->RenderState.GetFOVTextureSize(eye, fov, pixelsPerDisplayPixel); } @@ -590,73 +635,69 @@ OVR_EXPORT ovrSizei ovrHmd_GetFovTextureSize(ovrHmd hmddesc, ovrEyeType eye, ovr //------------------------------------------------------------------------------------- -OVR_EXPORT -ovrBool ovrHmd_ConfigureRendering( ovrHmd hmddesc, - const ovrRenderAPIConfig* apiConfig, - unsigned int distortionCaps, - const ovrFovPort eyeFovIn[2], - ovrEyeRenderDesc eyeRenderDescOut[2] ) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_ConfigureRendering(ovrHmd hmddesc, + const ovrRenderAPIConfig* apiConfig, + unsigned int distortionCaps, + const ovrFovPort eyeFovIn[2], + ovrEyeRenderDesc eyeRenderDescOut[2]) { - ovrHmdStruct * hmd = hmddesc->Handle; - if (!hmd) return 0; - return ((HMDState*)hmd)->ConfigureRendering(eyeRenderDescOut, eyeFovIn, - apiConfig, distortionCaps); -} - - - -// TBD: MA - Deprecated, need alternative -void ovrHmd_SetVsync(ovrHmd hmddesc, ovrBool vsync) -{ - ovrHmdStruct * hmd = hmddesc->Handle; - if (!hmd) return; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return ovrFalse; - return ((HMDState*)hmd)->TimeManager.SetVsync(vsync? true : false); + return hmds->ConfigureRendering(eyeRenderDescOut, eyeFovIn, + apiConfig, distortionCaps); } +OVR_PUBLIC_FUNCTION(ovrFrameTiming) ovrHmd_BeginFrame(ovrHmd hmddesc, unsigned int frameIndex) +{ + // NOTE: frameIndex == 0 is handled inside ovrHmd_BeginFrameTiming() -OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrame(ovrHmd hmddesc, unsigned int frameIndex) -{ - HMDState* hmds = (HMDState*)hmddesc->Handle; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); if (!hmds) - { - ovrFrameTiming f; - memset(&f, 0, sizeof(f)); - return f; - } + return GetNullFrameTiming(); + + TraceCall(frameIndex); // Check: Proper configure and threading state for the call. hmds->checkRenderingConfigured("ovrHmd_BeginFrame"); - OVR_DEBUG_LOG_COND(hmds->BeginFrameCalled, ("ovrHmd_BeginFrame called multiple times.")); + OVR_DEBUG_LOG_COND(hmds->BeginFrameCalled, ("ovrHmd_BeginFrame called multiple times.")); ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_BeginFrame"); - + hmds->BeginFrameCalled = true; hmds->BeginFrameThreadId = OVR::GetCurrentThreadId(); - return ovrHmd_BeginFrameTiming(hmddesc, frameIndex); + ovrFrameTiming timing = ovrHmd_BeginFrameTiming(hmddesc, frameIndex); + + TraceReturn(frameIndex); + + return timing; } // Renders textures to frame buffer -OVR_EXPORT void ovrHmd_EndFrame(ovrHmd hmddesc, - const ovrPosef renderPose[2], - const ovrTexture eyeTexture[2]) +OVR_PUBLIC_FUNCTION(void) ovrHmd_EndFrame(ovrHmd hmddesc, + const ovrPosef renderPose[2], + const ovrTexture eyeTexture[2]) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - if (!hmds) return; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return; - // Instrument when the EndFrame() call started - hmds->LagStats.InstrumentEndFrameStart(ovr_GetTimeInSeconds()); + const ovrTexture* eyeDepthTexture = nullptr; + ovrPositionTimewarpDesc* posTimewarpDesc = nullptr; - hmds->SubmitEyeTextures(renderPose, eyeTexture); + TraceCall(hmds->BeginFrameIndex); + + hmds->SubmitEyeTextures(renderPose, eyeTexture, eyeDepthTexture); // Debug state checks: Must be in BeginFrame, on the same thread. hmds->checkBeginFrameScope("ovrHmd_EndFrame"); ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame"); - hmds->pRenderer->SetLatencyTestColor(hmds->LatencyTestActive ? hmds->LatencyTestDrawColor : NULL); + hmds->pRenderer->SetLatencyTestColor(hmds->LatencyTestActive ? hmds->LatencyTestDrawColor : nullptr); - ovrHmd_GetLatencyTest2DrawColor(hmddesc, NULL); // We don't actually need to draw color, so send NULL + ovrHmd_GetLatencyTest2DrawColor(hmddesc, nullptr); // We don't actually need to draw color, so send nullptr if (hmds->pRenderer) { @@ -677,36 +718,33 @@ OVR_EXPORT void ovrHmd_EndFrame(ovrHmd hmddesc, } #endif /* !defined(HEADLESS_APP) */ - hmds->pRenderer->EndFrame(true); + if (posTimewarpDesc) + hmds->pRenderer->SetPositionTimewarpDesc(*posTimewarpDesc); + + hmds->pRenderer->EndFrame(hmds->BeginFrameIndex, true); hmds->pRenderer->RestoreGraphicsState(); } // Call after present ovrHmd_EndFrameTiming(hmddesc); - // Instrument latency tester - hmds->LagStats.InstrumentLatencyTimings(hmds->TimeManager); - - // Instrument when the EndFrame() call ended - hmds->LagStats.InstrumentEndFrameEnd(ovr_GetTimeInSeconds()); + TraceReturn(hmds->BeginFrameIndex); // Out of BeginFrame hmds->BeginFrameThreadId = 0; hmds->BeginFrameCalled = false; + hmds->BeginFrameIndex++; // Set frame index to the next value in case 0 is passed. } - #if !defined(HEADLESS_APP) // Not exposed as part of public API -OVR_EXPORT void ovrHmd_RegisterPostDistortionCallback(ovrHmd hmddesc, PostDistortionCallback callback) +OVR_PUBLIC_FUNCTION(void) ovrHmd_RegisterPostDistortionCallback(ovrHmd hmddesc, PostDistortionCallback callback) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - if (!hmds) return; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds || !hmds->pRenderer) + return; - if (hmds->pRenderer) - { - hmds->pRenderer->RegisterPostDistortionCallback(callback); - } + hmds->pRenderer->RegisterPostDistortionCallback(callback); } #endif /* !defined(HEADLESS_APP) */ @@ -715,209 +753,209 @@ OVR_EXPORT void ovrHmd_RegisterPostDistortionCallback(ovrHmd hmddesc, PostDistor //------------------------------------------------------------------------------------- // ***** Frame Timing logic - -OVR_EXPORT ovrFrameTiming ovrHmd_GetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex) +OVR_PUBLIC_FUNCTION(ovrFrameTiming) ovrHmd_GetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex) { - ovrHmdStruct * hmd = hmddesc->Handle; - ovrFrameTiming f; - memset(&f, 0, sizeof(f)); + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return GetNullFrameTiming(); - HMDState* hmds = (HMDState*)hmd; - if (hmds) + // If no frame index is provided, + if (frameIndex == 0) { - FrameTimeManager::Timing frameTiming = hmds->TimeManager.GetFrameTiming(frameIndex); - - f.ThisFrameSeconds = frameTiming.ThisFrameTime; - f.NextFrameSeconds = frameTiming.NextFrameTime; - f.TimewarpPointSeconds = frameTiming.TimewarpPointTime; - f.ScanoutMidpointSeconds = frameTiming.MidpointTime; - f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0]; - f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1]; - - // Compute DeltaSeconds. - f.DeltaSeconds = (hmds->LastGetFrameTimeSeconds == 0.0f) ? 0.0f : - (float) (f.ThisFrameSeconds - hmds->LastFrameTimeSeconds); - hmds->LastGetFrameTimeSeconds = f.ThisFrameSeconds; - if (f.DeltaSeconds > 1.0f) - f.DeltaSeconds = 1.0f; + // Use the next one in the series. + frameIndex = hmds->BeginFrameIndex; } - - return f; + + return hmds->GetFrameTiming(frameIndex); } -OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrameTiming(ovrHmd hmddesc, unsigned int frameIndex) +OVR_PUBLIC_FUNCTION(ovrFrameTiming) ovrHmd_BeginFrameTiming(ovrHmd hmddesc, unsigned int frameIndex) { - ovrHmdStruct * hmd = hmddesc->Handle; - ovrFrameTiming f; - memset(&f, 0, sizeof(f)); - - HMDState* hmds = (HMDState*)hmd; - if (!hmds) return f; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return GetNullFrameTiming(); // Check: Proper state for the call. OVR_DEBUG_LOG_COND(hmds->BeginFrameTimingCalled, ("ovrHmd_BeginFrameTiming called multiple times.")); hmds->BeginFrameTimingCalled = true; - double thisFrameTime = hmds->TimeManager.BeginFrame(frameIndex); - - const FrameTimeManager::Timing &frameTiming = hmds->TimeManager.GetFrameTiming(); + // If a frame index is specified, + if (frameIndex != 0) + { + // Use the next one after the last BeginFrame() index. + hmds->BeginFrameIndex = (uint32_t)frameIndex; + } + else + { + frameIndex = hmds->BeginFrameIndex; + } - f.ThisFrameSeconds = thisFrameTime; - f.NextFrameSeconds = frameTiming.NextFrameTime; - f.TimewarpPointSeconds = frameTiming.TimewarpPointTime; - f.ScanoutMidpointSeconds= frameTiming.MidpointTime; - f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0]; - f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1]; + // Update latency tester once per frame + hmds->LatencyTestActive = hmds->ProcessLatencyTest(hmds->LatencyTestDrawColor); - // Compute DeltaSeconds. - f.DeltaSeconds = (hmds->LastFrameTimeSeconds == 0.0f) ? 0.0f : - (float) (thisFrameTime - hmds->LastFrameTimeSeconds); - hmds->LastFrameTimeSeconds = thisFrameTime; - if (f.DeltaSeconds > 1.0f) - f.DeltaSeconds = 1.0f; + if (!hmds->BeginFrameCalled) + { + hmds->TimewarpTimer.CalculateTimewarpTiming(frameIndex); + } - return f; + return hmds->GetFrameTiming(frameIndex); } - -OVR_EXPORT void ovrHmd_EndFrameTiming(ovrHmd hmddesc) +OVR_PUBLIC_FUNCTION(void) ovrHmd_EndFrameTiming(ovrHmd hmddesc) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - if (!hmds) return; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return; // Debug state checks: Must be in BeginFrameTiming, on the same thread. hmds->checkBeginFrameTimingScope("ovrHmd_EndTiming"); // MA TBD: Correct check or not? // ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame"); - hmds->TimeManager.EndFrame(); hmds->BeginFrameTimingCalled = false; - bool dk2LatencyTest = (hmds->EnabledHmdCaps & ovrHmdCap_DynamicPrediction) != 0; - if (dk2LatencyTest) - { - Util::FrameTimeRecordSet recordset; - hmds->TheLatencyTestStateReader.GetRecordSet(recordset); - hmds->TimeManager.UpdateFrameLatencyTrackingAfterEndFrame( hmds->LatencyTest2DrawColor, - recordset); - } + hmds->endFrameRenderTiming(); } - -OVR_EXPORT void ovrHmd_ResetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex) +OVR_PUBLIC_FUNCTION(void) ovrHmd_ResetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - if (!hmds) return; - - hmds->TimeManager.ResetFrameTiming(frameIndex, - false, - hmds->RenderingConfigured); - hmds->LastFrameTimeSeconds = 0.0; - hmds->LastGetFrameTimeSeconds = 0.0; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return; + + OVR_UNUSED(frameIndex); + + // Clear timing-related state. + hmds->BeginFrameIndex = frameIndex; + hmds->TimewarpTimer.Reset(); } -OVR_EXPORT void ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], - ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState) +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetEyePoses(ovrHmd hmddesc, unsigned int frameIndex, const ovrVector3f hmdToEyeViewOffset[2], + ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState) { - HMDState* hmds = (HMDState*)hmd->Handle; - if (!hmds) return; + if (!hmdToEyeViewOffset || !outEyePoses) + { + OVR_ASSERT(false); + return; + } - hmds->LatencyTestActive = hmds->ProcessLatencyTest(hmds->LatencyTestDrawColor); - - ovrTrackingState hmdTrackingState = hmds->TimeManager.GetEyePredictionTracking(hmd, ovrEye_Count, frameIndex); + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + { + outEyePoses[0] = ovrPosef(); outEyePoses[0].Orientation.w = 1; + outEyePoses[1] = ovrPosef(); outEyePoses[1].Orientation.w = 1; + if (outHmdTrackingState) + *outHmdTrackingState = GetNullTrackingState(); + return; + } + + // If no frame index is provided, + if (frameIndex == 0) + { + // Use the next one in the series. + frameIndex = hmds->BeginFrameIndex; + } + + ovrTrackingState hmdTrackingState = hmds->GetMidpointPredictionTracking(frameIndex); + TraceTrackingState(hmdTrackingState); ovrPosef hmdPose = hmdTrackingState.HeadPose.ThePose; // caller passed in a valid pointer, so copy to output - if(outHmdTrackingState) + if (outHmdTrackingState) *outHmdTrackingState = hmdTrackingState; // Currently HmdToEyeViewOffset is only a 3D vector // (Negate HmdToEyeViewOffset because offset is a view matrix offset and not a camera offset) outEyePoses[0] = Posef(hmdPose.Orientation, ((Posef)hmdPose).Apply(-((Vector3f)hmdToEyeViewOffset[0]))); outEyePoses[1] = Posef(hmdPose.Orientation, ((Posef)hmdPose).Apply(-((Vector3f)hmdToEyeViewOffset[1]))); - - // Instrument data from eye pose - hmds->LagStats.InstrumentEyePose(hmdTrackingState); } -ovrPosef ovrHmd_GetHmdPosePerEye(ovrHmd hmd, ovrEyeType eye) +OVR_PUBLIC_FUNCTION(ovrPosef) ovrHmd_GetHmdPosePerEye(ovrHmd hmddesc, ovrEyeType eye) { - HMDState* hmds = (HMDState*)hmd->Handle; - if (!hmds) return ovrPosef(); - - // This isn't a great place, but since we removed ovrHmd_BeginEyeRender... - // Only process latency tester for drawing the left eye (assumes left eye is drawn first) - if (hmds->pRenderer && eye == 0) + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) { - hmds->LatencyTestActive = hmds->ProcessLatencyTest(hmds->LatencyTestDrawColor); + ovrPosef nullPose = ovrPosef(); + nullPose.Orientation.w = 1.0f; // Return a proper quaternion. + return nullPose; } hmds->checkBeginFrameTimingScope("ovrHmd_GetEyePose"); - return hmds->TimeManager.GetEyePredictionPose(hmd, eye); + + return hmds->GetEyePredictionPose(eye); } -OVR_EXPORT void ovrHmd_AddDistortionTimeMeasurement(ovrHmd hmddesc, double distortionTimeSeconds) +OVR_PUBLIC_FUNCTION(void) ovrHmd_AddDistortionTimeMeasurement(ovrHmd hmddesc, double distortionTimeSeconds) { - if (!hmddesc) + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) return; - HMDState* hmds = (HMDState*)hmddesc->Handle; hmds->checkBeginFrameTimingScope("ovrHmd_GetTimewarpEyeMatrices"); - hmds->TimeManager.AddDistortionTimeMeasurement(distortionTimeSeconds); -} - + hmds->TimewarpTimer.AddDistortionTimeMeasurement(distortionTimeSeconds); +} -OVR_EXPORT void ovrHmd_GetEyeTimewarpMatricesDebug(ovrHmd hmddesc, ovrEyeType eye, - ovrPosef renderPose, ovrMatrix4f twmOut[2],double debugTimingOffsetInSeconds) +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetEyeTimewarpMatricesDebug(ovrHmd hmddesc, ovrEyeType eye, ovrPosef renderPose, + ovrQuatf playerTorsoMotion, ovrMatrix4f twmOut[2], + double debugTimingOffsetInSeconds) { - if (!hmddesc) + if (!twmOut) + { + OVR_ASSERT(false); + return; + } + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) return; - HMDState* hmds = (HMDState*)hmddesc->Handle; // Debug checks: BeginFrame was called, on the same thread. hmds->checkBeginFrameTimingScope("ovrHmd_GetTimewarpEyeMatrices"); - hmds->TimeManager.GetTimewarpMatrices(hmddesc, eye, renderPose, twmOut, debugTimingOffsetInSeconds); + // TODO: Position input disabled for now + bool calcPosition = false; + ovrVector3f* hmdToEyeViewOffset = nullptr; - /* - // MA: Took this out because new latency test approach just sames - // the sample times in FrameTimeManager. - // TODO: if no timewarp, then test latency in begin eye render - if (eye == 0) - { - hmds->ProcessLatencyTest2(hmds->LatencyTest2DrawColor, -1.0f); - } - */ + // playerTorsoMotion can be fed in by the app to indicate player rotation, + // i.e. renderPose is in torso space, and playerTorsoMotion says that torso space changed. + Quatf playerTorsoMotionInv = Quatf(playerTorsoMotion).Inverted(); + Posef renderPoseTorso = (Posef)renderPose * Posef(playerTorsoMotionInv, Vector3f::Zero()); + hmds->GetTimewarpMatricesEx(eye, renderPoseTorso, calcPosition, hmdToEyeViewOffset, twmOut, + debugTimingOffsetInSeconds); } -OVR_EXPORT void ovrHmd_GetEyeTimewarpMatrices(ovrHmd hmddesc, ovrEyeType eye, - ovrPosef renderPose, ovrMatrix4f twmOut[2]) +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetEyeTimewarpMatrices(ovrHmd hmddesc, ovrEyeType eye, ovrPosef renderPose, ovrMatrix4f twmOut[2]) { - return(ovrHmd_GetEyeTimewarpMatricesDebug(hmddesc, eye, renderPose, twmOut, 0.0)); -} + if (!twmOut) + { + OVR_ASSERT(false); + return; + } + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return; + + // Shortcut to doing orientation-only timewarp. + hmds->GetTimewarpMatrices(eye, renderPose, twmOut); +} -OVR_EXPORT ovrEyeRenderDesc ovrHmd_GetRenderDesc(ovrHmd hmddesc, - ovrEyeType eyeType, ovrFovPort fov) +OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc) ovrHmd_GetRenderDesc(ovrHmd hmddesc, + ovrEyeType eyeType, ovrFovPort fov) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - ovrEyeRenderDesc erd; - + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); if (!hmds) - { - memset(&erd, 0, sizeof(erd)); - return erd; - } + return ovrEyeRenderDesc(); return hmds->RenderState.CalcRenderDesc(eyeType, fov); } - #if defined(OVR_CC_MSVC) #define OVR_OFFSET_OF(s, field) ((size_t)&((s*)0)->field) #else @@ -925,39 +963,56 @@ OVR_EXPORT ovrEyeRenderDesc ovrHmd_GetRenderDesc(ovrHmd hmddesc, #endif +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_CreateDistortionMeshDebug(ovrHmd hmddesc, + ovrEyeType eyeType, ovrFovPort fov, + unsigned int distortionCaps, + ovrDistortionMesh *meshData, + float debugEyeReliefOverrideInMetres) +{ + if (!meshData) + { + OVR_ASSERT(false); + return ovrFalse; + } + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return ovrFalse; -OVR_EXPORT ovrBool ovrHmd_CreateDistortionMeshDebug( ovrHmd hmddesc, - ovrEyeType eyeType, ovrFovPort fov, - unsigned int distortionCaps, - ovrDistortionMesh *meshData, - float debugEyeReliefOverrideInMetres) -{ - // The 'internal' function below can be found in CAPI_HMDState. - // Not ideal, but navigating the convolutions of what compiles - // where, meant they are in the few places which actually lets these compile. - // Please relocate (if you wish) to a more meaningful place if you can navigate the compiler gymnastics :) - return(ovrHmd_CreateDistortionMeshInternal( hmddesc->Handle, - eyeType, fov, - distortionCaps, - meshData, - debugEyeReliefOverrideInMetres)); - -} -OVR_EXPORT ovrBool ovrHmd_CreateDistortionMesh( ovrHmd hmddesc, - ovrEyeType eyeType, ovrFovPort fov, - unsigned int distortionCaps, - ovrDistortionMesh *meshData) + return hmds->CreateDistortionMesh(eyeType, fov, + distortionCaps, + meshData, + debugEyeReliefOverrideInMetres) + ? ovrTrue : ovrFalse; +} + + +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_CreateDistortionMesh(ovrHmd hmddesc, + ovrEyeType eyeType, ovrFovPort fov, + unsigned int distortionCaps, + ovrDistortionMesh *meshData) { - return(ovrHmd_CreateDistortionMeshDebug( hmddesc, eyeType, fov, distortionCaps,meshData, 0)); + if (!meshData) + { + OVR_ASSERT(false); + return ovrFalse; + } + + return ovrHmd_CreateDistortionMeshDebug(hmddesc, eyeType, fov, distortionCaps, meshData, 0); } // Frees distortion mesh allocated by ovrHmd_GenerateDistortionMesh. meshData elements // are set to null and 0s after the call. -OVR_EXPORT void ovrHmd_DestroyDistortionMesh(ovrDistortionMesh* meshData) +OVR_PUBLIC_FUNCTION(void) ovrHmd_DestroyDistortionMesh(ovrDistortionMesh* meshData) { + if (!meshData) + { + OVR_ASSERT(false); + return; + } + if (meshData->pVertexData) DistortionMeshDestroy((DistortionMeshVertexData*)meshData->pVertexData, meshData->pIndexData); @@ -971,10 +1026,16 @@ OVR_EXPORT void ovrHmd_DestroyDistortionMesh(ovrDistortionMesh* meshData) // Computes updated 'uvScaleOffsetOut' to be used with a distortion if render target size or // viewport changes after the fact. This can be used to adjust render size every frame, if desired. -OVR_EXPORT void ovrHmd_GetRenderScaleAndOffset( ovrFovPort fov, - ovrSizei textureSize, ovrRecti renderViewport, - ovrVector2f uvScaleOffsetOut[2] ) +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetRenderScaleAndOffset(ovrFovPort fov, + ovrSizei textureSize, ovrRecti renderViewport, + ovrVector2f uvScaleOffsetOut[2] ) { + if (!uvScaleOffsetOut) + { + OVR_ASSERT(false); + return; + } + // Find the mapping from TanAngle space to target NDC space. ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov); // Find the mapping from TanAngle space to textureUV space. @@ -982,73 +1043,95 @@ OVR_EXPORT void ovrHmd_GetRenderScaleAndOffset( ovrFovPort fov, eyeToSourceNDC, renderViewport, textureSize ); - uvScaleOffsetOut[0] = eyeToSourceUV.Scale; - uvScaleOffsetOut[1] = eyeToSourceUV.Offset; + if (uvScaleOffsetOut) + { + uvScaleOffsetOut[0] = eyeToSourceUV.Scale; + uvScaleOffsetOut[1] = eyeToSourceUV.Offset; + } } //------------------------------------------------------------------------------------- // ***** Latency Test interface -OVR_EXPORT ovrBool ovrHmd_GetLatencyTestDrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3]) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_GetLatencyTestDrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3]) { - HMDState* p = (HMDState*)hmddesc->Handle; - rgbColorOut[0] = p->LatencyTestDrawColor[0]; - rgbColorOut[1] = p->LatencyTestDrawColor[1]; - rgbColorOut[2] = p->LatencyTestDrawColor[2]; - return p->LatencyTestActive; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return ovrFalse; + + if (rgbColorOut) + { + rgbColorOut[0] = hmds->LatencyTestDrawColor[0]; + rgbColorOut[1] = hmds->LatencyTestDrawColor[1]; + rgbColorOut[2] = hmds->LatencyTestDrawColor[2]; + } + + return hmds->LatencyTestActive; } -OVR_EXPORT ovrBool ovrHmd_ProcessLatencyTest(ovrHmd hmddesc, unsigned char rgbColorOut[3]) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_ProcessLatencyTest(ovrHmd hmddesc, unsigned char rgbColorOut[3]) { OVR_UNUSED(hmddesc); + + if (!rgbColorOut) + { + OVR_ASSERT(false); + return ovrFalse; + } + return NetClient::GetInstance()->LatencyUtil_ProcessInputs(Timer::GetSeconds(), rgbColorOut); } -OVR_EXPORT const char* ovrHmd_GetLatencyTestResult(ovrHmd hmddesc) +OVR_PUBLIC_FUNCTION(const char*) ovrHmd_GetLatencyTestResult(ovrHmd hmddesc) { OVR_UNUSED(hmddesc); + return NetClient::GetInstance()->LatencyUtil_GetResultsString(); } -OVR_EXPORT ovrBool ovrHmd_GetLatencyTest2DrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3]) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_GetLatencyTest2DrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3]) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - if (!hmds) return false; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return ovrFalse; // TBD: Move directly into renderer bool dk2LatencyTest = (hmds->EnabledHmdCaps & ovrHmdCap_DynamicPrediction) != 0; if (dk2LatencyTest) { - hmds->TimeManager.GetFrameLatencyTestDrawColor(hmds->LatencyTest2DrawColor); - if(rgbColorOut != NULL) + hmds->LatencyTest2DrawColor[0] = hmds->ScreenLatencyTracker.GetNextDrawColor(); + hmds->LatencyTest2DrawColor[1] = hmds->ScreenLatencyTracker.IsLatencyTimingAvailable() ? 255 : 0; + hmds->LatencyTest2DrawColor[2] = hmds->ScreenLatencyTracker.IsLatencyTimingAvailable() ? 0 : 255; + + if (rgbColorOut) { rgbColorOut[0] = hmds->LatencyTest2DrawColor[0]; rgbColorOut[1] = hmds->LatencyTest2DrawColor[1]; rgbColorOut[2] = hmds->LatencyTest2DrawColor[2]; } - if(hmds->pRenderer != NULL) + if (hmds->pRenderer) hmds->pRenderer->SetLatencyTest2Color(hmds->LatencyTest2DrawColor); } else { - if(hmds->pRenderer != NULL) - hmds->pRenderer->SetLatencyTest2Color(NULL); + if (hmds->pRenderer) + hmds->pRenderer->SetLatencyTest2Color(nullptr); } - return dk2LatencyTest; + return dk2LatencyTest ? ovrTrue : ovrFalse; } -OVR_EXPORT double ovrHmd_GetMeasuredLatencyTest2(ovrHmd hmddesc) +OVR_PUBLIC_FUNCTION(double) ovrHmd_GetMeasuredLatencyTest2(ovrHmd hmddesc) { - HMDState* p = (HMDState*)hmddesc->Handle; - - // MA Test - float latencyRender, latencyTimewarp, latencyPostPresent; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return 0.; - p->TimeManager.GetLatencyTimings(latencyRender, latencyTimewarp, latencyPostPresent); + double latencyPostPresent = 0.; + hmds->ScreenLatencyTracker.GetVsyncToScanout(latencyPostPresent); return latencyPostPresent; } @@ -1059,253 +1142,296 @@ OVR_EXPORT double ovrHmd_GetMeasuredLatencyTest2(ovrHmd hmddesc) #if !defined(HEADLESS_APP) -OVR_EXPORT void ovrHmd_GetHSWDisplayState(ovrHmd hmd, ovrHSWDisplayState *hswDisplayState) +OVR_PUBLIC_FUNCTION(void) ovrHmd_GetHSWDisplayState(ovrHmd hmddesc, ovrHSWDisplayState *hswDisplayState) { - OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle; - - if (pHMDState) + if (!hswDisplayState) { - OVR::CAPI::HSWDisplay* pHSWDisplay = pHMDState->pHSWDisplay; - - if(pHSWDisplay) - pHSWDisplay->TickState(hswDisplayState); // This may internally call HSWDisplay::Display. + OVR_ASSERT(false); + return; } + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return; + + OVR::CAPI::HSWDisplay* pHSWDisplay = hmds->pHSWDisplay; + + if (pHSWDisplay) + pHSWDisplay->TickState(hswDisplayState); // This may internally call HSWDisplay::Display. } -OVR_EXPORT ovrBool ovrHmd_DismissHSWDisplay(ovrHmd hmd) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_DismissHSWDisplay(ovrHmd hmddesc) { - OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) + return ovrFalse; - if (pHMDState) - { - OVR::CAPI::HSWDisplay* pHSWDisplay = pHMDState->pHSWDisplay; + OVR::CAPI::HSWDisplay* pHSWDisplay = hmds->pHSWDisplay; - if(pHSWDisplay) - return (pHSWDisplay->Dismiss() ? 1 : 0); - } + if (pHSWDisplay && pHSWDisplay->Dismiss()) + return ovrTrue; - return false; + return ovrFalse; } #endif /* !defined(HEADLESS_APP) */ // ----------------------------------------------------------------------------------- // ***** Property Access -OVR_EXPORT ovrBool ovrHmd_GetBool(ovrHmd hmddesc, - const char* propertyName, - ovrBool defaultVal) + +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_GetBool(ovrHmd hmddesc, + const char* propertyName, + ovrBool defaultVal) { - OVR_ASSERT(propertyName); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ovrFalse; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + bool success = false; + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->getBoolValue(propertyName, (defaultVal != 0)); - } + success = hmds->getBoolValue(propertyName, (defaultVal != ovrFalse)); } - - return NetClient::GetInstance()->GetBoolValue(InvalidVirtualHmdId, propertyName, (defaultVal != 0)) ? 1 : 0; -} - -OVR_EXPORT ovrBool ovrHmd_SetBool(ovrHmd hmddesc, - const char* propertyName, - ovrBool value) -{ - OVR_ASSERT(propertyName); - if (hmddesc) + else { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->setBoolValue(propertyName, value != 0) ? 1 : 0; - } + success = NetClient::GetInstance()->GetBoolValue(InvalidVirtualHmdId, propertyName, (defaultVal != ovrFalse)); } - - return NetClient::GetInstance()->SetBoolValue(InvalidVirtualHmdId, propertyName, (value != 0)) ? 1 : 0; + return success ? ovrTrue : ovrFalse; } -OVR_EXPORT int ovrHmd_GetInt(ovrHmd hmddesc, - const char* propertyName, - int defaultVal) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetBool(ovrHmd hmddesc, + const char* propertyName, + ovrBool value) { - OVR_ASSERT(propertyName); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ovrFalse; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + bool retval = false; + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->getIntValue(propertyName, defaultVal); - } + retval = hmds->setBoolValue(propertyName, value != ovrFalse); } - - return NetClient::GetInstance()->GetIntValue(InvalidVirtualHmdId, propertyName, defaultVal); + else + { + retval = NetClient::GetInstance()->SetBoolValue(InvalidVirtualHmdId, propertyName, (value != ovrFalse)); + } + return retval ? ovrTrue : ovrFalse; } -OVR_EXPORT ovrBool ovrHmd_SetInt(ovrHmd hmddesc, - const char* propertyName, - int value) +OVR_PUBLIC_FUNCTION(int) ovrHmd_GetInt(ovrHmd hmddesc, + const char* propertyName, + int defaultVal) { - OVR_ASSERT(propertyName); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ovrFalse; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->setIntValue(propertyName, value) ? 1 : 0; - } + return hmds->getIntValue(propertyName, defaultVal); + } + else + { + return NetClient::GetInstance()->GetIntValue(InvalidVirtualHmdId, propertyName, defaultVal); } - - return NetClient::GetInstance()->SetIntValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0; } -OVR_EXPORT float ovrHmd_GetFloat(ovrHmd hmddesc, - const char* propertyName, - float defaultVal) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetInt(ovrHmd hmddesc, + const char* propertyName, + int value) { - OVR_ASSERT(propertyName); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ovrFalse; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + bool success = false; + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->getFloatValue(propertyName, defaultVal); - } + success = hmds->setIntValue(propertyName, value); } - - return (float)NetClient::GetInstance()->GetNumberValue(InvalidVirtualHmdId, propertyName, defaultVal); + else + { + success = NetClient::GetInstance()->SetIntValue(InvalidVirtualHmdId, propertyName, value); + } + return success ? ovrTrue : ovrFalse; } -OVR_EXPORT ovrBool ovrHmd_SetFloat(ovrHmd hmddesc, - const char* propertyName, - float value) +OVR_PUBLIC_FUNCTION(float) ovrHmd_GetFloat(ovrHmd hmddesc, + const char* propertyName, + float defaultVal) { - OVR_ASSERT(propertyName); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ovrFalse; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->setFloatValue(propertyName, value) ? 1 : 0; - } + return hmds->getFloatValue(propertyName, defaultVal); + } + else + { + return (float)NetClient::GetInstance()->GetNumberValue(InvalidVirtualHmdId, propertyName, defaultVal); } - - return NetClient::GetInstance()->SetNumberValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0; } -OVR_EXPORT unsigned int ovrHmd_GetFloatArray(ovrHmd hmddesc, +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetFloat(ovrHmd hmddesc, const char* propertyName, - float values[], - unsigned int arraySize) + float value) { - OVR_ASSERT(propertyName); - OVR_ASSERT(hmddesc); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ovrFalse; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + bool success = false; + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->getFloatArray(propertyName, values, arraySize); - } + success = hmds->setFloatValue(propertyName, value); + } + else + { + success = NetClient::GetInstance()->SetNumberValue(InvalidVirtualHmdId, propertyName, value); } + return success ? ovrTrue : ovrFalse; +} + +OVR_PUBLIC_FUNCTION(unsigned int) ovrHmd_GetFloatArray(ovrHmd hmddesc, + const char* propertyName, + float values[], + unsigned int arraySize) +{ + OVR_ASSERT(propertyName != nullptr && values != nullptr); + if (!propertyName || !values) + return 0; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) return 0; - // FIXME: Currently it takes a few lines of code to do this, so just not supported for now. - return 0; + return hmds->getFloatArray(propertyName, values, arraySize); } // Modify float[] property; false if property doesn't exist or is readonly. -OVR_EXPORT ovrBool ovrHmd_SetFloatArray(ovrHmd hmddesc, - const char* propertyName, - float values[], - unsigned int arraySize) +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetFloatArray(ovrHmd hmddesc, + const char* propertyName, + float values[], + unsigned int arraySize) { - OVR_ASSERT(propertyName); - OVR_ASSERT(hmddesc); - if (hmddesc) - { - HMDState* hmds = (HMDState*)hmddesc->Handle; - OVR_ASSERT(hmds); - if (hmds) - { - return hmds->setFloatArray(propertyName, values, arraySize) ? 1 : 0; - } - } + OVR_ASSERT(propertyName != nullptr && values != nullptr); + if (!propertyName || !values) + return ovrFalse; - // FIXME: Currently it takes a few lines of code to do this, so just not supported for now. - return 0; + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (!hmds) return ovrFalse; + + return hmds->setFloatArray(propertyName, values, arraySize) ? ovrTrue : ovrFalse; } -OVR_EXPORT const char* ovrHmd_GetString(ovrHmd hmddesc, - const char* propertyName, - const char* defaultVal) +OVR_PUBLIC_FUNCTION(const char*) ovrHmd_GetString(ovrHmd hmddesc, + const char* propertyName, + const char* defaultVal) { - OVR_ASSERT(propertyName); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ""; + + // Replace null default with empty string + if (!defaultVal) + defaultVal = ""; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - if (hmds) - { - return hmds->getString(propertyName, defaultVal); - } + return hmds->getString(propertyName, defaultVal); + } + else + { + return NetClient::GetInstance()->GetStringValue(InvalidVirtualHmdId, propertyName, defaultVal); } - - return NetClient::GetInstance()->GetStringValue(InvalidVirtualHmdId, propertyName, defaultVal); } - -OVR_EXPORT ovrBool ovrHmd_SetString(ovrHmd hmddesc, - const char* propertyName, - const char* value) + +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_SetString(ovrHmd hmddesc, + const char* propertyName, + const char* value) { - OVR_ASSERT(propertyName); - if (hmddesc) + OVR_ASSERT(propertyName != nullptr); + if (!propertyName) + return ovrFalse; + + // Replace null value with empty string + if (!value) + value = ""; + + HMDState* hmds = GetHMDStateFromOvrHmd(hmddesc); + bool success = false; + if (hmds) { - HMDState* hmds = (HMDState*)hmddesc->Handle; - if (hmds) - { - return hmds->setString(propertyName, value) ? 1 : 0; - } + success = hmds->setString(propertyName, value); } - - return NetClient::GetInstance()->SetStringValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0; + else + { + success = NetClient::GetInstance()->SetStringValue(InvalidVirtualHmdId, propertyName, value); + } + return success ? ovrTrue : ovrFalse; } + // ----------------------------------------------------------------------------------- // ***** Logging -OVR_EXPORT ovrBool ovrHmd_StartPerfLog(ovrHmd hmd, const char* fileName, const char* userData1) -{ - OVR_ASSERT(fileName && fileName[0]); +// make sure OVR_Log.h's enum matches CAPI's +static_assert( + ((ovrLogLevel_Debug == ovrLogLevel(LogLevel_Debug)) && + (ovrLogLevel_Info == ovrLogLevel(LogLevel_Info)) && + (ovrLogLevel_Error == ovrLogLevel(LogLevel_Error))), + "mismatched LogLevel enums" +); - OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle; +#define OVR_TRACEMSG_MAX_LEN 1024 /* in chars */ - if (pHMDState) - { - ovrBool started = pHMDState->LagStatsCSV.Start(fileName, userData1) ? 1 : 0; - if (started) - pHMDState->LagStats.AddResultsObserver(pHMDState->LagStatsCSV.GetObserver()); - return started; - } - return 0; -} -OVR_EXPORT ovrBool ovrHmd_StopPerfLog(ovrHmd hmd) +OVR_PUBLIC_FUNCTION(int) ovr_TraceMessage(int level, const char* message) { - OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle; + OVR_ASSERT(message != nullptr); + if (!message) + return -1; + + // Keep traced messages to some reasonable maximum length + int len = (int)strnlen(message, OVR_TRACEMSG_MAX_LEN); + if (len >= OVR_TRACEMSG_MAX_LEN) + return -1; - if (pHMDState) + switch (level) { - return pHMDState->LagStatsCSV.Stop() ? 1 : 0; + case ovrLogLevel_Debug: + TraceLogDebug(message); + break; + case ovrLogLevel_Info: + default: + TraceLogInfo(message); + break; + case ovrLogLevel_Error: + TraceLogError(message); + break; } - return false; + + return len; } +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_StartPerfLog(ovrHmd hmddesc, const char* fileName, const char* userData1) +{ + // DEPRECATED + OVR_UNUSED3(hmddesc, fileName, userData1); + return ovrFalse; +} -#ifdef __cplusplus -} // extern "C" -#endif +OVR_PUBLIC_FUNCTION(ovrBool) ovrHmd_StopPerfLog(ovrHmd hmddesc) +{ + // DEPRECATED + OVR_UNUSED(hmddesc); + return ovrFalse; +} |