mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 11:45:36 +02:00
Fixing framerate limit, moving vsync to 2d plugin
This commit is contained in:
parent
8cd13cad00
commit
270f2f7a3b
12 changed files with 206 additions and 213 deletions
|
@ -189,6 +189,11 @@ static QTimer* billboardPacketTimer = NULL;
|
|||
static QTimer* checkFPStimer = NULL;
|
||||
static QTimer* idleTimer = NULL;
|
||||
|
||||
static const unsigned int TARGET_SIM_FRAMERATE = 60;
|
||||
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
|
||||
static const int TARGET_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / TARGET_SIM_FRAMERATE;
|
||||
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
|
||||
|
||||
const QString CHECK_VERSION_URL = "https://highfidelity.com/latestVersion.xml";
|
||||
const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
|
||||
|
||||
|
@ -347,7 +352,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_trayIcon(new QSystemTrayIcon(_window)),
|
||||
_lastNackTime(usecTimestampNow()),
|
||||
_lastSendDownstreamAudioStats(usecTimestampNow()),
|
||||
_isVSyncOn(true),
|
||||
_isThrottleFPSEnabled(true),
|
||||
_aboutToQuit(false),
|
||||
_notifiedPacketVersionMismatchThisDomain(false),
|
||||
|
@ -745,8 +749,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
});
|
||||
|
||||
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
|
||||
|
||||
setVSyncEnabled(); // make sure VSync is set properly at startup
|
||||
}
|
||||
|
||||
void Application::aboutToQuit() {
|
||||
|
@ -920,7 +922,7 @@ void Application::initializeGL() {
|
|||
// call our idle function whenever we can
|
||||
idleTimer = new QTimer(this);
|
||||
connect(idleTimer, SIGNAL(timeout()), SLOT(idle()));
|
||||
idleTimer->start(0);
|
||||
idleTimer->start(TARGET_SIM_FRAME_PERIOD_MS);
|
||||
_idleLoopStdev.reset();
|
||||
|
||||
if (_justStarted) {
|
||||
|
@ -2033,38 +2035,38 @@ void Application::checkFPS() {
|
|||
}
|
||||
|
||||
void Application::idle() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
static SimpleAverage<float> interIdleDurations;
|
||||
|
||||
static uint64_t lastIdleStart{ 0 };
|
||||
static uint64_t lastIdleEnd{ 0 };
|
||||
uint64_t now = usecTimestampNow();
|
||||
uint64_t idleStartToStartDuration = now - lastIdleStart;
|
||||
|
||||
if (lastIdleStart > 0 && idleStartToStartDuration > 0) {
|
||||
_simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration);
|
||||
}
|
||||
|
||||
lastIdleStart = now;
|
||||
|
||||
if (lastIdleEnd != 0) {
|
||||
interIdleDurations.update(now - lastIdleEnd);
|
||||
static uint64_t lastReportTime = now;
|
||||
if ((now - lastReportTime) >= (USECS_PER_SECOND)) {
|
||||
static QString LOGLINE("Average inter-idle time: %1 us for %2 samples");
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::LogExtraTimings)) {
|
||||
qCDebug(interfaceapp_timing) << LOGLINE.arg((int)interIdleDurations.getAverage()).arg(interIdleDurations.getCount());
|
||||
}
|
||||
interIdleDurations.reset();
|
||||
lastReportTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
PerformanceTimer perfTimer("idle");
|
||||
if (_aboutToQuit) {
|
||||
return; // bail early, nothing to do here.
|
||||
}
|
||||
|
||||
// depending on whether we're throttling or not.
|
||||
// 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();
|
||||
// Only run simulation code if more than the targetFramePeriod have passed since last time we ran
|
||||
// This attempts to lock the simulation at 60 updates per second, regardless of framerate
|
||||
float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC;
|
||||
float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND;
|
||||
|
||||
if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) {
|
||||
return; // bail early, we're throttled and not enough time has elapsed
|
||||
}
|
||||
|
||||
_lastTimeUpdated.start();
|
||||
|
||||
|
||||
{
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
uint64_t now = usecTimestampNow();
|
||||
static uint64_t lastIdleStart{ now };
|
||||
uint64_t idleStartToStartDuration = now - lastIdleStart;
|
||||
if (idleStartToStartDuration != 0) {
|
||||
_simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration);
|
||||
}
|
||||
lastIdleStart = now;
|
||||
}
|
||||
|
||||
PerformanceTimer perfTimer("idle");
|
||||
// Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds
|
||||
if (!_keyboardFocusedItem.isInvalidID()) {
|
||||
const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus
|
||||
|
@ -2080,69 +2082,42 @@ void Application::idle() {
|
|||
bool showWarnings = getLogger()->extraDebugging();
|
||||
PerformanceWarning warn(showWarnings, "idle()");
|
||||
|
||||
// Only run simulation code if more than the targetFramePeriod have passed since last time we ran
|
||||
double targetFramePeriod = 0.0;
|
||||
unsigned int targetFramerate = getRenderTargetFramerate();
|
||||
if (targetFramerate > 0) {
|
||||
targetFramePeriod = 1000.0 / targetFramerate;
|
||||
{
|
||||
PerformanceTimer perfTimer("update");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... update()");
|
||||
static const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||
update(glm::clamp(secondsSinceLastUpdate, 0.0f, BIGGEST_DELTA_TIME_SECS));
|
||||
}
|
||||
double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0;
|
||||
if (timeSinceLastUpdate > targetFramePeriod) {
|
||||
_lastTimeUpdated.start();
|
||||
{
|
||||
PerformanceTimer perfTimer("update");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... update()");
|
||||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||
PROFILE_RANGE(__FUNCTION__ "/idleUpdate");
|
||||
update(glm::clamp((float)timeSinceLastUpdate / 1000.0f, 0.0f, BIGGEST_DELTA_TIME_SECS));
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("updateGL");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()");
|
||||
getActiveDisplayPlugin()->idle();
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
QString name = inputPlugin->getName();
|
||||
QAction* action = Menu::getInstance()->getActionForOption(name);
|
||||
if (action && action->isChecked()) {
|
||||
inputPlugin->idle();
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("pluginIdle");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... pluginIdle()");
|
||||
getActiveDisplayPlugin()->idle();
|
||||
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
|
||||
foreach(auto inputPlugin, inputPlugins) {
|
||||
QString name = inputPlugin->getName();
|
||||
QAction* action = Menu::getInstance()->getActionForOption(name);
|
||||
if (action && action->isChecked()) {
|
||||
inputPlugin->idle();
|
||||
}
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("rest");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
|
||||
_idleLoopStdev.addValue(timeSinceLastUpdate);
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("rest");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
|
||||
_idleLoopStdev.addValue(secondsSinceLastUpdate);
|
||||
|
||||
// Record standard deviation and reset counter if needed
|
||||
const int STDEV_SAMPLES = 500;
|
||||
if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) {
|
||||
_idleLoopMeasuredJitter = _idleLoopStdev.getStDev();
|
||||
_idleLoopStdev.reset();
|
||||
}
|
||||
}
|
||||
|
||||
float secondsSinceLastUpdate = (float)timeSinceLastUpdate / 1000.0f;
|
||||
_overlayConductor.update(secondsSinceLastUpdate);
|
||||
|
||||
// depending on whether we're throttling or not.
|
||||
// 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 = isThrottled ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS;
|
||||
//qDebug() << "isThrottled:" << isThrottled << "desiredInterval:" << desiredInterval;
|
||||
|
||||
if (idleTimer->interval() != desiredInterval) {
|
||||
idleTimer->start(desiredInterval);
|
||||
// Record standard deviation and reset counter if needed
|
||||
const int STDEV_SAMPLES = 500;
|
||||
if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) {
|
||||
_idleLoopMeasuredJitter = _idleLoopStdev.getStDev();
|
||||
_idleLoopStdev.reset();
|
||||
}
|
||||
}
|
||||
|
||||
_overlayConductor.update(secondsSinceLastUpdate);
|
||||
|
||||
// check for any requested background downloads.
|
||||
emit checkBackgroundDownloads();
|
||||
lastIdleEnd = usecTimestampNow();
|
||||
}
|
||||
|
||||
float Application::getAverageSimsPerSecond() {
|
||||
|
@ -4476,90 +4451,10 @@ void Application::takeSnapshot() {
|
|||
|
||||
}
|
||||
|
||||
void Application::setVSyncEnabled() {
|
||||
_glWidget->makeCurrent();
|
||||
#if defined(Q_OS_WIN)
|
||||
bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn);
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
wglSwapIntervalEXT(vsyncOn);
|
||||
int swapInterval = wglGetSwapIntervalEXT();
|
||||
qCDebug(interfaceapp, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
|
||||
} else {
|
||||
qCDebug(interfaceapp, "V-Sync is FORCED ON on this system\n");
|
||||
}
|
||||
#elif defined(Q_OS_LINUX)
|
||||
// TODO: write the poper code for linux
|
||||
/*
|
||||
if (glQueryExtension.... ("GLX_EXT_swap_control")) {
|
||||
glxSwapIntervalEXT(vsyncOn);
|
||||
int swapInterval = xglGetSwapIntervalEXT();
|
||||
_isVSyncOn = swapInterval;
|
||||
qCDebug(interfaceapp, "V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
|
||||
} else {
|
||||
qCDebug(interfaceapp, "V-Sync is FORCED ON on this system\n");
|
||||
}
|
||||
*/
|
||||
#else
|
||||
qCDebug(interfaceapp, "V-Sync is FORCED ON on this system\n");
|
||||
#endif
|
||||
_offscreenContext->makeCurrent();
|
||||
}
|
||||
|
||||
void Application::setThrottleFPSEnabled() {
|
||||
_isThrottleFPSEnabled = Menu::getInstance()->isOptionChecked(MenuOption::ThrottleFPSIfNotFocus);
|
||||
}
|
||||
|
||||
bool Application::isVSyncOn() const {
|
||||
#if defined(Q_OS_WIN)
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
int swapInterval = wglGetSwapIntervalEXT();
|
||||
return (swapInterval > 0);
|
||||
}
|
||||
#elif defined(Q_OS_LINUX)
|
||||
// TODO: write the poper code for linux
|
||||
/*
|
||||
if (glQueryExtension.... ("GLX_EXT_swap_control")) {
|
||||
int swapInterval = xglGetSwapIntervalEXT();
|
||||
return (swapInterval > 0);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::isVSyncEditable() const {
|
||||
#if defined(Q_OS_WIN)
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
return true;
|
||||
}
|
||||
#elif defined(Q_OS_LINUX)
|
||||
// TODO: write the poper code for linux
|
||||
/*
|
||||
if (glQueryExtension.... ("GLX_EXT_swap_control")) {
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int Application::getRenderTargetFramerate() const {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateUnlimited)) {
|
||||
return 0;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerate60)) {
|
||||
return 60;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerate50)) {
|
||||
return 50;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerate40)) {
|
||||
return 40;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerate30)) {
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Application::getRenderResolutionScale() const {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionOne)) {
|
||||
return 1.0f;
|
||||
|
|
|
@ -300,9 +300,6 @@ public:
|
|||
float getRenderResolutionScale() const;
|
||||
int getRenderAmbientLight() const;
|
||||
|
||||
unsigned int getRenderTargetFramerate() const;
|
||||
bool isVSyncOn() const;
|
||||
bool isVSyncEditable() const;
|
||||
bool isAboutToQuit() const { return _aboutToQuit; }
|
||||
|
||||
// the isHMDmode is true whenever we use the interface from an HMD and not a standard flat display
|
||||
|
@ -411,8 +408,6 @@ public slots:
|
|||
|
||||
void domainSettingsReceived(const QJsonObject& domainSettingsObject);
|
||||
|
||||
void setVSyncEnabled();
|
||||
|
||||
void setThrottleFPSEnabled();
|
||||
bool isThrottleFPSEnabled() { return _isThrottleFPSEnabled; }
|
||||
|
||||
|
@ -626,7 +621,6 @@ private:
|
|||
quint64 _lastNackTime;
|
||||
quint64 _lastSendDownstreamAudioStats;
|
||||
|
||||
bool _isVSyncOn;
|
||||
bool _isThrottleFPSEnabled;
|
||||
|
||||
bool _aboutToQuit;
|
||||
|
|
|
@ -222,7 +222,7 @@ Menu::Menu() {
|
|||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::PackageModel, 0,
|
||||
qApp, SLOT(packageModel()));
|
||||
|
||||
MenuWrapper* displayMenu = addMenu(DisplayPlugin::MENU_PATH);
|
||||
MenuWrapper* displayMenu = addMenu(DisplayPlugin::MENU_PATH());
|
||||
{
|
||||
MenuWrapper* displayModeMenu = addMenu(MenuOption::OutputMenu);
|
||||
QActionGroup* displayModeGroup = new QActionGroup(displayModeMenu);
|
||||
|
@ -333,25 +333,8 @@ Menu::Menu() {
|
|||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
|
||||
ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
|
||||
|
||||
{
|
||||
MenuWrapper* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate);
|
||||
QActionGroup* framerateGroup = new QActionGroup(framerateMenu);
|
||||
framerateGroup->setExclusive(true);
|
||||
framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerateUnlimited, 0, true));
|
||||
framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate60, 0, false));
|
||||
framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate50, 0, false));
|
||||
framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate40, 0, false));
|
||||
framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate30, 0, false));
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
#else
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true,
|
||||
qApp, SLOT(setVSyncEnabled()));
|
||||
#endif
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true,
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true,
|
||||
qApp, SLOT(setThrottleFPSEnabled()));
|
||||
}
|
||||
|
||||
|
||||
MenuWrapper* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution);
|
||||
QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu);
|
||||
|
|
|
@ -238,13 +238,6 @@ namespace MenuOption {
|
|||
const QString RenderLookAtTargets = "Show Look-at Targets";
|
||||
const QString RenderLookAtVectors = "Show Look-at Vectors";
|
||||
const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes";
|
||||
const QString RenderTargetFramerate = "Framerate";
|
||||
const QString RenderTargetFramerateUnlimited = "Unlimited";
|
||||
const QString RenderTargetFramerate60 = "60";
|
||||
const QString RenderTargetFramerate50 = "50";
|
||||
const QString RenderTargetFramerate40 = "40";
|
||||
const QString RenderTargetFramerate30 = "30";
|
||||
const QString RenderTargetFramerateVSyncOn = "V-Sync On";
|
||||
const QString RenderResolution = "Scale Resolution";
|
||||
const QString RenderResolutionOne = "1";
|
||||
const QString RenderResolutionTwoThird = "2/3";
|
||||
|
|
|
@ -7,21 +7,35 @@
|
|||
//
|
||||
#include "Basic2DWindowOpenGLDisplayPlugin.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtWidgets/QAction>
|
||||
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <QWindow>
|
||||
#include <QGuiApplication>
|
||||
|
||||
const QString Basic2DWindowOpenGLDisplayPlugin::NAME("2D Display");
|
||||
|
||||
static const QString FULLSCREEN = "Fullscreen";
|
||||
static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
|
||||
static const QString FRAMERATE_UNLIMITED = "Unlimited";
|
||||
static const QString FRAMERATE_60 = "60";
|
||||
static const QString FRAMERATE_50 = "50";
|
||||
static const QString FRAMERATE_40 = "40";
|
||||
static const QString FRAMERATE_30 = "30";
|
||||
static const QString VSYNC_ON = "V-Sync On";
|
||||
|
||||
const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
std::vector<QAction*> _framerateActions;
|
||||
QAction* _vsyncAction{ nullptr };
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::activate() {
|
||||
CONTAINER->addMenu(MENU_PATH);
|
||||
CONTAINER->addMenuItem(MENU_PATH, FULLSCREEN,
|
||||
_framerateActions.clear();
|
||||
CONTAINER->addMenuItem(MENU_PATH(), FULLSCREEN,
|
||||
[this](bool clicked) {
|
||||
if (clicked) {
|
||||
CONTAINER->setFullscreen(getFullscreenTarget());
|
||||
|
@ -29,18 +43,65 @@ void Basic2DWindowOpenGLDisplayPlugin::activate() {
|
|||
CONTAINER->unsetFullscreen();
|
||||
}
|
||||
}, true, false);
|
||||
CONTAINER->addMenu(FRAMERATE);
|
||||
_framerateActions.push_back(
|
||||
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
|
||||
[this](bool) { updateFramerate(); }, true, true, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_60,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_50,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_40,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
_framerateActions.push_back(
|
||||
CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_30,
|
||||
[this](bool) { updateFramerate(); }, true, false, FRAMERATE));
|
||||
|
||||
WindowOpenGLDisplayPlugin::activate();
|
||||
|
||||
// Vsync detection happens in the parent class activate, so we need to check after that
|
||||
if (_vsyncSupported) {
|
||||
_vsyncAction = CONTAINER->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
|
||||
} else {
|
||||
_vsyncAction = nullptr;
|
||||
}
|
||||
|
||||
updateFramerate();
|
||||
}
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::deactivate() {
|
||||
WindowOpenGLDisplayPlugin::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;
|
||||
void Basic2DWindowOpenGLDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {
|
||||
if (_vsyncAction) {
|
||||
bool wantVsync = _vsyncAction->isChecked();
|
||||
bool vsyncEnabed = isVsyncEnabled();
|
||||
if (vsyncEnabed ^ wantVsync) {
|
||||
enableVsync(wantVsync);
|
||||
}
|
||||
}
|
||||
|
||||
return isThrottled ? THROTTLED_PAINT_TIMER_DELAY : PAINT_TIMER_DELAY_MS;
|
||||
WindowOpenGLDisplayPlugin::display(sceneTexture, sceneSize);
|
||||
}
|
||||
|
||||
|
||||
int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
|
||||
static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15;
|
||||
static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1;
|
||||
int result = ULIMIITED_PAINT_TIMER_DELAY_MS;
|
||||
if (_isThrottled) {
|
||||
result = THROTTLED_PAINT_TIMER_DELAY_MS;
|
||||
}
|
||||
if (0 != _framerateTarget) {
|
||||
result = MSECS_PER_SECOND / _framerateTarget;
|
||||
}
|
||||
|
||||
qDebug() << "New interval " << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
|
||||
|
@ -49,14 +110,42 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
|
|||
bool shouldThrottle = (!CONTAINER->isForeground() && CONTAINER->isOptionChecked(ThrottleFPSIfNotFocus));
|
||||
|
||||
if (_isThrottled != shouldThrottle) {
|
||||
int desiredInterval = getDesiredInterval(shouldThrottle);
|
||||
_timer.start(desiredInterval);
|
||||
_isThrottled = shouldThrottle;
|
||||
_timer.start(getDesiredInterval());
|
||||
}
|
||||
|
||||
return shouldThrottle;
|
||||
}
|
||||
|
||||
|
||||
void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() {
|
||||
QAction* checkedFramerate{ nullptr };
|
||||
foreach(auto action, _framerateActions) {
|
||||
if (action->isChecked()) {
|
||||
checkedFramerate = action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_framerateTarget = 0;
|
||||
if (checkedFramerate) {
|
||||
QString actionText = checkedFramerate->text();
|
||||
if (FRAMERATE_60 == actionText) {
|
||||
_framerateTarget = 60;
|
||||
} else if (FRAMERATE_50 == actionText) {
|
||||
_framerateTarget = 50;
|
||||
} else if (FRAMERATE_40 == actionText) {
|
||||
_framerateTarget = 40;
|
||||
} else if (FRAMERATE_30 == actionText) {
|
||||
_framerateTarget = 30;
|
||||
}
|
||||
}
|
||||
|
||||
int newInterval = getDesiredInterval();
|
||||
qDebug() << newInterval;
|
||||
_timer.start(getDesiredInterval());
|
||||
}
|
||||
|
||||
// FIXME target the screen the window is currently on
|
||||
QScreen* Basic2DWindowOpenGLDisplayPlugin::getFullscreenTarget() {
|
||||
return qApp->primaryScreen();
|
||||
|
|
|
@ -14,19 +14,23 @@ class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual const QString & getName() const override;
|
||||
|
||||
virtual void activate() override;
|
||||
virtual void deactivate() override;
|
||||
|
||||
virtual const QString & getName() const override;
|
||||
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
|
||||
|
||||
virtual bool isThrottled() const override;
|
||||
|
||||
protected:
|
||||
int getDesiredInterval(bool isThrottled) const;
|
||||
int getDesiredInterval() const;
|
||||
mutable bool _isThrottled = false;
|
||||
|
||||
private:
|
||||
void updateFramerate();
|
||||
static const QString NAME;
|
||||
QScreen* getFullscreenTarget();
|
||||
uint32_t _framerateTarget{ 0 };
|
||||
int _fullscreenTarget{ -1 };
|
||||
};
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
#include "oculus/OculusDisplayPlugin.h"
|
||||
#include "oculus/OculusLegacyDisplayPlugin.h"
|
||||
|
||||
const QString DisplayPlugin::MENU_PATH{ "Display" };
|
||||
const QString& DisplayPlugin::MENU_PATH() {
|
||||
static const QString value = "Display";
|
||||
return value;
|
||||
}
|
||||
|
||||
// TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
|
||||
DisplayPluginList getDisplayPlugins() {
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
virtual void resetSensors() {}
|
||||
virtual float devicePixelRatio() { return 1.0; }
|
||||
|
||||
static const QString MENU_PATH;
|
||||
static const QString& MENU_PATH();
|
||||
signals:
|
||||
void recommendedFramebufferSizeChanged(const QSize & size);
|
||||
void requestRender();
|
||||
|
|
|
@ -38,6 +38,11 @@ void OpenGLDisplayPlugin::finishFrame() {
|
|||
|
||||
void OpenGLDisplayPlugin::customizeContext() {
|
||||
using namespace oglplus;
|
||||
// TODO: write the poper code for linux
|
||||
#if defined(Q_OS_WIN)
|
||||
_vsyncSupported = wglewGetExtension("WGL_EXT_swap_control");
|
||||
#endif
|
||||
|
||||
Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
|
||||
Context::Disable(Capability::Blend);
|
||||
Context::Disable(Capability::DepthTest);
|
||||
|
@ -46,6 +51,8 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
|
||||
_program = loadDefaultShader();
|
||||
_plane = loadPlane(_program);
|
||||
|
||||
enableVsync();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::activate() {
|
||||
|
@ -114,4 +121,24 @@ void OpenGLDisplayPlugin::display(
|
|||
void OpenGLDisplayPlugin::drawUnitQuad() {
|
||||
_program->Bind();
|
||||
_plane->Draw();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::enableVsync(bool enable) {
|
||||
if (!_vsyncSupported) {
|
||||
return;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
wglSwapIntervalEXT(enable ? 1 : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OpenGLDisplayPlugin::isVsyncEnabled() {
|
||||
if (!_vsyncSupported) {
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
return wglGetSwapIntervalEXT() != 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
|
@ -38,9 +38,13 @@ protected:
|
|||
virtual void doneCurrent() = 0;
|
||||
virtual void swapBuffers() = 0;
|
||||
|
||||
virtual bool isVsyncEnabled();
|
||||
virtual void enableVsync(bool enable = true);
|
||||
|
||||
mutable QTimer _timer;
|
||||
ProgramPtr _program;
|
||||
ShapeWrapperPtr _plane;
|
||||
bool _vsyncSupported{ false };
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ void StereoDisplayPlugin::activate() {
|
|||
if (screen == qApp->primaryScreen()) {
|
||||
checked = true;
|
||||
}
|
||||
auto action = CONTAINER->addMenuItem(MENU_PATH, name,
|
||||
auto action = CONTAINER->addMenuItem(MENU_PATH(), name,
|
||||
[this](bool clicked) { updateScreen(); }, true, checked, "Screens");
|
||||
_screenActions[i] = action;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ const float METERS_PER_DECIMETER = 0.1f;
|
|||
const float METERS_PER_CENTIMETER = 0.01f;
|
||||
const float METERS_PER_MILLIMETER = 0.001f;
|
||||
const float MILLIMETERS_PER_METER = 1000.0f;
|
||||
const quint64 NSECS_PER_USEC = 1000;
|
||||
const quint64 USECS_PER_MSEC = 1000;
|
||||
const quint64 MSECS_PER_SECOND = 1000;
|
||||
const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND;
|
||||
|
|
Loading…
Reference in a new issue