diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2c4cd4aa0a..9b45b5bb5b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -247,6 +247,8 @@ static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStanda Setting::Handle maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS); static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com"; +static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds +static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop"; const QHash Application::_acceptedExtensions { { SVO_EXTENSION, &Application::importSVOFromURL }, @@ -1413,6 +1415,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo properties["active_display_plugin"] = getActiveDisplayPlugin()->getName(); properties["using_hmd"] = isHMDMode(); + _autoSwitchDisplayModeSupportedHMDPlugin = nullptr; + foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { + if (displayPlugin->isHmd() && + displayPlugin->getSupportsAutoSwitch()) { + _autoSwitchDisplayModeSupportedHMDPlugin = displayPlugin; + _autoSwitchDisplayModeSupportedHMDPluginName = + _autoSwitchDisplayModeSupportedHMDPlugin->getName(); + _previousHMDWornStatus = + _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible(); + break; + } + } + + if (_autoSwitchDisplayModeSupportedHMDPlugin) { + if (getActiveDisplayPlugin() != _autoSwitchDisplayModeSupportedHMDPlugin && + !_autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { + startHMDStandBySession(); + } + // Poll periodically to check whether the user has worn HMD or not. Switch Display mode accordingly. + // If the user wears HMD then switch to VR mode. If the user removes HMD then switch to Desktop mode. + QTimer* autoSwitchDisplayModeTimer = new QTimer(this); + connect(autoSwitchDisplayModeTimer, SIGNAL(timeout()), this, SLOT(switchDisplayMode())); + autoSwitchDisplayModeTimer->start(INTERVAL_TO_CHECK_HMD_WORN_STATUS); + } + auto glInfo = getGLContextData(); properties["gl_info"] = glInfo; properties["gpu_used_memory"] = (int)BYTES_TO_MB(gpu::Context::getUsedGPUMemSize()); @@ -1646,7 +1673,10 @@ void Application::aboutToQuit() { } getActiveDisplayPlugin()->deactivate(); - + if (_autoSwitchDisplayModeSupportedHMDPlugin + && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { + _autoSwitchDisplayModeSupportedHMDPlugin->endSession(); + } // use the CloseEventSender via a QThread to send an event that says the user asked for the app to close auto closeEventSender = DependencyManager::get(); QThread* closureEventThread = new QThread(this); @@ -6855,6 +6885,35 @@ void Application::updateDisplayMode() { Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); } +void Application::switchDisplayMode() { + if (!_autoSwitchDisplayModeSupportedHMDPlugin) { + return; + } + bool currentHMDWornStatus = _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible(); + if (currentHMDWornStatus != _previousHMDWornStatus) { + // Switch to respective mode as soon as currentHMDWornStatus changes + if (currentHMDWornStatus) { + qCDebug(interfaceapp) << "Switching from Desktop to HMD mode"; + endHMDSession(); + setActiveDisplayPlugin(_autoSwitchDisplayModeSupportedHMDPluginName); + } else { + qCDebug(interfaceapp) << "Switching from HMD to desktop mode"; + setActiveDisplayPlugin(DESKTOP_DISPLAY_PLUGIN_NAME); + startHMDStandBySession(); + } + emit activeDisplayPluginChanged(); + } + _previousHMDWornStatus = currentHMDWornStatus; +} + +void Application::startHMDStandBySession() { + _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession(); +} + +void Application::endHMDSession() { + _autoSwitchDisplayModeSupportedHMDPlugin->endSession(); +} + mat4 Application::getEyeProjection(int eye) const { QMutexLocker viewLocker(&_viewMutex); if (isHMDMode()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 9cf03f1cef..46e5e882a4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -442,7 +442,7 @@ private slots: void addAssetToWorldErrorTimeout(); void handleSandboxStatus(QNetworkReply* reply); - + void switchDisplayMode(); private: static void initDisplay(); void init(); @@ -680,7 +680,11 @@ private: FileScriptingInterface* _fileDownload; AudioInjector* _snapshotSoundInjector { nullptr }; SharedSoundPointer _snapshotSound; + + DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin; + QString _autoSwitchDisplayModeSupportedHMDPluginName; + bool _previousHMDWornStatus; + void startHMDStandBySession(); + void endHMDSession(); }; - - #endif // hifi_Application_h diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index f6f7da0ecd..bfd158ffb5 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -339,6 +339,18 @@ void OpenGLDisplayPlugin::deactivate() { Parent::deactivate(); } +bool OpenGLDisplayPlugin::startStandBySession() { + if (!activateStandBySession()) { + return false; + } + return Parent::startStandBySession(); +} + +void OpenGLDisplayPlugin::endSession() { + deactivateSession(); + Parent::endSession(); +} + void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index e1eea5de6c..10a7558398 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -42,6 +42,8 @@ public: // between the main thread and the presentation thread bool activate() override final; void deactivate() override final; + bool startStandBySession() override final; + void endSession() override final; bool eventFilter(QObject* receiver, QEvent* event) override; bool isDisplayVisible() const override { return true; } @@ -99,6 +101,10 @@ protected: // Returns true on successful activation virtual bool internalActivate() { return true; } virtual void internalDeactivate() {} + + // Returns true on successful activation of standby session + virtual bool activateStandBySession() { return true; } + virtual void deactivateSession() {} // Plugin specific functionality to send the composed scene to the output window or device virtual void internalPresent(); diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 754c919fd4..297bdb2cca 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -200,6 +200,7 @@ public: virtual float newFramePresentRate() const { return -1.0f; } // Rate at which rendered frames are being skipped virtual float droppedFrameRate() const { return -1.0f; } + virtual bool getSupportsAutoSwitch() { return false; } // Hardware specific stats virtual QJsonObject getHardwareStats() const { return QJsonObject(); } diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h index 15588fafa4..2d4a24a1fe 100644 --- a/libraries/plugins/src/plugins/Plugin.h +++ b/libraries/plugins/src/plugins/Plugin.h @@ -53,6 +53,18 @@ public: virtual bool isActive() { return _active; } + virtual bool startStandBySession() { + _sessionStatus = true; + return _sessionStatus; + } + + virtual void endSession() { + _sessionStatus = false; + } + + virtual bool isSessionActive() { + return _sessionStatus; + } /** * Called by the application during it's idle phase. If the plugin needs to do @@ -73,6 +85,7 @@ signals: protected: bool _active { false }; + bool _sessionStatus { false }; PluginContainer* _container { nullptr }; static const char* UNKNOWN_PLUGIN_ID; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 26906ef2fb..93f4787f0f 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -123,10 +123,19 @@ bool OculusBaseDisplayPlugin::internalActivate() { void OculusBaseDisplayPlugin::internalDeactivate() { Parent::internalDeactivate(); +} + +bool OculusBaseDisplayPlugin::activateStandBySession() { + _session = acquireOculusSession(); + if (!_session) { + return false; + } + return true; +} +void OculusBaseDisplayPlugin::deactivateSession() { releaseOculusSession(); _session = nullptr; } - void OculusBaseDisplayPlugin::updatePresentPose() { //mat4 sensorResetMat; //_currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index e5dc75095d..5230b11681 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -26,6 +26,7 @@ public: void resetSensors() override final; bool beginFrameRender(uint32_t frameIndex) override; float getTargetFrameRate() const override { return _hmdDesc.DisplayRefreshRate; } + bool getSupportsAutoSwitch() override final { return true; } protected: @@ -33,6 +34,8 @@ protected: void uncustomizeContext() override; bool internalActivate() override; void internalDeactivate() override; + bool activateStandBySession() override; + void deactivateSession() override; void updatePresentPose() override; protected: