Skip to content

Commit d0e142d

Browse files
committed
Workaround for OVRPlugin incorrectly using prediction refinement.
1 parent 5dfaedf commit d0e142d

File tree

3 files changed

+42
-14
lines changed

3 files changed

+42
-14
lines changed

virtualdesktop-openxr/instance.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ namespace virtualdesktop_openxr {
221221
}
222222

223223
m_applicationName = createInfo->applicationInfo.applicationName;
224+
m_isUnity = startsWith(createInfo->applicationInfo.engineName, "Unity");
224225

225226
Log("Application: %s (%s); Engine: %s\n",
226227
m_applicationName.c_str(),

virtualdesktop-openxr/runtime.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ namespace virtualdesktop_openxr {
662662
bool m_loggedResolution{false};
663663
std::string m_applicationName;
664664
std::string m_exeName;
665+
bool m_isUnity{false};
665666
bool m_useApplicationDeviceForSubmission{true};
666667
EyeTracking m_eyeTrackingType{EyeTracking::None};
667668
wil::unique_handle m_bodyStateFile;
@@ -841,7 +842,9 @@ namespace virtualdesktop_openxr {
841842
uint32_t m_actionSourcePriority[(size_t)ActionSourceIndex::Count]{};
842843
BodyTracking::BodyStateV2 m_cachedBodyState{};
843844
XrTime m_lastPredictedDisplayTime{0};
845+
XrTime m_lastRequestedViewDisplayTime{0};
844846
mutable std::optional<XrPosef> m_lastValidHmdPose;
847+
mutable std::optional<XrView> m_lastValidViews;
845848
std::optional<float> m_lastSeenIpd{};
846849

847850
// Statistics.

virtualdesktop-openxr/space.cpp

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -330,18 +330,26 @@ namespace virtualdesktop_openxr {
330330

331331
// Debug option to test reprojection.
332332
if (m_jiggleViewRotations) {
333-
static std::mt19937_64 randGen(0);
334-
335-
// Scale jitter by FOV.
336-
const float randMax = (views[i].fov.angleRight - views[i].fov.angleLeft) * 0.06f;
337-
std::uniform_real_distribution<float> dist(-randMax, randMax);
338-
const auto randomQuatJiggle =
339-
DirectX::XMVectorSet(dist(randGen), dist(randGen), dist(randGen), dist(randGen));
340-
const auto originalPoseOrientation = xr::math::LoadXrQuaternion(views[i].pose.orientation);
341-
const auto poseOrientationWithJiggle =
342-
DirectX::XMVectorAdd(originalPoseOrientation, randomQuatJiggle);
343-
xr::math::StoreXrQuaternion(&views[i].pose.orientation,
344-
DirectX::XMVector4Normalize(poseOrientationWithJiggle));
333+
// To investigate cross-frame or within-frame issues.
334+
const bool useSameJiggleForEachDisplayTime = false;
335+
if (!useSameJiggleForEachDisplayTime ||
336+
m_lastRequestedViewDisplayTime != viewLocateInfo->displayTime) {
337+
static std::mt19937_64 randGen(0);
338+
339+
// Scale jitter by FOV.
340+
const float randMax = (views[i].fov.angleRight - views[i].fov.angleLeft) * 0.06f;
341+
std::uniform_real_distribution<float> dist(-randMax, randMax);
342+
const auto randomQuatJiggle =
343+
DirectX::XMVectorSet(dist(randGen), dist(randGen), dist(randGen), dist(randGen));
344+
const auto originalPoseOrientation = xr::math::LoadXrQuaternion(views[i].pose.orientation);
345+
const auto poseOrientationWithJiggle =
346+
DirectX::XMVectorAdd(originalPoseOrientation, randomQuatJiggle);
347+
xr::math::StoreXrQuaternion(&views[i].pose.orientation,
348+
DirectX::XMVector4Normalize(poseOrientationWithJiggle));
349+
} else if (m_lastValidViews) {
350+
*views = m_lastValidViews.value();
351+
}
352+
m_lastValidViews = *views;
345353
}
346354

347355
TraceLoggingWrite(g_traceProvider,
@@ -359,14 +367,15 @@ namespace virtualdesktop_openxr {
359367
} else {
360368
m_lastSeenIpd.reset();
361369
}
362-
363370
} else {
364371
// All or nothing.
365372
viewState->viewStateFlags = 0;
366373
TraceLoggingWrite(g_traceProvider, "xrLocateViews", TLArg(viewState->viewStateFlags, "ViewStateFlags"));
367374
}
368375
}
369376

377+
m_lastRequestedViewDisplayTime = viewLocateInfo->displayTime;
378+
370379
return XR_SUCCESS;
371380
}
372381

@@ -599,6 +608,13 @@ namespace virtualdesktop_openxr {
599608
XrSpaceLocationFlags locationFlags = 0;
600609
ovrPoseStatef state{};
601610
ovrTrackedDeviceType hmd = ovrTrackedDevice_HMD;
611+
612+
// OVRPlugin assumes that xrLocateViews() with the same displayTime returns the same value across calls, which
613+
// violates OpenXR spec 1.0 per 10.2. View and Projection State: "Repeatedly calling xrLocateViews with the same
614+
// time may not necessarily return the same result. Instead the prediction gets increasingly accurate as the
615+
// function is called closer to the given time for which a prediction is made.".
616+
const bool enablePredictionRefinement = !(m_isUnity && m_isOculusXrPlugin);
617+
602618
const auto result = ovr_GetDevicePoses(m_ovrSession, &hmd, 1, xrTimeToOvrTime(time), &state);
603619
if (result == ovrError_LostTracking) {
604620
TraceLoggingWrite(g_traceProvider, "OVR_HmdPoseNotTracking");
@@ -615,7 +631,15 @@ namespace virtualdesktop_openxr {
615631
if (isTracked) {
616632
locationFlags |= (XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT |
617633
XR_SPACE_LOCATION_POSITION_VALID_BIT | XR_SPACE_LOCATION_POSITION_TRACKED_BIT);
618-
pose = ovrPoseToXrPose(state.ThePose);
634+
if (enablePredictionRefinement || time != m_lastRequestedViewDisplayTime) {
635+
pose = ovrPoseToXrPose(state.ThePose);
636+
} else if (m_lastValidHmdPose) {
637+
// Return the same pose for the same timestamp.
638+
pose = m_lastValidHmdPose.value();
639+
} else {
640+
locationFlags = 0;
641+
pose = Pose::Identity();
642+
}
619643
} else {
620644
if (m_lastValidHmdPose) {
621645
locationFlags |= XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_POSITION_VALID_BIT;

0 commit comments

Comments
 (0)