From d654b1355a9f5a8488d7b4707cf669e2a5c3657e Mon Sep 17 00:00:00 2001 From: Ada Date: Tue, 17 Jun 2025 22:51:42 +1000 Subject: [PATCH] Fix switching to desktop from OpenXR --- plugins/openxr/src/OpenXrContext.cpp | 4 +++ plugins/openxr/src/OpenXrContext.h | 2 ++ plugins/openxr/src/OpenXrDisplayPlugin.cpp | 35 ++++++++++++---------- plugins/openxr/src/OpenXrInputPlugin.cpp | 19 ++++++++++-- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/plugins/openxr/src/OpenXrContext.cpp b/plugins/openxr/src/OpenXrContext.cpp index 264c4c5251..0850b0c014 100644 --- a/plugins/openxr/src/OpenXrContext.cpp +++ b/plugins/openxr/src/OpenXrContext.cpp @@ -390,6 +390,7 @@ bool OpenXrContext::updateSessionState(XrSessionState newState) { _isSessionRunning = true; } _shouldRunFrameCycle = true; + _isValid = true; break; } @@ -414,6 +415,7 @@ bool OpenXrContext::updateSessionState(XrSessionState newState) { _shouldQuit = true; _shouldRunFrameCycle = false; _session = XR_NULL_HANDLE; + _isValid = false; qCDebug(xr_context_cat, "Destroyed session"); break; } @@ -433,6 +435,7 @@ bool OpenXrContext::pollEvents() { const auto& instanceLossPending = *reinterpret_cast(&event); qCCritical(xr_context_cat, "Instance loss pending at %lu! Destroying instance.", instanceLossPending.lossTime); _shouldQuit = true; + _isValid = false; continue; } case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: { @@ -480,6 +483,7 @@ bool OpenXrContext::pollEvents() { if (result != XR_EVENT_UNAVAILABLE) { qCCritical(xr_context_cat, "Failed to poll events!"); + _isValid = false; return false; } diff --git a/plugins/openxr/src/OpenXrContext.h b/plugins/openxr/src/OpenXrContext.h index 9a3702612c..9f93a26ed8 100644 --- a/plugins/openxr/src/OpenXrContext.h +++ b/plugins/openxr/src/OpenXrContext.h @@ -61,8 +61,10 @@ public: controller::Pose _lastHeadPose; std::optional _lastPredictedDisplayTime; + bool _isValid = true; // set to false when the context is lost bool _shouldQuit = false; bool _shouldRunFrameCycle = false; + bool _isDisplayActive = false; bool _isSupported = false; diff --git a/plugins/openxr/src/OpenXrDisplayPlugin.cpp b/plugins/openxr/src/OpenXrDisplayPlugin.cpp index ba4d514399..5ea22d1c52 100644 --- a/plugins/openxr/src/OpenXrDisplayPlugin.cpp +++ b/plugins/openxr/src/OpenXrDisplayPlugin.cpp @@ -33,7 +33,7 @@ OpenXrDisplayPlugin::OpenXrDisplayPlugin(std::shared_ptr c) { } bool OpenXrDisplayPlugin::isSupported() const { - return _context->_isSupported; + return _context->_isValid && _context->_isSupported; } // Slightly differs from glm::ortho @@ -263,25 +263,15 @@ const QString OpenXrDisplayPlugin::getName() const { } bool OpenXrDisplayPlugin::internalActivate() { + if (!_context->_isValid) { return false; } + _context->reset(); + _context->_isDisplayActive = true; return HmdDisplayPlugin::internalActivate(); } void OpenXrDisplayPlugin::internalDeactivate() { - // We can get into a state where activate -> deactivate -> activate is called in a chain. - // We are probably gonna have a bad time then. At least check if the session is already running. - // This happens when the application decides to switch display plugins back and forth. This should - // probably be fixed there. - if (_context->_isSessionRunning) { - if (!_context->requestExitSession()) { - qCCritical(xr_display_cat, "Failed to request exit session"); - } else { - // Poll events until runtime wants to quit - while (!_context->_shouldQuit) { - _context->pollEvents(); - } - } - } + _context->_isDisplayActive = false; HmdDisplayPlugin::internalDeactivate(); } @@ -326,6 +316,11 @@ void OpenXrDisplayPlugin::resetSensors() { } bool OpenXrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { + if (!_context->_isValid) { + deactivate(); + return false; + } + _context->pollEvents(); if (_context->_shouldQuit) { @@ -366,6 +361,11 @@ void OpenXrDisplayPlugin::compositeLayers() { } void OpenXrDisplayPlugin::hmdPresent() { + if (!_context->_isValid) { + deactivate(); + return; + } + if (!_context->_shouldRunFrameCycle) { qCWarning(xr_display_cat, "hmdPresent: Shouldn't run frame cycle. Skipping renderin frame %d", _currentFrame->frameIndex); @@ -464,6 +464,11 @@ bool OpenXrDisplayPlugin::isHmdMounted() const { } void OpenXrDisplayPlugin::updatePresentPose() { + if (!_context->_isValid) { + deactivate(); + return; + } + if (_lastFrameState.predictedDisplayTime == 0) { return; } _context->_lastPredictedDisplayTime = _lastFrameState.predictedDisplayTime; diff --git a/plugins/openxr/src/OpenXrInputPlugin.cpp b/plugins/openxr/src/OpenXrInputPlugin.cpp index 47dfd9bcd3..3571f22251 100644 --- a/plugins/openxr/src/OpenXrInputPlugin.cpp +++ b/plugins/openxr/src/OpenXrInputPlugin.cpp @@ -37,7 +37,7 @@ bool OpenXrInputPlugin::uncalibrate() { } bool OpenXrInputPlugin::isSupported() const { - return _context->_isSupported; + return _context->_isValid && _context->_isSupported; } // TODO: Config options @@ -54,6 +54,8 @@ QString OpenXrInputPlugin::configurationLayout() { } bool OpenXrInputPlugin::activate() { + if (!_context->_isValid) { return false; } + InputPlugin::activate(); loadSettings(); @@ -80,12 +82,25 @@ void OpenXrInputPlugin::deactivate() { } void OpenXrInputPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { - if (_context->_shouldQuit) { + if (_context->_shouldQuit || !_context->_isValid) { deactivate(); return; } auto userInputMapper = DependencyManager::get(); + + if (_registeredWithInputMapper && !_context->_isDisplayActive) { + userInputMapper->removeDevice(_inputDevice->_deviceID); + _registeredWithInputMapper = false; + _inputDevice->_poseStateMap.clear(); + return; + } else if (!_registeredWithInputMapper && _context->_isDisplayActive) { + userInputMapper->registerDevice(_inputDevice); + _registeredWithInputMapper = true; + } + + if (!_registeredWithInputMapper) { return; } + userInputMapper->withLock([&, this]() { _inputDevice->update(deltaTime, inputCalibrationData); }); if (_inputDevice->_trackedControllers == 0 && _registeredWithInputMapper) {