Fix switching to desktop from OpenXR

This commit is contained in:
Ada 2025-06-17 22:51:42 +10:00
parent 1238aa1297
commit d654b1355a
4 changed files with 43 additions and 17 deletions

View file

@ -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<XrEventDataInstanceLossPending*>(&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;
}

View file

@ -61,8 +61,10 @@ public:
controller::Pose _lastHeadPose;
std::optional<XrTime> _lastPredictedDisplayTime;
bool _isValid = true; // set to false when the context is lost
bool _shouldQuit = false;
bool _shouldRunFrameCycle = false;
bool _isDisplayActive = false;
bool _isSupported = false;

View file

@ -33,7 +33,7 @@ OpenXrDisplayPlugin::OpenXrDisplayPlugin(std::shared_ptr<OpenXrContext> 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;

View file

@ -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<controller::UserInputMapper>();
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) {