mirror of
https://github.com/lubosz/overte.git
synced 2025-04-06 16:42:12 +02:00
Refresh Rate Controller
This commit is contained in:
parent
1b67042091
commit
0bdc37859d
14 changed files with 458 additions and 2 deletions
|
@ -77,6 +77,12 @@ Item {
|
|||
visible: root.expanded
|
||||
text: " Present New Rate: " + root.presentnewrate.toFixed(2);
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: " RefreshRateController:\n " +
|
||||
"refreshRateTarget:\t " + root.refreshRateTarget + "\n " +
|
||||
"refreshRateMode:\t " + root.refreshRateMode ;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: " Present Drop Rate: " + root.presentdroprate.toFixed(2);
|
||||
|
|
|
@ -150,6 +150,7 @@
|
|||
#include <Preferences.h>
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <display-plugins/hmd/HmdDisplayPlugin.h>
|
||||
#include <display-plugins/RefreshRateController.h>
|
||||
#include <trackers/EyeTracker.h>
|
||||
#include <avatars-renderer/ScriptAvatar.h>
|
||||
#include <RenderableEntityItem.h>
|
||||
|
@ -192,6 +193,7 @@
|
|||
#include "scripting/WalletScriptingInterface.h"
|
||||
#include "scripting/TTSScriptingInterface.h"
|
||||
#include "scripting/KeyboardScriptingInterface.h"
|
||||
#include "scripting/RefreshRateScriptingInterface.h"
|
||||
|
||||
|
||||
|
||||
|
@ -820,7 +822,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
audioDLLPath += "/audioWin7";
|
||||
}
|
||||
QCoreApplication::addLibraryPath(audioDLLPath);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
||||
|
@ -1813,6 +1815,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
});
|
||||
|
||||
|
||||
getRefreshRateManager().setRefreshRateRegime(RefreshRateManager::RefreshRateRegime::STARTUP);
|
||||
|
||||
// Setup the _keyboardMouseDevice, _touchscreenDevice, _touchscreenVirtualPadDevice and the user input mapper with the default bindings
|
||||
userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice());
|
||||
// if the _touchscreenDevice is not supported it will not be registered
|
||||
|
@ -2613,6 +2617,8 @@ void Application::onAboutToQuit() {
|
|||
_aboutToQuit = true;
|
||||
|
||||
cleanupBeforeQuit();
|
||||
|
||||
getRefreshRateManager().setRefreshRateRegime(RefreshRateManager::RefreshRateRegime::SHUTDOWN);
|
||||
}
|
||||
|
||||
void Application::cleanupBeforeQuit() {
|
||||
|
@ -3222,6 +3228,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
|
||||
surfaceContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("RefreshRate", new RefreshRateScriptingInterface());
|
||||
_fileDownload = new FileScriptingInterface(engine);
|
||||
surfaceContext->setContextProperty("File", _fileDownload);
|
||||
connect(_fileDownload, &FileScriptingInterface::unzipResult, this, &Application::handleUnzip);
|
||||
|
@ -3370,6 +3377,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona
|
|||
|
||||
surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||
surfaceContext->setContextProperty("RefreshRate", new RefreshRateScriptingInterface());
|
||||
|
||||
surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
surfaceContext->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
|
||||
|
@ -4041,6 +4049,9 @@ bool Application::event(QEvent* event) {
|
|||
case QEvent::KeyRelease:
|
||||
keyReleaseEvent(static_cast<QKeyEvent*>(event));
|
||||
return true;
|
||||
case QEvent::FocusIn:
|
||||
focusInEvent(static_cast<QFocusEvent*>(event));
|
||||
return true;
|
||||
case QEvent::FocusOut:
|
||||
focusOutEvent(static_cast<QFocusEvent*>(event));
|
||||
return true;
|
||||
|
@ -4102,6 +4113,12 @@ bool Application::eventFilter(QObject* object, QEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
if (getWindow()->windowState() == Qt::WindowMinimized) {
|
||||
getRefreshRateManager().setRefreshRateRegime(RefreshRateManager::RefreshRateRegime::MINIMIZED);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4388,6 +4405,13 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
|||
|
||||
}
|
||||
|
||||
void Application::focusInEvent(QFocusEvent* event) {
|
||||
if (!_aboutToQuit && _startUpFinished) {
|
||||
getRefreshRateManager().setRefreshRateRegime(RefreshRateManager::RefreshRateRegime::RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Application::focusOutEvent(QFocusEvent* event) {
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
|
@ -4396,6 +4420,9 @@ void Application::focusOutEvent(QFocusEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!_aboutToQuit && _startUpFinished) {
|
||||
getRefreshRateManager().setRefreshRateRegime(RefreshRateManager::RefreshRateRegime::UNFOCUS);
|
||||
}
|
||||
// FIXME spacemouse code still needs cleanup
|
||||
#if 0
|
||||
//SpacemouseDevice::getInstance().focusOutEvent();
|
||||
|
@ -5563,6 +5590,8 @@ void Application::resumeAfterLoginDialogActionTaken() {
|
|||
menu->getMenu("Developer")->setVisible(_developerMenuVisible);
|
||||
_myCamera.setMode(_previousCameraMode);
|
||||
cameraModeChanged();
|
||||
_startUpFinished = true;
|
||||
getRefreshRateManager().setRefreshRateRegime(RefreshRateManager::RefreshRateRegime::RUNNING);
|
||||
}
|
||||
|
||||
void Application::loadAvatarScripts(const QVector<QString>& urls) {
|
||||
|
@ -7345,6 +7374,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGlobalObject("LODManager", DependencyManager::get<LODManager>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Keyboard", DependencyManager::get<KeyboardScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("RefreshRate", new RefreshRateScriptingInterface);
|
||||
|
||||
scriptEngine->registerGlobalObject("Paths", DependencyManager::get<PathUtils>().data());
|
||||
|
||||
|
@ -8758,6 +8788,7 @@ void Application::updateDisplayMode() {
|
|||
auto displayPlugins = getDisplayPlugins();
|
||||
|
||||
// Default to the first item on the list, in case none of the menu items match
|
||||
|
||||
DisplayPluginPointer newDisplayPlugin = displayPlugins.at(0);
|
||||
auto menu = getPrimaryMenu();
|
||||
if (menu) {
|
||||
|
@ -8847,6 +8878,14 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) {
|
|||
if (desktop) {
|
||||
desktop->setProperty("repositionLocked", wasRepositionLocked);
|
||||
}
|
||||
|
||||
RefreshRateManager& refreshRateManager = getRefreshRateManager();
|
||||
refreshRateManager.setRefreshRateOperator(OpenGLDisplayPlugin::getRefreshRateOperator());
|
||||
bool isHmd = newDisplayPlugin->isHmd();
|
||||
RefreshRateManager::UXMode uxMode = isHmd ? RefreshRateManager::UXMode::HMD :
|
||||
RefreshRateManager::UXMode::DESKTOP;
|
||||
|
||||
refreshRateManager.setUXMode(uxMode);
|
||||
}
|
||||
|
||||
bool isHmd = _displayPlugin->isHmd();
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "gpu/Context.h"
|
||||
#include "LoginStateManager.h"
|
||||
#include "Menu.h"
|
||||
#include "RefreshRateManager.h"
|
||||
#include "octree/OctreePacketProcessor.h"
|
||||
#include "render/Engine.h"
|
||||
#include "scripting/ControllerScriptingInterface.h"
|
||||
|
@ -203,6 +204,7 @@ public:
|
|||
CompositorHelper& getApplicationCompositor() const;
|
||||
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
RefreshRateManager& getRefreshRateManager() { return _refreshRateManager; }
|
||||
|
||||
size_t getRenderFrameCount() const { return _graphicsEngine.getRenderFrameCount(); }
|
||||
float getRenderLoopRate() const { return _graphicsEngine.getRenderLoopRate(); }
|
||||
|
@ -721,6 +723,7 @@ private:
|
|||
QUuid _loginDialogID;
|
||||
QUuid _avatarInputsBarID;
|
||||
LoginStateManager _loginStateManager;
|
||||
RefreshRateManager _refreshRateManager;
|
||||
|
||||
quint64 _lastFaceTrackerUpdate;
|
||||
|
||||
|
@ -818,5 +821,6 @@ private:
|
|||
|
||||
bool _resumeAfterLoginDialogActionTaken_WasPostponed { false };
|
||||
bool _resumeAfterLoginDialogActionTaken_SafeToRun { false };
|
||||
bool _startUpFinished { false };
|
||||
};
|
||||
#endif // hifi_Application_h
|
||||
|
|
138
interface/src/RefreshRateManager.cpp
Normal file
138
interface/src/RefreshRateManager.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// RefreshRateManager.cpp
|
||||
// interface/src/
|
||||
//
|
||||
// Created by Dante Ruiz on 2019-04-15.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "RefreshRateManager.h"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
#include <display-plugins/hmd/HmdDisplayPlugin.h>
|
||||
|
||||
static const int HMD_TARGET_RATE = 90;
|
||||
|
||||
static const std::array<std::string, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> REFRESH_RATE_PROFILE_TO_STRING =
|
||||
{ { "Eco", "Interactive", "Realtime" } };
|
||||
|
||||
static const std::array<std::string, RefreshRateManager::RefreshRateRegime::REGIME_NUM> REFRESH_RATE_REGIME_TO_STRING =
|
||||
{ { "Running", "Unfocus", "Minimized", "StartUp", "ShutDown" } };
|
||||
|
||||
static const std::array<std::string, RefreshRateManager::UXMode::UX_NUM> UX_MODE_TO_STRING =
|
||||
{ { "Desktop", "HMD" } };
|
||||
|
||||
static const std::map<std::string, RefreshRateManager::RefreshRateProfile> REFRESH_RATE_PROFILE_FROM_STRING =
|
||||
{ { "Eco", RefreshRateManager::RefreshRateProfile::ECO },
|
||||
{ "Interactive", RefreshRateManager::RefreshRateProfile::INTERACTIVE },
|
||||
{ "Realtime", RefreshRateManager::RefreshRateProfile::REALTIME } };
|
||||
|
||||
static const std::array<int, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> RUNNING_REGIME_PROFILES =
|
||||
{ { 5, 20, 60 } };
|
||||
|
||||
static const std::array<int, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> UNFOCUS_REGIME_PROFILES =
|
||||
{ { 5, 5, 10 } };
|
||||
|
||||
static const std::array<int, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> MINIMIZED_REGIME_PROFILE =
|
||||
{ { 2, 2, 2 } };
|
||||
|
||||
static const std::array<int, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> START_AND_SHUTDOWN_REGIME_PROFILES =
|
||||
{ { 30, 30, 30 } };
|
||||
|
||||
static const std::array<std::array<int, RefreshRateManager::RefreshRateProfile::PROFILE_NUM>, RefreshRateManager::RefreshRateRegime::REGIME_NUM> REFRESH_RATE_REGIMES =
|
||||
{ { RUNNING_REGIME_PROFILES, UNFOCUS_REGIME_PROFILES, MINIMIZED_REGIME_PROFILE,
|
||||
START_AND_SHUTDOWN_REGIME_PROFILES, START_AND_SHUTDOWN_REGIME_PROFILES } };
|
||||
|
||||
|
||||
std::string RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile refreshRateProfile) {
|
||||
return REFRESH_RATE_PROFILE_TO_STRING.at(refreshRateProfile);
|
||||
}
|
||||
|
||||
RefreshRateManager::RefreshRateProfile RefreshRateManager::refreshRateProfileFromString(std::string refreshRateProfile) {
|
||||
return REFRESH_RATE_PROFILE_FROM_STRING.at(refreshRateProfile);
|
||||
}
|
||||
|
||||
std::string RefreshRateManager::refreshRateRegimeToString(RefreshRateManager::RefreshRateRegime refreshRateRegime) {
|
||||
return REFRESH_RATE_REGIME_TO_STRING.at(refreshRateRegime);
|
||||
}
|
||||
|
||||
std::string RefreshRateManager::uxModeToString(RefreshRateManager::RefreshRateManager::UXMode uxMode) {
|
||||
return UX_MODE_TO_STRING.at(uxMode);
|
||||
}
|
||||
|
||||
RefreshRateManager::RefreshRateManager() {
|
||||
_refreshRateProfile = (RefreshRateManager::RefreshRateProfile) _refreshRateMode.get();
|
||||
}
|
||||
|
||||
void RefreshRateManager::setRefreshRateProfile(RefreshRateManager::RefreshRateProfile refreshRateProfile) {
|
||||
if (_refreshRateProfile != refreshRateProfile) {
|
||||
_refreshRateModeLock.withWriteLock([&] {
|
||||
_refreshRateProfile = refreshRateProfile;
|
||||
_refreshRateMode.set((int) refreshRateProfile);
|
||||
});
|
||||
updateRefreshRateController();
|
||||
}
|
||||
}
|
||||
|
||||
RefreshRateManager::RefreshRateProfile RefreshRateManager::getRefreshRateProfile() const {
|
||||
return (RefreshRateManager::RefreshRateProfile) _refreshRateModeLock.resultWithReadLock<int>([&] {
|
||||
return _refreshRateMode.get();
|
||||
});
|
||||
}
|
||||
|
||||
void RefreshRateManager::setRefreshRateRegime(RefreshRateManager::RefreshRateRegime refreshRateRegime) {
|
||||
if (_refreshRateRegime != refreshRateRegime) {
|
||||
_refreshRateRegime = refreshRateRegime;
|
||||
updateRefreshRateController();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RefreshRateManager::setUXMode(RefreshRateManager::UXMode uxMode) {
|
||||
if (_uxMode != uxMode) {
|
||||
_uxMode = uxMode;
|
||||
updateRefreshRateController();
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshRateManager::updateRefreshRateController() const {
|
||||
if (_refreshRateOperator) {
|
||||
int targetRefreshRate;
|
||||
if (_uxMode == RefreshRateManager::UXMode::DESKTOP) {
|
||||
if (_refreshRateRegime == RefreshRateManager::RefreshRateRegime::RUNNING &&
|
||||
_refreshRateProfile == RefreshRateManager::RefreshRateProfile::INTERACTIVE) {
|
||||
targetRefreshRate = getInteractiveRefreshRate();
|
||||
} else {
|
||||
targetRefreshRate = REFRESH_RATE_REGIMES[_refreshRateRegime][_refreshRateProfile];
|
||||
}
|
||||
} else {
|
||||
targetRefreshRate = HMD_TARGET_RATE;
|
||||
}
|
||||
|
||||
_refreshRateOperator(targetRefreshRate);
|
||||
_activeRefreshRate = targetRefreshRate;
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshRateManager::setInteractiveRefreshRate(int refreshRate) {
|
||||
_refreshRateLock.withWriteLock([&] {
|
||||
_interactiveRefreshRate.set(refreshRate);
|
||||
});
|
||||
updateRefreshRateController();
|
||||
}
|
||||
|
||||
|
||||
int RefreshRateManager::getInteractiveRefreshRate() const {
|
||||
return _refreshRateLock.resultWithReadLock<int>([&] {
|
||||
return _interactiveRefreshRate.get();
|
||||
});
|
||||
}
|
83
interface/src/RefreshRateManager.h
Normal file
83
interface/src/RefreshRateManager.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// RefreshRateManager.h
|
||||
// interface/src/
|
||||
//
|
||||
// Created by Dante Ruiz on 2019-04-15.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_RefreshRateManager_h
|
||||
#define hifi_RefreshRateManager_h
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <shared/ReadWriteLockable.h>
|
||||
|
||||
class RefreshRateManager {
|
||||
public:
|
||||
enum RefreshRateProfile {
|
||||
ECO = 0,
|
||||
INTERACTIVE,
|
||||
REALTIME,
|
||||
PROFILE_NUM
|
||||
};
|
||||
|
||||
enum RefreshRateRegime {
|
||||
RUNNING = 0,
|
||||
UNFOCUS,
|
||||
MINIMIZED,
|
||||
STARTUP,
|
||||
SHUTDOWN,
|
||||
REGIME_NUM
|
||||
};
|
||||
|
||||
enum UXMode {
|
||||
DESKTOP = 0,
|
||||
HMD,
|
||||
UX_NUM
|
||||
};
|
||||
|
||||
RefreshRateManager();
|
||||
~RefreshRateManager() = default;
|
||||
|
||||
void setRefreshRateProfile(RefreshRateProfile refreshRateProfile);
|
||||
RefreshRateProfile getRefreshRateProfile() const;
|
||||
|
||||
void setRefreshRateRegime(RefreshRateRegime refreshRateRegime);
|
||||
RefreshRateRegime getRefreshRateRegime() const { return _refreshRateRegime; }
|
||||
|
||||
void setUXMode(UXMode uxMode);
|
||||
UXMode getUXMode() const { return _uxMode; }
|
||||
|
||||
void setRefreshRateOperator(std::function<void(int)> refreshRateOperator) { _refreshRateOperator = refreshRateOperator; }
|
||||
int getActiveRefreshRate() const { return _activeRefreshRate; }
|
||||
void updateRefreshRateController() const;
|
||||
void setInteractiveRefreshRate(int refreshRate);
|
||||
int getInteractiveRefreshRate() const;
|
||||
|
||||
static std::string refreshRateProfileToString(RefreshRateProfile refreshRateProfile);
|
||||
static RefreshRateProfile refreshRateProfileFromString(std::string refreshRateProfile);
|
||||
static std::string uxModeToString(UXMode uxMode);
|
||||
static std::string refreshRateRegimeToString(RefreshRateRegime refreshRateRegime);
|
||||
|
||||
private:
|
||||
mutable ReadWriteLockable _refreshRateLock;
|
||||
mutable ReadWriteLockable _refreshRateModeLock;
|
||||
|
||||
mutable int _activeRefreshRate { 20 };
|
||||
RefreshRateProfile _refreshRateProfile { RefreshRateProfile::INTERACTIVE};
|
||||
RefreshRateRegime _refreshRateRegime { RefreshRateRegime::STARTUP };
|
||||
UXMode _uxMode;
|
||||
|
||||
Setting::Handle<int> _interactiveRefreshRate { "interactiveRefreshRate", 20};
|
||||
Setting::Handle<int> _refreshRateMode { "refreshRateProfile", INTERACTIVE };
|
||||
|
||||
std::function<void(int)> _refreshRateOperator { nullptr };
|
||||
};
|
||||
|
||||
#endif
|
46
interface/src/scripting/RefreshRateScriptingInterface.h
Normal file
46
interface/src/scripting/RefreshRateScriptingInterface.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// RefreshRateScriptingInterface.h
|
||||
// interface/src/scrfipting
|
||||
//
|
||||
// Created by Dante Ruiz on 2019-04-15.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_RefreshRateScriptingInterface_h
|
||||
#define hifi_RefreshRateScriptingInterface_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
class RefreshRateScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RefreshRateScriptingInterface() = default;
|
||||
~RefreshRateScriptingInterface() = default;
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QString getRefreshRateProfile() {
|
||||
RefreshRateManager& refreshRateManager = qApp->getRefreshRateManager();
|
||||
return QString::fromStdString(RefreshRateManager::refreshRateProfileToString(refreshRateManager.getRefreshRateProfile()));
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString getRefreshRateRegime() {
|
||||
RefreshRateManager& refreshRateManager = qApp->getRefreshRateManager();
|
||||
return QString::fromStdString(RefreshRateManager::refreshRateRegimeToString(refreshRateManager.getRefreshRateRegime()));
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString getUXMode() {
|
||||
RefreshRateManager& refreshRateManager = qApp->getRefreshRateManager();
|
||||
return QString::fromStdString(RefreshRateManager::uxModeToString(refreshRateManager.getUXMode()));
|
||||
}
|
||||
|
||||
Q_INVOKABLE int getActiveRefreshRate() {
|
||||
return qApp->getRefreshRateManager().getActiveRefreshRate();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -82,6 +82,28 @@ void setupPreferences() {
|
|||
preferences->addPreference(new CheckPreference(GRAPHICS_QUALITY, "Show Shadows", getterShadow, setterShadow));
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = []()->QString {
|
||||
RefreshRateManager::RefreshRateProfile refreshRateProfile = qApp->getRefreshRateManager().getRefreshRateProfile();
|
||||
return QString::fromStdString(RefreshRateManager::refreshRateProfileToString(refreshRateProfile));
|
||||
};
|
||||
|
||||
auto setter = [](QString value) {
|
||||
std::string profileName = value.toStdString();
|
||||
RefreshRateManager::RefreshRateProfile refreshRateProfile = RefreshRateManager::refreshRateProfileFromString(profileName);
|
||||
qApp->getRefreshRateManager().setRefreshRateProfile(refreshRateProfile);
|
||||
};
|
||||
|
||||
auto preference = new ComboBoxPreference(GRAPHICS_QUALITY, "Refresh Rate", getter, setter);
|
||||
QStringList refreshRateProfiles
|
||||
{ QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::ECO)),
|
||||
QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::INTERACTIVE)),
|
||||
QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::REALTIME)) };
|
||||
|
||||
preference->setItems(refreshRateProfiles);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
// UI
|
||||
static const QString UI_CATEGORY { "User Interface" };
|
||||
{
|
||||
|
|
|
@ -222,6 +222,10 @@ void Stats::updateStats(bool force) {
|
|||
STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getWorldVelocity()), 0.01f);
|
||||
STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f);
|
||||
if (_expanded || force) {
|
||||
RefreshRateManager& refreshRateManager = qApp->getRefreshRateManager();
|
||||
std::string refreshRateMode = RefreshRateManager::refreshRateProfileToString(refreshRateManager.getRefreshRateProfile());
|
||||
STAT_UPDATE(refreshRateMode, QString::fromStdString(refreshRateMode));
|
||||
STAT_UPDATE(refreshRateTarget, refreshRateManager.getActiveRefreshRate());
|
||||
SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||
if (avatarMixer) {
|
||||
STAT_UPDATE(avatarMixerInKbps, (int)roundf(avatarMixer->getInboundKbps()));
|
||||
|
|
|
@ -206,6 +206,8 @@ class Stats : public QQuickItem {
|
|||
STATS_PROPERTY(float, presentdroprate, 0)
|
||||
STATS_PROPERTY(int, gameLoopRate, 0)
|
||||
STATS_PROPERTY(int, avatarCount, 0)
|
||||
STATS_PROPERTY(int, refreshRateTarget, 0)
|
||||
STATS_PROPERTY(QString, refreshRateMode, QString())
|
||||
STATS_PROPERTY(int, heroAvatarCount, 0)
|
||||
STATS_PROPERTY(int, physicsObjectCount, 0)
|
||||
STATS_PROPERTY(int, updatedAvatarCount, 0)
|
||||
|
@ -1067,6 +1069,11 @@ signals:
|
|||
*/
|
||||
void decimatedTextureCountChanged();
|
||||
|
||||
|
||||
void refreshRateTargetChanged();
|
||||
|
||||
void refreshRateModeChanged();
|
||||
|
||||
// QQuickItem signals.
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include <TextureCache.h>
|
||||
#include "CompositorHelper.h"
|
||||
#include "Logging.h"
|
||||
|
||||
#include "RefreshRateController.h"
|
||||
extern QThread* RENDER_THREAD;
|
||||
|
||||
class PresentThread : public QThread, public Dependency {
|
||||
|
@ -60,12 +60,16 @@ public:
|
|||
shutdown();
|
||||
});
|
||||
setObjectName("Present");
|
||||
|
||||
_refreshRateController = std::make_shared<RefreshRateController>();
|
||||
}
|
||||
|
||||
~PresentThread() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
auto getRefreshRateController() { return _refreshRateController; }
|
||||
|
||||
void shutdown() {
|
||||
if (isRunning()) {
|
||||
// First ensure that we turn off any current display plugin
|
||||
|
@ -179,6 +183,7 @@ public:
|
|||
}
|
||||
|
||||
// Execute the frame and present it to the display device.
|
||||
_refreshRateController->clockStartTime();
|
||||
{
|
||||
PROFILE_RANGE(render, "PluginPresent")
|
||||
gl::globalLock();
|
||||
|
@ -186,6 +191,10 @@ public:
|
|||
gl::globalRelease(false);
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
// stop time
|
||||
_refreshRateController->clockEndTime();
|
||||
_refreshRateController->sleepThreadIfNeeded(this);
|
||||
// sleep if needed
|
||||
}
|
||||
|
||||
_context->doneCurrent();
|
||||
|
@ -234,6 +243,7 @@ private:
|
|||
bool _finishedOtherThreadOperation { false };
|
||||
std::queue<OpenGLDisplayPlugin*> _newPluginQueue;
|
||||
gl::Context* _context { nullptr };
|
||||
std::shared_ptr<RefreshRateController> _refreshRateController { nullptr };
|
||||
};
|
||||
|
||||
bool OpenGLDisplayPlugin::activate() {
|
||||
|
@ -759,6 +769,13 @@ float OpenGLDisplayPlugin::presentRate() const {
|
|||
return _presentRate.rate();
|
||||
}
|
||||
|
||||
std::function<void(int)> OpenGLDisplayPlugin::getRefreshRateOperator() {
|
||||
return [](int targetRefreshRate) {
|
||||
auto refreshRateController = DependencyManager::get<PresentThread>()->getRefreshRateController();
|
||||
refreshRateController->setRefreshRateLimit(targetRefreshRate);
|
||||
};
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::resetPresentRate() {
|
||||
// FIXME
|
||||
// _presentRate = RateCounter<100>();
|
||||
|
|
|
@ -29,6 +29,8 @@ namespace gpu {
|
|||
}
|
||||
}
|
||||
|
||||
class RefreshRateController;
|
||||
|
||||
class OpenGLDisplayPlugin : public DisplayPlugin {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float hudAlpha MEMBER _hudAlpha)
|
||||
|
@ -41,6 +43,9 @@ public:
|
|||
~OpenGLDisplayPlugin();
|
||||
// These must be final to ensure proper ordering of operations
|
||||
// between the main thread and the presentation thread
|
||||
|
||||
static std::function<void(int)> getRefreshRateOperator();
|
||||
|
||||
bool activate() override final;
|
||||
void deactivate() override final;
|
||||
bool startStandBySession() override final;
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// RefreshRateController.cpp
|
||||
// libraries/display-pluging/src/display-plugin
|
||||
//
|
||||
// Created by Dante Ruiz on 2019-04-15.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "RefreshRateController.h"
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
int refreshRateConverter(int refreshRate) {
|
||||
const float ONE_SECOND_IN_MILLISECONDS = 1000.0f;
|
||||
const float ONE_TIME_UNIT = 1.0f;
|
||||
float frameInOneTimeUnit = ONE_TIME_UNIT / (float) refreshRate;
|
||||
float convertedRefreshRate = frameInOneTimeUnit * ONE_SECOND_IN_MILLISECONDS;
|
||||
return (int) convertedRefreshRate;
|
||||
}
|
||||
|
||||
void RefreshRateController::setRefreshRateLimit(int refreshRateLimit) {
|
||||
_refreshRateLimit = refreshRateConverter(refreshRateLimit);
|
||||
}
|
||||
|
||||
int RefreshRateController::getRefreshRateLimit() const {
|
||||
return refreshRateConverter(_refreshRateLimit);
|
||||
}
|
||||
|
||||
void RefreshRateController::sleepThreadIfNeeded(QThread* thread) {
|
||||
auto startTimeFromEpoch = _startTime.time_since_epoch();
|
||||
auto endTimeFromEpoch = _endTime.time_since_epoch();
|
||||
|
||||
auto startMs = std::chrono::duration_cast<std::chrono::milliseconds>(startTimeFromEpoch).count();
|
||||
auto endMs = std::chrono::duration_cast<std::chrono::milliseconds>(endTimeFromEpoch).count();
|
||||
auto duration = endMs - startMs;
|
||||
if (duration < _refreshRateLimit) {
|
||||
thread->msleep(_refreshRateLimit - duration);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// RefreshRateController.h
|
||||
// libraries/display-pluging/src/display-plugin
|
||||
//
|
||||
// Created by Dante Ruiz on 2019-04-15.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_RefreshRateController_h
|
||||
#define hifi_RefreshRateController_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
class QThread;
|
||||
|
||||
class RefreshRateController {
|
||||
public:
|
||||
RefreshRateController() = default;
|
||||
~RefreshRateController() = default;
|
||||
|
||||
void setRefreshRateLimit(int refreshRateLimiti);
|
||||
int getRefreshRateLimit() const;
|
||||
|
||||
void clockStartTime() { _startTime = std::chrono::system_clock::now(); }
|
||||
void clockEndTime() { _endTime = std::chrono::system_clock::now(); }
|
||||
void sleepThreadIfNeeded(QThread* thread);
|
||||
private:
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> _startTime { std::chrono::system_clock::now() };
|
||||
std::chrono::time_point<std::chrono::system_clock> _endTime { std::chrono::system_clock::now() };
|
||||
std::atomic_int _refreshRateLimit { 50 }; // milliseconds
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -90,6 +90,7 @@ public:
|
|||
// HMD display functionality
|
||||
// TODO move out of this file don't derive DisplayPlugin from this. Instead use dynamic casting when
|
||||
// displayPlugin->isHmd returns true
|
||||
class RefreshRateController;
|
||||
class HmdDisplay : public StereoDisplay {
|
||||
public:
|
||||
// HMD specific methods
|
||||
|
@ -128,6 +129,7 @@ public:
|
|||
/// By default, all HMDs are stereo
|
||||
virtual bool isStereo() const { return isHmd(); }
|
||||
virtual bool isThrottled() const { return false; }
|
||||
|
||||
virtual float getTargetFrameRate() const { return 1.0f; }
|
||||
virtual bool hasAsyncReprojection() const { return false; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue