diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dd61b7982..5f8b17f178 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -175,8 +175,6 @@ public: using namespace std; // Starfield information -static uint8_t THROTTLED_IDLE_TIMER_DELAY = 10; - const qint64 MAXIMUM_CACHE_SIZE = 10 * BYTES_PER_GIGABYTES; // 10GB static QTimer* locationUpdateTimer = NULL; @@ -737,6 +735,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _keyboardFocusHighlight->setVisible(false); } }); + + connect(this, &Application::applicationStateChanged, this, &Application::activeChanged); } void Application::aboutToQuit() { @@ -2108,8 +2108,11 @@ void Application::idle() { // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in // perpetuity and not expect events to get backed up. + bool isThrottled = getActiveDisplayPlugin()->isThrottled(); + static const int THROTTLED_IDLE_TIMER_DELAY = MSECS_PER_SECOND / 15; static const int IDLE_TIMER_DELAY_MS = 2; - int desiredInterval = getActiveDisplayPlugin()->isThrottled() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS; + int desiredInterval = isThrottled ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS; + //qDebug() << "isThrottled:" << isThrottled << "desiredInterval:" << desiredInterval; if (idleTimer->interval() != desiredInterval) { idleTimer->start(desiredInterval); @@ -4612,6 +4615,24 @@ void Application::checkSkeleton() { } } +bool Application::isForeground() { + return _isForeground && !getWindow()->isMinimized(); +} + +void Application::activeChanged(Qt::ApplicationState state) { + switch (state) { + case Qt::ApplicationActive: + _isForeground = true; + break; + + case Qt::ApplicationSuspended: + case Qt::ApplicationHidden: + case Qt::ApplicationInactive: + default: + _isForeground = false; + break; + } +} void Application::showFriendsWindow() { const QString FRIENDS_WINDOW_TITLE = "Add/Remove Friends"; const QString FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends"; @@ -4725,6 +4746,7 @@ static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool acti } static QVector> _currentDisplayPluginActions; +static bool _activatingDisplayPlugin{false}; void Application::updateDisplayMode() { auto menu = Menu::getInstance(); @@ -4771,7 +4793,9 @@ void Application::updateDisplayMode() { if (newDisplayPlugin) { _offscreenContext->makeCurrent(); + _activatingDisplayPlugin = true; newDisplayPlugin->activate(); + _activatingDisplayPlugin = false; _offscreenContext->makeCurrent(); offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); _offscreenContext->makeCurrent(); @@ -4888,14 +4912,17 @@ void Application::removeMenu(const QString& menuName) { void Application::addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { auto menu = Menu::getInstance(); MenuWrapper* parentItem = menu->getMenu(path); - QAction* action = parentItem->addAction(name); + QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); connect(action, &QAction::triggered, [=] { onClicked(action->isChecked()); }); action->setCheckable(checkable); action->setChecked(checked); - _currentDisplayPluginActions.push_back({ path, name }); - _currentInputPluginActions.push_back({ path, name }); + if (_activatingDisplayPlugin) { + _currentDisplayPluginActions.push_back({ path, name }); + } else { + _currentInputPluginActions.push_back({ path, name }); + } } void Application::removeMenuItem(const QString& menuName, const QString& menuItem) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 4819bd08a4..a1765109ce 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -291,6 +291,7 @@ public: virtual void unsetFullscreen(const QScreen* avoid) override; virtual void showDisplayPluginsTools() override; virtual QGLWidget* getPrimarySurface() override; + virtual bool isForeground() override; void setActiveDisplayPlugin(const QString& pluginName); @@ -476,6 +477,7 @@ private slots: void faceTrackerMuteToggled(); void setCursorVisible(bool visible); + void activeChanged(Qt::ApplicationState state); private: void resetCameras(Camera& camera, const glm::uvec2& size); @@ -688,6 +690,7 @@ private: SimpleMovingAverage _simsPerSecond{10}; int _simsPerSecondReport = 0; quint64 _lastSimsPerSecondUpdate = 0; + bool _isForeground = true; // starts out assumed to be in foreground }; #endif // hifi_Application_h diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 0d0d335b67..bfa2dacf3a 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -18,8 +18,6 @@ #include "MainWindow.h" -const int MSECS_PER_FRAME_WHEN_THROTTLED = 66; - static QGLFormat& getDesiredGLFormat() { // Specify an OpenGL 3.3 format using the Core profile. // That is, no old-school fixed pipeline functionality @@ -35,10 +33,7 @@ static QGLFormat& getDesiredGLFormat() { return glFormat; } -GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()), - _throttleRendering(false), - _idleRenderInterval(MSECS_PER_FRAME_WHEN_THROTTLED) -{ +GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()) { #ifdef Q_OS_LINUX // Cause GLCanvas::eventFilter to be called. // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux. @@ -46,15 +41,6 @@ GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()), #endif } -void GLCanvas::stopFrameTimer() { - _frameTimer.stop(); -} - -bool GLCanvas::isThrottleRendering() const { - return (_throttleRendering - || (Application::getInstance()->getWindow()->isMinimized() && Application::getInstance()->isThrottleFPSEnabled())); -} - int GLCanvas::getDeviceWidth() const { return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); } @@ -66,17 +52,17 @@ int GLCanvas::getDeviceHeight() const { void GLCanvas::initializeGL() { setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); - connect(Application::getInstance(), SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(activeChanged(Qt::ApplicationState))); - connect(&_frameTimer, SIGNAL(timeout()), this, SLOT(throttleRender())); - // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. setAutoBufferSwap(false); } void GLCanvas::paintGL() { PROFILE_RANGE(__FUNCTION__); - if (!_throttleRendering && - (!Application::getInstance()->getWindow()->isMinimized() || !Application::getInstance()->isThrottleFPSEnabled())) { + + // FIXME - I'm not sure why this still remains, it appears as if this GLCanvas gets a single paintGL call near + // the beginning of the application starting up. I'm not sure if we really need to call Application::paintGL() + // in this case, since the display plugins eventually handle all the painting + if ((!Application::getInstance()->getWindow()->isMinimized() || !Application::getInstance()->isThrottleFPSEnabled())) { Application::getInstance()->paintGL(); } } @@ -85,39 +71,6 @@ void GLCanvas::resizeGL(int width, int height) { Application::getInstance()->resizeGL(); } -void GLCanvas::activeChanged(Qt::ApplicationState state) { - switch (state) { - case Qt::ApplicationActive: - // If we're active, stop the frame timer and the throttle. - _frameTimer.stop(); - _throttleRendering = false; - break; - - case Qt::ApplicationSuspended: - case Qt::ApplicationHidden: - // If we're hidden or are about to suspend, don't render anything. - _throttleRendering = false; - _frameTimer.stop(); - break; - - default: - // Otherwise, throttle. - if (!_throttleRendering && !Application::getInstance()->isAboutToQuit() - && Application::getInstance()->isThrottleFPSEnabled()) { - _frameTimer.start(_idleRenderInterval); - _throttleRendering = true; - } - break; - } -} - -void GLCanvas::throttleRender() { - _frameTimer.start(_idleRenderInterval); - if (!Application::getInstance()->getWindow()->isMinimized()) { - Application::getInstance()->paintGL(); - } -} - int updateTime = 0; bool GLCanvas::event(QEvent* event) { switch (event->type()) { diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index bcaa9577d1..73c5b5e8bf 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -23,28 +23,18 @@ class GLCanvas : public QGLWidget { public: GLCanvas(); - void stopFrameTimer(); - - bool isThrottleRendering() const; - int getDeviceWidth() const; int getDeviceHeight() const; QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } protected: - QTimer _frameTimer; - bool _throttleRendering; - int _idleRenderInterval; - virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int width, int height); virtual bool event(QEvent* event); private slots: - void activeChanged(Qt::ApplicationState state); - void throttleRender(); bool eventFilter(QObject*, QEvent* event); }; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b0a78fdd83..ca46b80f92 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -283,7 +283,7 @@ namespace MenuOption { const QString TestPing = "Test Ping"; const QString ThirdPerson = "Third Person"; const QString ThreePointCalibration = "3 Point Calibration"; - const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; + const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index ce6467cd55..e478223281 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -34,3 +34,24 @@ void Basic2DWindowOpenGLDisplayPlugin::deactivate() { // container->removeMenu(MENU_PATH); MainWindowOpenGLDisplayPlugin::deactivate(); } + +int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval(bool isThrottled) const { + static const int THROTTLED_PAINT_TIMER_DELAY = MSECS_PER_SECOND / 15; + static const int PAINT_TIMER_DELAY_MS = 1; + + return isThrottled ? THROTTLED_PAINT_TIMER_DELAY : PAINT_TIMER_DELAY_MS; +} + +bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const { + static const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Menu.h + + bool shouldThrottle = (!CONTAINER->isForeground() && CONTAINER->isOptionChecked(ThrottleFPSIfNotFocus)); + + if (_isThrottled != shouldThrottle) { + int desiredInterval = getDesiredInterval(shouldThrottle); + _timer.start(desiredInterval); + _isThrottled = shouldThrottle; + } + + return shouldThrottle; +} \ No newline at end of file diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index d19326f007..612d15377a 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -18,6 +18,12 @@ public: virtual const QString & getName() const override; + virtual bool isThrottled() const override; + +protected: + int getDesiredInterval(bool isThrottled) const; + mutable bool _isThrottled = false; + private: static const QString NAME; }; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 9986610a50..9b6b92d8d4 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -37,8 +37,8 @@ protected: virtual void doneCurrent() = 0; virtual void swapBuffers() = 0; - QTimer _timer; - ProgramPtr _program; + mutable QTimer _timer; + ProgramPtr _program; ShapeWrapperPtr _plane; }; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 85c5c814de..7f6346a181 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -26,4 +26,5 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0; virtual void showDisplayPluginsTools() = 0; virtual QGLWidget* getPrimarySurface() = 0; + virtual bool isForeground() = 0; };