aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/CAPI/CAPI_HMDState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/CAPI/CAPI_HMDState.cpp')
-rwxr-xr-x[-rw-r--r--]LibOVR/Src/CAPI/CAPI_HMDState.cpp780
1 files changed, 523 insertions, 257 deletions
diff --git a/LibOVR/Src/CAPI/CAPI_HMDState.cpp b/LibOVR/Src/CAPI/CAPI_HMDState.cpp
index 6ea9958..4aae646 100644..100755
--- a/LibOVR/Src/CAPI/CAPI_HMDState.cpp
+++ b/LibOVR/Src/CAPI/CAPI_HMDState.cpp
@@ -27,116 +27,80 @@ limitations under the License.
#include "CAPI_HMDState.h"
#include "../OVR_Profile.h"
#include "../Service/Service_NetClient.h"
+
#ifdef OVR_OS_WIN32
-#include "../Displays/OVR_Win32_ShimFunctions.h"
+ #include "../Displays/OVR_Win32_ShimFunctions.h"
+
+ // For auto-detection of window handle for direct mode:
+ #include <OVR_CAPI_D3D.h>
+ #include <GL/CAPI_GLE.h>
+ #include <OVR_CAPI_GL.h>
+
+#elif defined(OVR_OS_LINUX)
+
+ #include "../Displays/OVR_Linux_SDKWindow.h" // For screen rotation
+
#endif
+#include "Tracing/Tracing.h"
+
namespace OVR { namespace CAPI {
-// Accessed via HMDState::GetHMDStateList()
+// Accessed via HMDState::EnumerateHMDStateList()
+static OVR::Lock hmdStateListLock;
static OVR::List<HMDState> hmdStateList; // List of all created HMDStates.
//-------------------------------------------------------------------------------------
// ***** HMDState
-HMDState::HMDState(const OVR::Service::HMDNetworkInfo& netInfo,
- const OVR::HMDInfo& hmdInfo,
- Profile* profile,
- Service::NetClient* client) :
+HMDState::HMDState(HMDInfo const & hmdInfo,
+ Profile* profile,
+ Service::HMDNetworkInfo const * netInfo,
+ Service::NetClient* client) :
+ TimewarpTimer(),
+ RenderTimer(),
+ RenderIMUTimeSeconds(0.),
pProfile(profile),
pHmdDesc(0),
pWindow(0),
pClient(client),
- NetId(netInfo.NetId),
- NetInfo(netInfo),
- OurHMDInfo(hmdInfo),
- pLastError(NULL),
- EnabledHmdCaps(0),
- EnabledServiceHmdCaps(0),
- SharedStateReader(),
- TheSensorStateReader(),
- TheLatencyTestStateReader(),
- LatencyTestActive(false),
- //LatencyTestDrawColor(),
- LatencyTest2Active(false),
- //LatencyTest2DrawColor(),
- TimeManager(true),
- RenderState(),
- pRenderer(),
- pHSWDisplay(),
- LastFrameTimeSeconds(0.),
- LastGetFrameTimeSeconds(0.),
- //LastGetStringValue(),
- RenderingConfigured(false),
- BeginFrameCalled(false),
- BeginFrameThreadId(),
- RenderAPIThreadChecker(),
- BeginFrameTimingCalled(false)
-{
- sharedInit(profile);
- hmdStateList.PushBack(this);
-}
-
-
-HMDState::HMDState(const OVR::HMDInfo& hmdInfo, Profile* profile) :
- pProfile(profile),
- pHmdDesc(0),
- pWindow(0),
- pClient(0),
NetId(InvalidVirtualHmdId),
NetInfo(),
OurHMDInfo(hmdInfo),
- pLastError(NULL),
+ pLastError(nullptr),
EnabledHmdCaps(0),
EnabledServiceHmdCaps(0),
- SharedStateReader(),
- TheSensorStateReader(),
+ CombinedHmdReader(),
+ TheTrackingStateReader(),
TheLatencyTestStateReader(),
LatencyTestActive(false),
//LatencyTestDrawColor(),
LatencyTest2Active(false),
//LatencyTest2DrawColor(),
- TimeManager(true),
+ ScreenLatencyTracker(),
RenderState(),
pRenderer(),
pHSWDisplay(),
- LastFrameTimeSeconds(0.),
- LastGetFrameTimeSeconds(0.),
//LastGetStringValue(),
RenderingConfigured(false),
BeginFrameCalled(false),
BeginFrameThreadId(),
+ BeginFrameIndex(0),
RenderAPIThreadChecker(),
BeginFrameTimingCalled(false)
{
- sharedInit(profile);
- hmdStateList.PushBack(this);
-}
-
-HMDState::~HMDState()
-{
- hmdStateList.Remove(this);
-
- if (pClient)
+ if (netInfo)
{
- pClient->Hmd_Release(NetId);
- pClient = 0;
+ NetId = netInfo->NetId;
+ NetInfo = *netInfo;
}
- ConfigureRendering(0,0,0,0);
-
- if (pHmdDesc)
- {
- OVR_FREE(pHmdDesc);
- pHmdDesc = NULL;
- }
-}
+ // Hook up the app timing lockless updater
+ RenderTimer.SetUpdater(TimewarpTimer.GetUpdater());
-void HMDState::sharedInit(Profile* profile)
-{
// TBD: We should probably be looking up the default profile for the given
// device type + user if profile == 0.
pLastError = 0;
@@ -154,10 +118,12 @@ void HMDState::sharedInit(Profile* profile)
RenderState.ClearColor[1] = 0.0f;
RenderState.ClearColor[2] = 0.0f;
RenderState.ClearColor[3] = 0.0f;
-
RenderState.EnabledHmdCaps = 0;
- TimeManager.Init(RenderState.RenderInfo);
+ if (!TimewarpTimer.Initialize(&RenderState, &ScreenLatencyTracker))
+ {
+ OVR_ASSERT(false);
+ }
/*
LatencyTestDrawColor[0] = 0;
@@ -165,19 +131,60 @@ void HMDState::sharedInit(Profile* profile)
LatencyTestDrawColor[2] = 0;
*/
- RenderingConfigured = false;
- BeginFrameCalled = false;
- BeginFrameThreadId = 0;
+ RenderingConfigured = false;
+ BeginFrameCalled = false;
+ BeginFrameThreadId = 0;
BeginFrameTimingCalled = false;
// Construct the HSWDisplay. We will later reconstruct it with a specific ovrRenderAPI type if the application starts using SDK-based rendering.
if(!pHSWDisplay)
{
pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(ovrRenderAPI_None, pHmdDesc, RenderState);
- pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true));
+ }
+
+ RenderIMUTimeSeconds = 0.;
+
+ hmdStateListLock.DoLock();
+ hmdStateList.PushBack(this);
+ hmdStateListLock.Unlock();
+}
+
+HMDState::~HMDState()
+{
+ hmdStateListLock.DoLock();
+ hmdStateList.Remove(this);
+ hmdStateListLock.Unlock();
+
+ if (pClient)
+ {
+ pClient->Hmd_Release(NetId);
+ pClient = 0;
+ }
+
+ ConfigureRendering(0,0,0,0);
+
+ if (pHmdDesc)
+ {
+ OVR_FREE(pHmdDesc);
+ pHmdDesc = nullptr;
}
}
+bool HMDState::InitializeSharedState()
+{
+ if (!CombinedHmdReader.Open(NetInfo.SharedMemoryName.Hmd.ToCStr()) ||
+ !CameraReader.Open(NetInfo.SharedMemoryName.Camera.ToCStr()))
+ {
+ return false;
+ }
+
+ TheTrackingStateReader.SetUpdaters(CombinedHmdReader.Get(), CameraReader.Get());
+ TheLatencyTestStateReader.SetUpdater(CombinedHmdReader.Get());
+
+
+ return true;
+}
+
static Vector3f GetNeckModelFromProfile(Profile* profile)
{
OVR_ASSERT(profile);
@@ -220,7 +227,9 @@ static float GetCenterPupilDepthFromRenderInfo(HmdRenderInfo* hmdRenderInfo)
void HMDState::UpdateRenderProfile(Profile* profile)
{
// Apply the given profile to generate a render context
- RenderState.RenderInfo = GenerateHmdRenderInfoFromHmdInfo(RenderState.OurHMDInfo, profile);
+ RenderState.OurProfileRenderInfo = GenerateProfileRenderInfoFromProfile(RenderState.OurHMDInfo, profile);
+ RenderState.RenderInfo = GenerateHmdRenderInfoFromHmdInfo(RenderState.OurHMDInfo, RenderState.OurProfileRenderInfo);
+
RenderState.Distortion[0] = CalculateDistortionRenderDesc(StereoEye_Left, RenderState.RenderInfo, 0);
RenderState.Distortion[1] = CalculateDistortionRenderDesc(StereoEye_Right, RenderState.RenderInfo, 0);
@@ -239,19 +248,25 @@ void HMDState::UpdateRenderProfile(Profile* profile)
};
pClient->SetNumberValues(GetNetId(), "NeckModelVector3f", neckModelArray, 3);
- double camerastate[7];
- if (profile->GetDoubleValues(OVR_KEY_CAMERA_POSITION, camerastate, 7) == 0)
+ // Camera position
+
+ // OVR_KEY_CAMERA_POSITION is actually the *inverse* of a camera position.
+ Posed centeredFromWorld;
+
+ double values[7];
+ if (profile->GetDoubleValues(OVR_KEY_CAMERA_POSITION, values, 7) == 7)
{
- //there is no value, so we load the default
- for (int i = 0; i < 7; i++) camerastate[i] = 0;
- camerastate[3] = 1;//no offset. by default, give the quaternion w component value 1
+ centeredFromWorld = Posed::FromArray(values);
}
else
+ {
+ centeredFromWorld = TheTrackingStateReader.GetDefaultCenteredFromWorld();
+ }
- TheSensorStateReader.setCenteredFromWorld(OVR::Posed::FromArray(camerastate));
+ // ComputeCenteredFromWorld wants a worldFromCpf pose, so invert it.
+ // FIXME: The stored centeredFromWorld doesn't have a neck model offset applied, but probably should.
+ TheTrackingStateReader.ComputeCenteredFromWorld(centeredFromWorld.Inverted(), Vector3d(0, 0, 0));
}
-
-
}
HMDState* HMDState::CreateHMDState(NetClient* client, const HMDNetworkInfo& netInfo)
@@ -261,11 +276,11 @@ HMDState* HMDState::CreateHMDState(NetClient* client, const HMDNetworkInfo& netI
if (!client->Hmd_GetHmdInfo(netInfo.NetId, &hinfo))
{
OVR_DEBUG_LOG(("[HMDState] Unable to get HMD info"));
- return NULL;
+ return nullptr;
}
#ifdef OVR_OS_WIN32
- OVR_DEBUG_LOG(("Setting up display shim"));
+ OVR_DEBUG_LOG(("[HMDState] Setting up display shim"));
// Initialize the display shim before reporting the display to the user code
// so that this will happen before the D3D display object is created.
@@ -273,23 +288,20 @@ HMDState* HMDState::CreateHMDState(NetClient* client, const HMDNetworkInfo& netI
#endif
Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultUserProfile(&hinfo);
- OVR_DEBUG_LOG(("Using profile %s", pDefaultProfile->GetValue(OVR_KEY_USER)));
+ OVR_DEBUG_LOG(("[HMDState] Using profile %s", pDefaultProfile->GetValue(OVR_KEY_USER)));
- HMDState* hmds = new HMDState(netInfo, hinfo, pDefaultProfile, client);
+ HMDState* hmds = new HMDState(hinfo, pDefaultProfile, &netInfo, client);
- if (!hmds->SharedStateReader.Open(netInfo.SharedMemoryName.ToCStr()))
+ if (!hmds->InitializeSharedState())
{
delete hmds;
- return NULL;
+ return nullptr;
}
- hmds->TheSensorStateReader.SetUpdater(hmds->SharedStateReader.Get());
- hmds->TheLatencyTestStateReader.SetUpdater(hmds->SharedStateReader.Get());
-
return hmds;
}
-HMDState* HMDState::CreateHMDState(ovrHmdType hmdType)
+HMDState* HMDState::CreateDebugHMDState(ovrHmdType hmdType)
{
HmdTypeEnum t = HmdType_None;
if (hmdType == ovrHmd_DK1)
@@ -299,41 +311,51 @@ HMDState* HMDState::CreateHMDState(ovrHmdType hmdType)
// FIXME: This does not actually grab the right user..
Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultProfile(t);
-
+
return new HMDState(CreateDebugHMDInfo(t), pDefaultProfile);
}
-
-const OVR::List<HMDState>& HMDState::GetHMDStateList()
+// Enumerate each open HMD
+unsigned HMDState::EnumerateHMDStateList(bool (*callback)(const HMDState *state))
{
- return hmdStateList;
+ unsigned count = 0;
+ hmdStateListLock.DoLock();
+ for (const HMDState *hmds = hmdStateList.GetFirst(); !hmdStateList.IsNull(hmds); hmds = hmdStateList.GetNext(hmds))
+ {
+ if (callback && !callback(hmds))
+ break;
+ ++count;
+ }
+ hmdStateListLock.Unlock();
+ return count;
}
-
//-------------------------------------------------------------------------------------
// *** Sensor
bool HMDState::ConfigureTracking(unsigned supportedCaps, unsigned requiredCaps)
{
- return pClient ? pClient->Hmd_ConfigureTracking(NetId, supportedCaps, requiredCaps) : true;
+ return pClient ? pClient->Hmd_ConfigureTracking(NetId, supportedCaps, requiredCaps) : true;
}
-void HMDState::ResetTracking()
+void HMDState::ResetTracking(bool visionReset)
{
- if (pClient) pClient->Hmd_ResetTracking(NetId);
+ if (pClient) pClient->Hmd_ResetTracking(NetId, visionReset);
}
// Re-center the orientation.
void HMDState::RecenterPose()
{
- TheSensorStateReader.RecenterPose();
+ float hnm[3];
+ getFloatArray("NeckModelVector3f", hnm, 3);
+ TheTrackingStateReader.RecenterPose(Vector3d(hnm[0], hnm[1], hnm[2]));
}
// Returns prediction for time.
-ovrTrackingState HMDState::PredictedTrackingState(double absTime)
-{
- Tracking::TrackingState ss;
- TheSensorStateReader.GetSensorStateAtTime(absTime, ss);
+ovrTrackingState HMDState::PredictedTrackingState(double absTime, void*)
+{
+ Vision::TrackingState ss;
+ TheTrackingStateReader.GetTrackingStateAtTime(absTime, ss);
// Zero out the status flags
if (!pClient || !pClient->IsConnected(false, false))
@@ -341,6 +363,12 @@ ovrTrackingState HMDState::PredictedTrackingState(double absTime)
ss.StatusFlags = 0;
}
+#ifdef OVR_OS_WIN32
+ // Set up display code for Windows
+ Win32::DisplayShim::GetInstance().Active = (ss.StatusFlags & ovrStatus_HmdConnected) != 0;
+#endif
+
+
return ss;
}
@@ -350,31 +378,11 @@ void HMDState::SetEnabledHmdCaps(unsigned hmdCaps)
{
// disable low persistence and pentile.
hmdCaps &= ~ovrHmdCap_LowPersistence;
- hmdCaps &= ~ovrHmdCap_DirectPentile;
// disable dynamic prediction using the internal latency tester
hmdCaps &= ~ovrHmdCap_DynamicPrediction;
}
- if (OurHMDInfo.HmdType >= HmdType_DK2)
- {
- if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_DynamicPrediction)
- {
- // DynamicPrediction change
- TimeManager.ResetFrameTiming(TimeManager.GetFrameTiming().FrameIndex,
- (hmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
- RenderingConfigured);
- }
- }
-
- // Pentile unsupported on everything right now.
- hmdCaps &= ~ovrHmdCap_DirectPentile;
-
- if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoVSync)
- {
- TimeManager.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true);
- }
-
if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoMirrorToWindow)
{
#ifdef OVR_OS_WIN32
@@ -398,7 +406,7 @@ void HMDState::SetEnabledHmdCaps(unsigned hmdCaps)
unsigned newServiceCaps = hmdCaps & ovrHmdCap_Writable_Mask & ovrHmdCap_Service_Mask;
if (prevServiceCaps ^ newServiceCaps)
- {
+ {
EnabledServiceHmdCaps = pClient ? pClient->Hmd_SetEnabledCaps(NetId, newServiceCaps)
: newServiceCaps;
}
@@ -407,7 +415,7 @@ void HMDState::SetEnabledHmdCaps(unsigned hmdCaps)
unsigned HMDState::SetEnabledHmdCaps()
{
- unsigned serviceCaps = pClient ? pClient->Hmd_GetEnabledCaps(NetId) :
+ unsigned serviceCaps = pClient ? pClient->Hmd_GetEnabledCaps(NetId) :
EnabledServiceHmdCaps;
return serviceCaps & ((~ovrHmdCap_Service_Mask) | EnabledHmdCaps);
@@ -436,12 +444,12 @@ bool HMDState::getBoolValue(const char* propertyName, bool defaultVal)
bool HMDState::setBoolValue(const char* propertyName, bool value)
{
- if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetBoolValue, propertyName))
- {
- return NetClient::GetInstance()->SetBoolValue(GetNetId(), propertyName, value);
- }
+ if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetBoolValue, propertyName))
+ {
+ return NetClient::GetInstance()->SetBoolValue(GetNetId(), propertyName, value);
+ }
- return false;
+ return false;
}
int HMDState::getIntValue(const char* propertyName, int defaultVal)
@@ -459,12 +467,12 @@ int HMDState::getIntValue(const char* propertyName, int defaultVal)
bool HMDState::setIntValue(const char* propertyName, int value)
{
- if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetIntValue, propertyName))
- {
- return NetClient::GetInstance()->SetIntValue(GetNetId(), propertyName, value);
- }
+ if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetIntValue, propertyName))
+ {
+ return NetClient::GetInstance()->SetIntValue(GetNetId(), propertyName, value);
+ }
- return false;
+ return false;
}
float HMDState::getFloatValue(const char* propertyName, float defaultVal)
@@ -495,12 +503,12 @@ float HMDState::getFloatValue(const char* propertyName, float defaultVal)
bool HMDState::setFloatValue(const char* propertyName, float value)
{
- if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValue, propertyName))
- {
- return NetClient::GetInstance()->SetNumberValue(GetNetId(), propertyName, value);
- }
+ if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValue, propertyName))
+ {
+ return NetClient::GetInstance()->SetNumberValue(GetNetId(), propertyName, value);
+ }
- return false;
+ return false;
}
static unsigned CopyFloatArrayWithLimit(float dest[], unsigned destSize,
@@ -514,37 +522,70 @@ static unsigned CopyFloatArrayWithLimit(float dest[], unsigned destSize,
unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize)
{
- if (arraySize)
- {
- if (OVR_strcmp(propertyName, "ScreenSize") == 0)
- {
- float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h };
+ if (arraySize)
+ {
+ if (OVR_strcmp(propertyName, "ScreenSize") == 0)
+ {
+ float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h };
return CopyFloatArrayWithLimit(values, arraySize, data, 2);
- }
+ }
else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0)
{
return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4);
}
else if (OVR_strcmp(propertyName, "DK2Latency") == 0)
{
- if (OurHMDInfo.HmdType != HmdType_DK2)
+ if (OurHMDInfo.HmdType < HmdType_DK2)
{
return 0;
}
- union {
- struct X {
- float latencyRender, latencyTimewarp, latencyPostPresent;
- } x;
- float data[3];
- } m;
+ OutputLatencyTimings timings;
+ ScreenLatencyTracker.GetLatencyTimings(timings);
+
+ if (arraySize > 0)
+ {
+ switch (arraySize)
+ {
+ default: values[4] = (float)timings.ErrorTimewarp; // Fall-thru
+ case 4: values[3] = (float)timings.ErrorRender; // Fall-thru
+ case 3: values[2] = (float)timings.LatencyPostPresent; // Fall-thru
+ case 2: values[1] = (float)timings.LatencyTimewarp; // Fall-thru
+ case 1: values[0] = (float)timings.LatencyRender;
+ }
+ }
+
+ return arraySize > 5 ? 5 : arraySize;
+ }
+ else if (OVR_strcmp(propertyName, "NeckModelVector3f") == 0)
+ {
+ // Query the service to grab the HNM.
+ double hnm[3] = {};
+ int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, hnm, (int)arraySize);
- static_assert(sizeof(m.x)==sizeof(m.data), "sizeof(struct X) failure");
+ // If the service is unavailable or returns zero data,
+ if (count < 3 ||
+ (hnm[0] == 0.0 && hnm[1] == 0.0 && hnm[2] == 0.0))
+ {
+ // These are the default values used if the server does not return any data, due to not
+ // being reachable or other errors.
+ OVR_ASSERT(pProfile.GetPtr());
+ if (pProfile.GetPtr())
+ {
+ Vector3f neckModel = GetNeckModelFromProfile(pProfile);
+ hnm[0] = neckModel.x;
+ hnm[1] = neckModel.y;
+ hnm[2] = neckModel.z;
+ }
+ }
- TimeManager.GetLatencyTimings(m.x.latencyRender, m.x.latencyTimewarp, m.x.latencyPostPresent);
+ for (unsigned i = 0; i < 3 && i < arraySize; ++i)
+ {
+ values[i] = (float)hnm[i];
+ }
- return CopyFloatArrayWithLimit(values, arraySize, m.data, 3);
+ return arraySize > 3 ? 3 : arraySize;
}
else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName))
{
@@ -566,16 +607,16 @@ unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsig
return count;
}
- else if (pProfile)
- {
- // TBD: Not quite right. Should update profile interface, so that
- // we can return 0 in all conditions if property doesn't exist.
-
+ else if (pProfile)
+ {
+ // TBD: Not quite right. Should update profile interface, so that
+ // we can return 0 in all conditions if property doesn't exist.
+
return pProfile->GetFloatValues(propertyName, values, arraySize);
- }
- }
+ }
+ }
- return 0;
+ return 0;
}
bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned arraySize)
@@ -591,22 +632,22 @@ bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned
return true;
}
- if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValues, propertyName))
- {
- double* da = new double[arraySize];
- for (int i = 0; i < (int)arraySize; ++i)
- {
- da[i] = values[i];
- }
+ if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValues, propertyName))
+ {
+ double* da = new double[arraySize];
+ for (int i = 0; i < (int)arraySize; ++i)
+ {
+ da[i] = values[i];
+ }
- bool result = NetClient::GetInstance()->SetNumberValues(GetNetId(), propertyName, da, arraySize);
+ bool result = NetClient::GetInstance()->SetNumberValues(GetNetId(), propertyName, da, arraySize);
- delete[] da;
+ delete[] da;
- return result;
- }
+ return result;
+ }
- return false;
+ return false;
}
const char* HMDState::getString(const char* propertyName, const char* defaultVal)
@@ -616,26 +657,26 @@ const char* HMDState::getString(const char* propertyName, const char* defaultVal
return NetClient::GetInstance()->GetStringValue(GetNetId(), propertyName, defaultVal);
}
- if (pProfile)
- {
- LastGetStringValue[0] = 0;
- if (pProfile->GetValue(propertyName, LastGetStringValue, sizeof(LastGetStringValue)))
- {
- return LastGetStringValue;
- }
- }
+ if (pProfile)
+ {
+ LastGetStringValue[0] = 0;
+ if (pProfile->GetValue(propertyName, LastGetStringValue, sizeof(LastGetStringValue)))
+ {
+ return LastGetStringValue;
+ }
+ }
- return defaultVal;
+ return defaultVal;
}
bool HMDState::setString(const char* propertyName, const char* value)
{
- if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetStringValue, propertyName))
- {
- return NetClient::GetInstance()->SetStringValue(GetNetId(), propertyName, value);
- }
+ if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetStringValue, propertyName))
+ {
+ return NetClient::GetInstance()->SetStringValue(GetNetId(), propertyName, value);
+ }
- return false;
+ return false;
}
@@ -647,6 +688,200 @@ bool HMDState::ProcessLatencyTest(unsigned char rgbColorOut[3])
return NetClient::GetInstance()->LatencyUtil_ProcessInputs(Timer::GetSeconds(), rgbColorOut);
}
+
+//-------------------------------------------------------------------------------------
+// *** Timewarp
+
+AppTiming HMDState::GetAppTiming(uint32_t frameIndex)
+{
+ // Get prediction time for the requested frame index
+ AppTiming timing;
+ const bool VsyncOn = ((RenderState.EnabledHmdCaps & ovrHmdCap_NoVSync) == 0);
+ RenderTimer.GetAppTimingForIndex(timing, VsyncOn, frameIndex);
+
+ // Update the predicted scanout time for this frame index
+ TimingHistory.SetScanoutTimeForFrame(frameIndex, timing.ScanoutStartTime);
+
+ return timing;
+}
+
+ovrFrameTiming HMDState::GetFrameTiming(uint32_t frameIndex)
+{
+ AppTiming timing = GetAppTiming(frameIndex);
+
+ // Calculate eye render times based on shutter type
+ double eyePhotonsTimes[2];
+ CalculateEyeRenderTimes(timing.VisibleMidpointTime, timing.FrameInterval,
+ RenderState.RenderInfo.Shutter.Type,
+ eyePhotonsTimes[0], eyePhotonsTimes[1]);
+
+ RenderIMUTimeSeconds = Timer::GetSeconds(); // RenderPrediction.RawSensorData.TimeInSeconds;
+
+ // Construct a ovrFrameTiming object from the base app timing information
+ ovrFrameTiming result;
+ result.DeltaSeconds = (float)timing.FrameInterval;
+ result.EyeScanoutSeconds[0] = eyePhotonsTimes[0];
+ result.EyeScanoutSeconds[1] = eyePhotonsTimes[1];
+ result.ScanoutMidpointSeconds = timing.VisibleMidpointTime;
+ result.ThisFrameSeconds = timing.ScanoutStartTime - timing.FrameInterval;
+ result.NextFrameSeconds = timing.ScanoutStartTime;
+ // Deprecated: This should be queried after render work completes. Please delete me from CAPI.
+ result.TimewarpPointSeconds = 0.;
+ return result;
+}
+
+ovrTrackingState HMDState::GetMidpointPredictionTracking(uint32_t frameIndex)
+{
+ AppTiming timing = GetAppTiming(frameIndex);
+ RenderIMUTimeSeconds = Timer::GetSeconds(); // RenderPrediction.RawSensorData.TimeInSeconds;
+ return PredictedTrackingState(timing.VisibleMidpointTime);
+}
+
+Posef HMDState::GetEyePredictionPose(ovrEyeType eye)
+{
+ // Note that this function does not get the frame index parameter and depends
+ // on whichever value is passed into the BeginFrame() function.
+ ovrTrackingState ts = GetMidpointPredictionTracking(BeginFrameIndex);
+ TraceTrackingState(ts);
+ Posef const & hmdPose = ts.HeadPose.ThePose;
+
+ // Currently HmdToEyeViewOffset is only a 3D vector
+ // (Negate HmdToEyeViewOffset because offset is a view matrix offset and not a camera offset)
+ if (eye == ovrEye_Left)
+ {
+ return Posef(hmdPose.Rotation, ((Posef)hmdPose).Apply(-((Vector3f)RenderState.EyeRenderDesc[0].HmdToEyeViewOffset)));
+ }
+ else
+ {
+ return Posef(hmdPose.Rotation, ((Posef)hmdPose).Apply(-((Vector3f)RenderState.EyeRenderDesc[1].HmdToEyeViewOffset)));
+ }
+}
+
+void HMDState::endFrameRenderTiming()
+{
+ TimewarpTimer.SetLastPresentTime(); // Record approximate vsync time
+
+ bool dk2LatencyTest = (EnabledHmdCaps & ovrHmdCap_DynamicPrediction) != 0;
+ if (dk2LatencyTest)
+ {
+ Util::FrameTimeRecordSet recordSet;
+ TheLatencyTestStateReader.GetRecordSet(recordSet);
+
+ FrameLatencyData data;
+ data.DrawColor = LatencyTest2DrawColor[0];
+ data.RenderIMUTime = RenderIMUTimeSeconds;
+ data.RenderPredictedScanoutTime = TimingHistory.LookupScanoutTime(BeginFrameIndex);
+ data.PresentTime = TimewarpTimer.GetLatencyTesterPresentTime();
+ data.TimewarpPredictedScanoutTime = TimewarpTimer.GetTimewarpTiming()->ScanoutTime;
+ data.TimewarpIMUTime = TimewarpTimer.GetTimewarpIMUTime();
+
+ //OVR_ASSERT(data.TimewarpIMUTime == 0. || data.TimewarpIMUTime >= data.RenderIMUTime);
+
+ ScreenLatencyTracker.SaveDrawColor(data);
+ ScreenLatencyTracker.MatchRecord(recordSet);
+ }
+}
+
+void HMDState::getTimewarpStartEnd(ovrEyeType eyeId, double timewarpStartEnd[2])
+{
+ // Get eye start/end scanout times
+ TimewarpTiming const* timewarpTiming = TimewarpTimer.GetTimewarpTiming();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ timewarpStartEnd[i] = timewarpTiming->EyeStartEndTimes[eyeId][i];
+ }
+}
+
+void HMDState::GetTimewarpMatricesEx(ovrEyeType eyeId,
+ ovrPosef renderPose,
+ bool calcPosition, const ovrVector3f hmdToEyeViewOffset[2],
+ ovrMatrix4f twmOut[2], double debugTimingOffsetInSeconds)
+{
+ // Get timewarp start/end timing
+ double timewarpStartEnd[2];
+ getTimewarpStartEnd(eyeId, timewarpStartEnd);
+
+ //TPH, to vary timing, to allow developers to debug, to shunt the predicted time forward
+ //and back, and see if the SDK is truly delivering the correct time. Also to allow
+ //illustration of the detrimental effects when this is not done right.
+ timewarpStartEnd[0] += debugTimingOffsetInSeconds;
+ timewarpStartEnd[1] += debugTimingOffsetInSeconds;
+
+ ovrTrackingState startState = PredictedTrackingState(timewarpStartEnd[0]);
+ ovrTrackingState endState = PredictedTrackingState(timewarpStartEnd[1]);
+
+ ovrPosef startHmdPose = startState.HeadPose.ThePose;
+ ovrPosef endHmdPose = endState.HeadPose.ThePose;
+ Vector3f eyeOffset = Vector3f(0.0f, 0.0f, 0.0f);
+ Matrix4f timewarpStart, timewarpEnd;
+ if (calcPosition)
+ {
+ if (!hmdToEyeViewOffset)
+ {
+ OVR_ASSERT(false);
+ LogError("{ERR-102} [FrameTime] No hmdToEyeViewOffset provided even though calcPosition is true.");
+
+ // disable position to avoid positional issues
+ renderPose.Position = Vector3f::Zero();
+ startHmdPose.Position = Vector3f::Zero();
+ endHmdPose.Position = Vector3f::Zero();
+ }
+ else if (hmdToEyeViewOffset[eyeId].x >= MATH_FLOAT_MAXVALUE)
+ {
+ OVR_ASSERT(false);
+ LogError("{ERR-103} [FrameTime] Invalid hmdToEyeViewOffset provided by client.");
+
+ // disable position to avoid positional issues
+ renderPose.Position = Vector3f::Zero();
+ startHmdPose.Position = Vector3f::Zero();
+ endHmdPose.Position = Vector3f::Zero();
+ }
+ else
+ {
+ // Currently HmdToEyeViewOffset is only a 3D vector
+ // (Negate HmdToEyeViewOffset because offset is a view matrix offset and not a camera offset)
+ eyeOffset = ((Posef)startHmdPose).Apply(-((Vector3f)hmdToEyeViewOffset[eyeId]));
+ }
+
+ Posef fromEye = Posef(renderPose).Inverted(); // because we need the view matrix, not the camera matrix
+ CalculatePositionalTimewarpMatrix(fromEye, startHmdPose, eyeOffset, timewarpStart);
+ CalculatePositionalTimewarpMatrix(fromEye, endHmdPose, eyeOffset, timewarpEnd);
+ }
+ else
+ {
+ Quatf fromEye = Quatf(renderPose.Orientation).Inverted(); // because we need the view matrix, not the camera matrix
+ CalculateOrientationTimewarpMatrix(fromEye, startHmdPose.Orientation, timewarpStart);
+ CalculateOrientationTimewarpMatrix(fromEye, endHmdPose.Orientation, timewarpEnd);
+ }
+ twmOut[0] = timewarpStart;
+ twmOut[1] = timewarpEnd;
+}
+
+void HMDState::GetTimewarpMatrices(ovrEyeType eyeId, ovrPosef renderPose,
+ ovrMatrix4f twmOut[2])
+{
+ // Get timewarp start/end timing
+ double timewarpStartEnd[2];
+ getTimewarpStartEnd(eyeId, timewarpStartEnd);
+
+ ovrTrackingState startState = PredictedTrackingState(timewarpStartEnd[0]);
+ ovrTrackingState endState = PredictedTrackingState(timewarpStartEnd[1]);
+
+ Quatf quatFromEye = Quatf(renderPose.Orientation);
+ quatFromEye.Invert(); // because we need the view matrix, not the camera matrix
+
+ Matrix4f timewarpStart, timewarpEnd;
+ CalculateOrientationTimewarpMatrix(
+ quatFromEye, startState.HeadPose.ThePose.Orientation, timewarpStart);
+ CalculateOrientationTimewarpMatrix(
+ quatFromEye, endState.HeadPose.ThePose.Orientation, timewarpEnd);
+
+ twmOut[0] = timewarpStart;
+ twmOut[1] = timewarpEnd;
+}
+
+
//-------------------------------------------------------------------------------------
// *** Rendering
@@ -686,7 +921,7 @@ bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2],
pRenderer.Clear();
}
- distortionCaps = distortionCaps & pHmdDesc->DistortionCaps;
+ distortionCaps = distortionCaps & pHmdDesc->DistortionCaps;
// Step 1: do basic setup configuration
RenderState.EnabledHmdCaps = EnabledHmdCaps; // This is a copy... Any cleaner way?
@@ -696,27 +931,22 @@ bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2],
eyeRenderDescOut[0] = RenderState.EyeRenderDesc[0];
eyeRenderDescOut[1] = RenderState.EyeRenderDesc[1];
- TimeManager.ResetFrameTiming(0,
- (EnabledHmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
- true);
-
- LastFrameTimeSeconds = 0.0f;
-
// Set RenderingConfigured early to avoid ASSERTs in renderer initialization.
RenderingConfigured = true;
if (!pRenderer)
{
pRenderer = *DistortionRenderer::APICreateRegistry
- [apiConfig->Header.API](pHmdDesc, TimeManager, RenderState);
+ [apiConfig->Header.API]();
}
if (!pRenderer ||
- !pRenderer->Initialize(apiConfig))
+ !pRenderer->Initialize(apiConfig, &TheTrackingStateReader,
+ &TimewarpTimer, &RenderState))
{
RenderingConfigured = false;
return false;
- }
+ }
// Setup the Health and Safety Warning display system.
if(pHSWDisplay && (pHSWDisplay->GetRenderAPIType() != apiConfig->Header.API)) // If we need to reconstruct the HSWDisplay for a different graphics API type, delete the existing display.
@@ -728,83 +958,120 @@ bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2],
if(!pHSWDisplay) // Use * below because that for of operator= causes it to inherit the refcount the factory gave the object.
{
pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(apiConfig->Header.API, pHmdDesc, RenderState);
- pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true));
}
if (pHSWDisplay)
+ {
pHSWDisplay->Initialize(apiConfig); // This is potentially re-initializing it with a new config.
+ }
+
+#ifdef OVR_OS_WIN32
+ if (!pWindow)
+ {
+ // We can automatically populate the window to attach to by
+ // pulling that information off the swap chain that the
+ // application provides. If the application later calls the
+ // ovrHmd_AttachToWindow() function these will get harmlessly
+ // overwritten. The check above verifies that the window is
+ // not set yet, and it insures that this default doesn't
+ // overwrite the application setting.
+
+ if (apiConfig->Header.API == ovrRenderAPI_D3D11)
+ {
+ ovrD3D11Config* d3d11Config = (ovrD3D11Config*)apiConfig;
+ if (d3d11Config->D3D11.pSwapChain)
+ {
+ DXGI_SWAP_CHAIN_DESC desc = {};
+ HRESULT hr = d3d11Config->D3D11.pSwapChain->GetDesc(&desc);
+ if (SUCCEEDED(hr))
+ {
+ pWindow = (void*)desc.OutputWindow;
+ }
+ }
+ }
+ else if (apiConfig->Header.API == ovrRenderAPI_OpenGL)
+ {
+ ovrGLConfig* glConfig = (ovrGLConfig*)apiConfig;
+ pWindow = (void*)glConfig->OGL.Window;
+ }
+OVR_DISABLE_MSVC_WARNING(4996) // Disable deprecation warning
+ else if (apiConfig->Header.API == ovrRenderAPI_D3D9)
+ {
+ ovrD3D9Config* dx9Config = (ovrD3D9Config*)apiConfig;
+ if (dx9Config->D3D9.pDevice)
+ {
+ D3DDEVICE_CREATION_PARAMETERS params = {};
+ HRESULT hr = dx9Config->D3D9.pDevice->GetCreationParameters(&params);
+ if (SUCCEEDED(hr))
+ {
+ pWindow = (void*)params.hFocusWindow;
+ }
+ }
+ }
+OVR_RESTORE_MSVC_WARNING()
+
+ // If a window handle was implied by render configuration,
+ if (pWindow)
+ {
+ // This is the same logic as ovrHmd_AttachToWindow() on Windows:
+ if (pClient)
+ pClient->Hmd_AttachToWindow(GetNetId(), pWindow);
+ Win32::DisplayShim::GetInstance().hWindow = (HWND)pWindow;
+ // On the server side it is updating the association of connection
+ // to window handle. This is perfectly safe to update later to
+ // a new window handle (verified). Also verified that if this
+ // handle is garbage that it doesn't crash anything.
+ }
+ }
+#endif
return true;
}
void HMDState::SubmitEyeTextures(const ovrPosef renderPose[2],
- const ovrTexture eyeTexture[2])
+ const ovrTexture eyeTexture[2],
+ const ovrTexture eyeDepthTexture[2])
{
RenderState.EyeRenderPoses[0] = renderPose[0];
RenderState.EyeRenderPoses[1] = renderPose[1];
if (pRenderer)
{
+ if(eyeDepthTexture)
+ {
+ pRenderer->SubmitEyeWithDepth(0, &eyeTexture[0], &eyeDepthTexture[0]);
+ pRenderer->SubmitEyeWithDepth(1, &eyeTexture[1], &eyeDepthTexture[1]);
+ }
+ else
+ {
+ //OVR_ASSERT(!(RenderState.DistortionCaps & ovrDistortionCap_DepthProjectedTimeWarp));
+ //LogError("{ERR-104} [HMDState] Even though ovrDistortionCap_DepthProjectedTimeWarp is enabled, no depth buffer was provided.");
+
pRenderer->SubmitEye(0, &eyeTexture[0]);
pRenderer->SubmitEye(1, &eyeTexture[1]);
}
}
+}
-
-// I appreciate this is not an idea place for this function, but it didn't seem to be
-// being linked properly when in OVR_CAPI.cpp.
-// Please relocate if you know of a better place
-ovrBool ovrHmd_CreateDistortionMeshInternal( ovrHmdStruct * hmd,
- ovrEyeType eyeType, ovrFovPort fov,
- unsigned int distortionCaps,
- ovrDistortionMesh *meshData,
- float overrideEyeReliefIfNonZero )
+bool HMDState::CreateDistortionMesh(ovrEyeType eyeType, ovrFovPort fov,
+ unsigned int distortionCaps,
+ ovrDistortionMesh *meshData,
+ float overrideEyeReliefIfNonZero)
{
- if (!meshData)
- return 0;
- HMDState* hmds = (HMDState*)hmd;
-
- // Not used now, but Chromatic flag or others could possibly be checked for in the future.
- OVR_UNUSED1(distortionCaps);
-
-#if defined (OVR_CC_MSVC)
- static_assert(sizeof(DistortionMeshVertexData) == sizeof(ovrDistortionVertex), "DistortionMeshVertexData size mismatch");
-#endif
-
- // *** Calculate a part of "StereoParams" needed for mesh generation
-
- // Note that mesh distortion generation is invariant of RenderTarget UVs, allowing
- // render target size and location to be changed after the fact dynamically.
- // eyeToSourceUV is computed here for convenience, so that users don't need
- // to call ovrHmd_GetRenderScaleAndOffset unless changing RT dynamically.
+ const HmdRenderInfo& hmdri = RenderState.RenderInfo;
- const HmdRenderInfo& hmdri = hmds->RenderState.RenderInfo;
- StereoEye stereoEye = (eyeType == ovrEye_Left) ? StereoEye_Left : StereoEye_Right;
-
- DistortionRenderDesc& distortion = hmds->RenderState.Distortion[eyeType];
- if (overrideEyeReliefIfNonZero)
- {
- distortion.Lens = GenerateLensConfigFromEyeRelief(overrideEyeReliefIfNonZero,hmdri);
- }
-
- // Find the mapping from TanAngle space to target NDC space.
- ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov);
-
- int triangleCount = 0;
- int vertexCount = 0;
-
- DistortionMeshCreate((DistortionMeshVertexData**)&meshData->pVertexData,
- (uint16_t**)&meshData->pIndexData,
- &vertexCount, &triangleCount,
- (stereoEye == StereoEye_Right),
- hmdri, distortion, eyeToSourceNDC);
+ DistortionRenderDesc& distortion = RenderState.Distortion[eyeType];
+ if (overrideEyeReliefIfNonZero)
+ {
+ distortion.Lens = GenerateLensConfigFromEyeRelief(overrideEyeReliefIfNonZero, hmdri);
+ }
- if (meshData->pVertexData)
+ if (CalculateDistortionMeshFromFOV(
+ hmdri, distortion,
+ (eyeType == ovrEye_Left ? StereoEye_Left : StereoEye_Right),
+ fov, distortionCaps, meshData))
{
- // Convert to index
- meshData->IndexCount = triangleCount * 3;
- meshData->VertexCount = vertexCount;
return 1;
}
@@ -812,5 +1079,4 @@ ovrBool ovrHmd_CreateDistortionMeshInternal( ovrHmdStruct * hmd,
}
-
}} // namespace OVR::CAPI