Fixing framerate limit, moving vsync to 2d plugin

This commit is contained in:
Brad Davis 2015-08-25 00:55:00 -07:00
parent 8cd13cad00
commit 270f2f7a3b
12 changed files with 206 additions and 213 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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";

View file

@ -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();

View file

@ -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 };
};

View file

@ -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() {

View file

@ -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();

View file

@ -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
}

View file

@ -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 };
};

View file

@ -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;
}

View file

@ -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;