mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 00:23:51 +00:00
More accurate interpretation of openxr session states
This commit is contained in:
parent
cf20faff21
commit
6425749b7e
8 changed files with 187 additions and 151 deletions
|
@ -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, layerCount, layerStack);
|
||||
return impl().endFrame(frameInfo, layerStack);
|
||||
}
|
||||
|
||||
bool OpenXRManager::appShouldSyncFrameLoop() const
|
||||
{
|
||||
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,11 +474,17 @@ namespace MWVR
|
|||
}
|
||||
|
||||
void
|
||||
OpenXRManagerImpl::endFrame(FrameInfo frameInfo, int layerCount, const std::array<CompositionLayerProjectionView, 2>& layerStack)
|
||||
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 (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]);
|
||||
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);
|
||||
|
@ -493,8 +499,8 @@ namespace MWVR
|
|||
// 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();
|
||||
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)
|
||||
{
|
||||
|
@ -502,13 +508,7 @@ namespace MWVR
|
|||
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE].next = &compositionLayerDepth[(int)Side::RIGHT_SIDE];
|
||||
}
|
||||
}
|
||||
|
||||
XrFrameEndInfo frameEndInfo{ XR_TYPE_FRAME_END_INFO };
|
||||
frameEndInfo.displayTime = frameInfo.runtimePredictedDisplayTime;
|
||||
frameEndInfo.environmentBlendMode = mEnvironmentBlendMode;
|
||||
//if (frameInfo.runtimeRequestsRender)
|
||||
{
|
||||
frameEndInfo.layerCount = layerCount;
|
||||
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;
|
||||
mAppShouldSyncFrameLoop = false;
|
||||
mAppShouldRender = false;
|
||||
mAppShouldReadInput = false;
|
||||
mXrSessionShouldStop = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
case XR_SESSION_STATE_SYNCHRONIZED:
|
||||
{
|
||||
mSessionStopRequested = true;
|
||||
success = false;
|
||||
mAppShouldSyncFrameLoop = true;
|
||||
mAppShouldRender = false;
|
||||
mAppShouldReadInput = false;
|
||||
mXrSessionShouldStop = false;
|
||||
break;
|
||||
}
|
||||
case XR_SESSION_STATE_VISIBLE:
|
||||
{
|
||||
mAppShouldSyncFrameLoop = true;
|
||||
mAppShouldRender = true;
|
||||
mAppShouldReadInput = false;
|
||||
mXrSessionShouldStop = false;
|
||||
break;
|
||||
}
|
||||
case XR_SESSION_STATE_FOCUSED:
|
||||
{
|
||||
mAppShouldSyncFrameLoop = true;
|
||||
mAppShouldRender = true;
|
||||
mAppShouldReadInput = true;
|
||||
mXrSessionShouldStop = false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Log(Debug::Verbose) << "XrEventDataSessionStateChanged: Ignoring new state " << to_string(newState);
|
||||
Log(Debug::Warning) << "XrEventDataSessionStateChanged: Ignoring new state " << to_string(mSessionState);
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
mSessionState = newState;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(Debug::Verbose) << "XrEventDataSessionStateChanged: Conditions for state " << to_string(newState) << " not met, retrying next frame";
|
||||
}
|
||||
|
||||
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,13 +121,14 @@ namespace MWVR
|
|||
auto leftView = viewer.getView("LeftEye");
|
||||
auto rightView = viewer.getView("RightEye");
|
||||
|
||||
if (frameMeta->mShouldSyncFrameLoop)
|
||||
{
|
||||
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();
|
||||
|
@ -141,8 +136,14 @@ namespace MWVR
|
|||
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->endFrame(frameMeta->mFrameInfo, 1, layerStack);
|
||||
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,12 +192,9 @@ namespace MWVR
|
|||
mCondition.wait(lock);
|
||||
}
|
||||
|
||||
if (frame->mShouldRender)
|
||||
{
|
||||
Environment::get().getManager()->beginFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<VRSession::VRFrameMeta>& VRSession::getFrame(FramePhase phase)
|
||||
{
|
||||
|
@ -215,12 +213,15 @@ 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();
|
||||
}
|
||||
|
||||
if (frame->mShouldRender)
|
||||
{
|
||||
frame->mPredictedDisplayTime = frame->mFrameInfo.runtimePredictedDisplayTime;
|
||||
|
||||
PoseSet predictedPoses{};
|
||||
|
@ -246,11 +247,14 @@ namespace MWVR
|
|||
|
||||
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…
Reference in a new issue