More accurate interpretation of openxr session states

pull/615/head
Mads Buvik Sandvei 4 years ago
parent cf20faff21
commit 6425749b7e

@ -179,7 +179,7 @@ namespace MWVR
OpenXRActionSet::updateControls()
{
auto* xr = Environment::get().getManager();
if (!xr->impl().xrSessionRunning())
if (!xr->impl().appShouldReadInput())
return;
const XrActiveActionSet activeActionSet{ mActionSet, XR_NULL_PATH };

@ -21,25 +21,11 @@ namespace MWVR
}
bool
OpenXRManager::realized()
OpenXRManager::realized() const
{
return !!mPrivate;
}
bool OpenXRManager::xrSessionRunning()
{
if (realized())
return impl().xrSessionRunning();
return false;
}
bool OpenXRManager::xrSessionCanRender()
{
if (realized())
return impl().xrSessionCanRender();
return false;
}
void OpenXRManager::handleEvents()
{
if (realized())
@ -56,9 +42,30 @@ namespace MWVR
return impl().beginFrame();
}
void OpenXRManager::endFrame(FrameInfo frameInfo, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack)
void OpenXRManager::endFrame(FrameInfo frameInfo, const std::array<CompositionLayerProjectionView, 2>* layerStack)
{
return impl().endFrame(frameInfo, layerStack);
}
bool OpenXRManager::appShouldSyncFrameLoop() const
{
return impl().endFrame(frameInfo, layerCount, layerStack);
if (realized())
return impl().appShouldSyncFrameLoop();
return false;
}
bool OpenXRManager::appShouldRender() const
{
if (realized())
return impl().appShouldRender();
return false;
}
bool OpenXRManager::appShouldReadInput() const
{
if (realized())
return impl().appShouldReadInput();
return false;
}
void

@ -42,7 +42,7 @@ namespace MWVR
~OpenXRManager();
/// Manager has been initialized.
bool realized();
bool realized() const;
//! Forward call to xrWaitFrame()
FrameInfo waitFrame();
@ -51,13 +51,16 @@ namespace MWVR
void beginFrame();
//! Forward call to xrEndFrame()
void endFrame(FrameInfo frameInfo, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack);
void endFrame(FrameInfo frameInfo, const std::array<CompositionLayerProjectionView, 2>* layerStack);
//! Whether the openxr session is currently in a running state
bool xrSessionRunning();
//! Whether the app should call the openxr frame sync functions ( xr*Frame() )
bool appShouldSyncFrameLoop() const;
//! Whether frames can be rendered in the current state
bool xrSessionCanRender();
//! Whether the app should render anything.
bool appShouldRender() const;
//! Whether the session is focused and can read input
bool appShouldReadInput() const;
//! Process all openxr events
void handleEvents();

@ -474,41 +474,41 @@ namespace MWVR
}
void
OpenXRManagerImpl::endFrame(FrameInfo frameInfo, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack)
{
std::array<XrCompositionLayerProjectionView, 2> compositionLayerProjectionViews{};
compositionLayerProjectionViews[(int)Side::LEFT_SIDE] = toXR(layerStack[(int)Side::LEFT_SIDE]);
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE] = toXR(layerStack[(int)Side::RIGHT_SIDE]);
XrCompositionLayerProjection layer{};
layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
layer.space = getReferenceSpace(ReferenceSpace::STAGE);
layer.viewCount = 2;
layer.views = compositionLayerProjectionViews.data();
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
std::array<XrCompositionLayerDepthInfoKHR, 2> compositionLayerDepth = mLayerDepth;
if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME))
{
auto farClip = Settings::Manager::getFloat("viewing distance", "Camera");
// All values not set here are set previously as they are constant
compositionLayerDepth[(int)Side::LEFT_SIDE].farZ = farClip;
compositionLayerDepth[(int)Side::RIGHT_SIDE].farZ = farClip;
compositionLayerDepth[(int)Side::LEFT_SIDE].subImage = layerStack[(int)Side::LEFT_SIDE].swapchain->impl().xrSubImageDepth();
compositionLayerDepth[(int)Side::RIGHT_SIDE].subImage = layerStack[(int)Side::RIGHT_SIDE].swapchain->impl().xrSubImageDepth();
if (compositionLayerDepth[(int)Side::LEFT_SIDE].subImage.swapchain != XR_NULL_HANDLE
&& compositionLayerDepth[(int)Side::RIGHT_SIDE].subImage.swapchain != XR_NULL_HANDLE)
{
compositionLayerProjectionViews[(int)Side::LEFT_SIDE].next = &compositionLayerDepth[(int)Side::LEFT_SIDE];
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE].next = &compositionLayerDepth[(int)Side::RIGHT_SIDE];
}
}
OpenXRManagerImpl::endFrame(FrameInfo frameInfo, const std::array<CompositionLayerProjectionView, 2>* layerStack)
{
XrFrameEndInfo frameEndInfo{ XR_TYPE_FRAME_END_INFO };
frameEndInfo.displayTime = frameInfo.runtimePredictedDisplayTime;
frameEndInfo.environmentBlendMode = mEnvironmentBlendMode;
//if (frameInfo.runtimeRequestsRender)
if (layerStack)
{
frameEndInfo.layerCount = layerCount;
std::array<XrCompositionLayerProjectionView, 2> compositionLayerProjectionViews{};
compositionLayerProjectionViews[(int)Side::LEFT_SIDE] = toXR((*layerStack)[(int)Side::LEFT_SIDE]);
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE] = toXR((*layerStack)[(int)Side::RIGHT_SIDE]);
XrCompositionLayerProjection layer{};
layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
layer.space = getReferenceSpace(ReferenceSpace::STAGE);
layer.viewCount = 2;
layer.views = compositionLayerProjectionViews.data();
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
std::array<XrCompositionLayerDepthInfoKHR, 2> compositionLayerDepth = mLayerDepth;
if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME))
{
auto farClip = Settings::Manager::getFloat("viewing distance", "Camera");
// All values not set here are set previously as they are constant
compositionLayerDepth[(int)Side::LEFT_SIDE].farZ = farClip;
compositionLayerDepth[(int)Side::RIGHT_SIDE].farZ = farClip;
compositionLayerDepth[(int)Side::LEFT_SIDE].subImage = (*layerStack)[(int)Side::LEFT_SIDE].swapchain->impl().xrSubImageDepth();
compositionLayerDepth[(int)Side::RIGHT_SIDE].subImage = (*layerStack)[(int)Side::RIGHT_SIDE].swapchain->impl().xrSubImageDepth();
if (compositionLayerDepth[(int)Side::LEFT_SIDE].subImage.swapchain != XR_NULL_HANDLE
&& compositionLayerDepth[(int)Side::RIGHT_SIDE].subImage.swapchain != XR_NULL_HANDLE)
{
compositionLayerProjectionViews[(int)Side::LEFT_SIDE].next = &compositionLayerDepth[(int)Side::LEFT_SIDE];
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE].next = &compositionLayerDepth[(int)Side::RIGHT_SIDE];
}
}
frameEndInfo.layerCount = 1;
frameEndInfo.layers = &xrLayerStack;
}
CHECK_XRCMD(xrEndFrame(mSession, &frameEndInfo));
@ -602,6 +602,15 @@ namespace MWVR
}
popEvent();
}
if (mXrSessionShouldStop)
{
if (checkStopCondition())
{
CHECK_XRCMD(xrEndSession(mSession));
mXrSessionShouldStop = false;
}
}
}
const XrEventDataBaseHeader* OpenXRManagerImpl::nextEvent()
@ -638,50 +647,70 @@ namespace MWVR
OpenXRManagerImpl::handleSessionStateChanged(
const XrEventDataSessionStateChanged& stateChangedEvent)
{
auto oldState = mSessionState;
auto newState = stateChangedEvent.state;
Log(Debug::Verbose) << "XrEventDataSessionStateChanged: state " << to_string(oldState) << "->" << to_string(newState);
bool success = true;
Log(Debug::Verbose) << "XrEventDataSessionStateChanged: state " << to_string(mSessionState) << "->" << to_string(stateChangedEvent.state);
mSessionState = stateChangedEvent.state;
switch (newState)
// Ref: https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#session-states
switch (mSessionState)
{
case XR_SESSION_STATE_IDLE:
{
mAppShouldSyncFrameLoop = false;
mAppShouldRender = false;
mAppShouldReadInput = false;
mXrSessionShouldStop = false;
break;
}
case XR_SESSION_STATE_READY:
{
mAppShouldSyncFrameLoop = true;
mAppShouldRender = false;
mAppShouldReadInput = false;
mXrSessionShouldStop = false;
XrSessionBeginInfo beginInfo{ XR_TYPE_SESSION_BEGIN_INFO };
beginInfo.primaryViewConfigurationType = mViewConfigType;
CHECK_XRCMD(xrBeginSession(mSession, &beginInfo));
mSessionRunning = true;
break;
}
case XR_SESSION_STATE_STOPPING:
{
if (checkStopCondition())
{
CHECK_XRCMD(xrEndSession(mSession));
mSessionStopRequested = false;
mSessionRunning = false;
}
else
{
mSessionStopRequested = true;
success = false;
}
mAppShouldSyncFrameLoop = false;
mAppShouldRender = false;
mAppShouldReadInput = false;
mXrSessionShouldStop = true;
break;
}
default:
Log(Debug::Verbose) << "XrEventDataSessionStateChanged: Ignoring new state " << to_string(newState);
case XR_SESSION_STATE_SYNCHRONIZED:
{
mAppShouldSyncFrameLoop = true;
mAppShouldRender = false;
mAppShouldReadInput = false;
mXrSessionShouldStop = false;
break;
}
if (success)
case XR_SESSION_STATE_VISIBLE:
{
mSessionState = newState;
mAppShouldSyncFrameLoop = true;
mAppShouldRender = true;
mAppShouldReadInput = false;
mXrSessionShouldStop = false;
break;
}
else
case XR_SESSION_STATE_FOCUSED:
{
Log(Debug::Verbose) << "XrEventDataSessionStateChanged: Conditions for state " << to_string(newState) << " not met, retrying next frame";
mAppShouldSyncFrameLoop = true;
mAppShouldRender = true;
mAppShouldReadInput = true;
mXrSessionShouldStop = false;
break;
}
default:
Log(Debug::Warning) << "XrEventDataSessionStateChanged: Ignoring new state " << to_string(mSessionState);
}
return success;
return true;
}
bool OpenXRManagerImpl::checkStopCondition()
@ -760,11 +789,6 @@ namespace MWVR
return mEnabledExtensions.count(extensionName) != 0;
}
bool OpenXRManagerImpl::xrSessionCanRender()
{
return xrSessionRunning() && !xrSessionStopRequested();
}
void OpenXRManagerImpl::xrResourceAcquired()
{
mAcquiredResources++;
@ -792,11 +816,6 @@ namespace MWVR
return function;
}
bool OpenXRManagerImpl::xrSessionStopRequested()
{
return mSessionStopRequested;
}
void OpenXRManagerImpl::enablePredictions()
{
mPredictionsEnabled = true;

@ -51,8 +51,10 @@ namespace MWVR
FrameInfo waitFrame();
void beginFrame();
void endFrame(FrameInfo frameInfo, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack);
bool xrSessionRunning() const { return mSessionRunning; }
void endFrame(FrameInfo frameInfo, const std::array<CompositionLayerProjectionView, 2>* layerStack);
bool appShouldSyncFrameLoop() const { return mAppShouldSyncFrameLoop; }
bool appShouldRender() const { return mAppShouldRender; }
bool appShouldReadInput() const { return mAppShouldReadInput; }
std::array<View, 2> getPredictedViews(int64_t predictedDisplayTime, ReferenceSpace space);
MWVR::Pose getPredictedHeadPose(int64_t predictedDisplayTime, ReferenceSpace space);
void handleEvents();
@ -65,8 +67,6 @@ namespace MWVR
XrSession xrSession() const { return mSession; };
XrInstance xrInstance() const { return mInstance; };
bool xrExtensionIsEnabled(const char* extensionName) const;
bool xrSessionStopRequested();
bool xrSessionCanRender();
void xrResourceAcquired();
void xrResourceReleased();
void xrUpdateNames();
@ -106,8 +106,12 @@ namespace MWVR
XrFrameState mFrameState{};
XrSessionState mSessionState = XR_SESSION_STATE_UNKNOWN;
XrDebugUtilsMessengerEXT mDebugMessenger{ nullptr };
bool mSessionStopRequested = false;
bool mSessionRunning = false;
bool mXrSessionShouldStop = false;
bool mAppShouldSyncFrameLoop = false;
bool mAppShouldRender = false;
bool mAppShouldReadInput = false;
uint32_t mAcquiredResources = 0;
std::mutex mFrameStateMutex{};
std::mutex mEventMutex{};

@ -111,12 +111,6 @@ namespace MWVR
}
}
bool VRSession::isRunning() const {
return true;
auto* xr = Environment::get().getManager();
return xr->xrSessionRunning();
}
void VRSession::swapBuffers(osg::GraphicsContext* gc, VRViewer& viewer)
{
auto* xr = Environment::get().getManager();
@ -127,22 +121,29 @@ namespace MWVR
auto leftView = viewer.getView("LeftEye");
auto rightView = viewer.getView("RightEye");
if (frameMeta->mShouldRender)
if (frameMeta->mShouldSyncFrameLoop)
{
viewer.blitEyesToMirrorTexture(gc);
gc->swapBuffersImplementation();
leftView->swapBuffers(gc);
rightView->swapBuffers(gc);
std::array<CompositionLayerProjectionView, 2> layerStack{};
layerStack[(int)Side::LEFT_SIDE].swapchain = &leftView->swapchain();
layerStack[(int)Side::RIGHT_SIDE].swapchain = &rightView->swapchain();
layerStack[(int)Side::LEFT_SIDE].pose = frameMeta->mPredictedPoses.eye[(int)Side::LEFT_SIDE] / mPlayerScale;
layerStack[(int)Side::RIGHT_SIDE].pose = frameMeta->mPredictedPoses.eye[(int)Side::RIGHT_SIDE] / mPlayerScale;
layerStack[(int)Side::LEFT_SIDE].fov = frameMeta->mPredictedPoses.view[(int)Side::LEFT_SIDE].fov;
layerStack[(int)Side::RIGHT_SIDE].fov = frameMeta->mPredictedPoses.view[(int)Side::RIGHT_SIDE].fov;
xr->endFrame(frameMeta->mFrameInfo, 1, layerStack);
if (frameMeta->mShouldRender)
{
viewer.blitEyesToMirrorTexture(gc);
gc->swapBuffersImplementation();
leftView->swapBuffers(gc);
rightView->swapBuffers(gc);
std::array<CompositionLayerProjectionView, 2> layerStack{};
layerStack[(int)Side::LEFT_SIDE].swapchain = &leftView->swapchain();
layerStack[(int)Side::RIGHT_SIDE].swapchain = &rightView->swapchain();
layerStack[(int)Side::LEFT_SIDE].pose = frameMeta->mPredictedPoses.eye[(int)Side::LEFT_SIDE] / mPlayerScale;
layerStack[(int)Side::RIGHT_SIDE].pose = frameMeta->mPredictedPoses.eye[(int)Side::RIGHT_SIDE] / mPlayerScale;
layerStack[(int)Side::LEFT_SIDE].fov = frameMeta->mPredictedPoses.view[(int)Side::LEFT_SIDE].fov;
layerStack[(int)Side::RIGHT_SIDE].fov = frameMeta->mPredictedPoses.view[(int)Side::RIGHT_SIDE].fov;
xr->endFrame(frameMeta->mFrameInfo, &layerStack);
}
else
{
gc->swapBuffersImplementation();
xr->endFrame(frameMeta->mFrameInfo, nullptr);
}
xr->xrResourceReleased();
}
@ -181,7 +182,7 @@ namespace MWVR
frame = std::move(getFrame(previousPhase));
}
if (phase == mXrSyncPhase && frame->mShouldRender)
if (phase == mXrSyncPhase && frame->mShouldSyncFrameLoop)
{
// We may reach this point before xrEndFrame of the previous frame
// Must wait or openxr will interpret another call to xrBeginFrame() as skipping a frame
@ -191,10 +192,7 @@ namespace MWVR
mCondition.wait(lock);
}
if (frame->mShouldRender)
{
Environment::get().getManager()->beginFrame();
}
Environment::get().getManager()->beginFrame();
}
}
@ -215,42 +213,48 @@ namespace MWVR
frame.reset(new VRFrameMeta);
frame->mFrameNo = mFrames;
frame->mShouldRender = xr->xrSessionCanRender();
if (frame->mShouldRender)
frame->mShouldSyncFrameLoop = xr->appShouldSyncFrameLoop();
frame->mShouldRender = xr->appShouldRender();
if (frame->mShouldSyncFrameLoop)
{
frame->mFrameInfo = xr->waitFrame();
xr->xrResourceAcquired();
}
frame->mPredictedDisplayTime = frame->mFrameInfo.runtimePredictedDisplayTime;
PoseSet predictedPoses{};
xr->enablePredictions();
predictedPoses.head = xr->getPredictedHeadPose(frame->mPredictedDisplayTime, ReferenceSpace::STAGE) * mPlayerScale;
auto hmdViews = xr->getPredictedViews(frame->mPredictedDisplayTime, ReferenceSpace::VIEW);
predictedPoses.view[(int)Side::LEFT_SIDE].pose = hmdViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
predictedPoses.view[(int)Side::RIGHT_SIDE].pose = hmdViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
predictedPoses.view[(int)Side::LEFT_SIDE].fov = hmdViews[(int)Side::LEFT_SIDE].fov;
predictedPoses.view[(int)Side::RIGHT_SIDE].fov = hmdViews[(int)Side::RIGHT_SIDE].fov;
auto stageViews = xr->getPredictedViews(frame->mPredictedDisplayTime, ReferenceSpace::STAGE);
predictedPoses.eye[(int)Side::LEFT_SIDE] = stageViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
predictedPoses.eye[(int)Side::RIGHT_SIDE] = stageViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
auto* input = Environment::get().getInputManager();
if (input)
{
predictedPoses.hands[(int)Side::LEFT_SIDE] = input->getLimbPose(frame->mPredictedDisplayTime, TrackedLimb::LEFT_HAND) * mPlayerScale;
predictedPoses.hands[(int)Side::RIGHT_SIDE] = input->getLimbPose(frame->mPredictedDisplayTime, TrackedLimb::RIGHT_HAND) * mPlayerScale;
}
xr->disablePredictions();
frame->mPredictedPoses = predictedPoses;
if (frame->mShouldRender)
{
frame->mPredictedDisplayTime = frame->mFrameInfo.runtimePredictedDisplayTime;
PoseSet predictedPoses{};
xr->enablePredictions();
predictedPoses.head = xr->getPredictedHeadPose(frame->mPredictedDisplayTime, ReferenceSpace::STAGE) * mPlayerScale;
auto hmdViews = xr->getPredictedViews(frame->mPredictedDisplayTime, ReferenceSpace::VIEW);
predictedPoses.view[(int)Side::LEFT_SIDE].pose = hmdViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
predictedPoses.view[(int)Side::RIGHT_SIDE].pose = hmdViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
predictedPoses.view[(int)Side::LEFT_SIDE].fov = hmdViews[(int)Side::LEFT_SIDE].fov;
predictedPoses.view[(int)Side::RIGHT_SIDE].fov = hmdViews[(int)Side::RIGHT_SIDE].fov;
auto stageViews = xr->getPredictedViews(frame->mPredictedDisplayTime, ReferenceSpace::STAGE);
predictedPoses.eye[(int)Side::LEFT_SIDE] = stageViews[(int)Side::LEFT_SIDE].pose * mPlayerScale;
predictedPoses.eye[(int)Side::RIGHT_SIDE] = stageViews[(int)Side::RIGHT_SIDE].pose * mPlayerScale;
auto* input = Environment::get().getInputManager();
if (input)
{
predictedPoses.hands[(int)Side::LEFT_SIDE] = input->getLimbPose(frame->mPredictedDisplayTime, TrackedLimb::LEFT_HAND) * mPlayerScale;
predictedPoses.hands[(int)Side::RIGHT_SIDE] = input->getLimbPose(frame->mPredictedDisplayTime, TrackedLimb::RIGHT_HAND) * mPlayerScale;
}
xr->disablePredictions();
frame->mPredictedPoses = predictedPoses;
}
}
}
const PoseSet& VRSession::predictedPoses(FramePhase phase)
{
auto& frame = getFrame(phase);
// TODO: Manage execution order properly instead of this hack
if (phase == FramePhase::Update && !frame)
beginPhase(FramePhase::Update);

@ -47,6 +47,7 @@ namespace MWVR
long long mPredictedDisplayTime{ 0 };
PoseSet mPredictedPoses{};
bool mShouldRender{ false };
bool mShouldSyncFrameLoop{ false };
FrameInfo mFrameInfo{};
};
@ -67,8 +68,6 @@ namespace MWVR
void beginPhase(FramePhase phase);
std::unique_ptr<VRFrameMeta>& getFrame(FramePhase phase);
bool isRunning() const;
float playerScale() const { return mPlayerScale; }
float setPlayerScale(float scale) { return mPlayerScale = scale; }

@ -955,7 +955,7 @@ XR_EXT_debug_utils message level info = true
XR_EXT_debug_utils message level warning = true
XR_EXT_debug_utils message level error = true
# Enable/disable openxr debug message types
XR_EXT_debug_utils message type general = false
XR_EXT_debug_utils message type general = true
XR_EXT_debug_utils message type validation = true
XR_EXT_debug_utils message type performance = true
XR_EXT_debug_utils message type conformance = true

Loading…
Cancel
Save