History

Application: don't simulate until we are ready to render.

Anthony J. Thibault committed 10 years ago

Commit 1fdae131 parent 8422d4f2 files · +17 −33Browse files

Showing the changes to interface/src/Application.cpp (1 of 2 files). Show all

Unified · Split

interface/src/Application.cpp+17−32
@@ -210,8 +210,6 @@ static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html"; · 209 unmodified lines
210 210
211static const unsigned int THROTTLED_SIM_FRAMERATE = 15;211static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
212static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;212static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
213static const unsigned int CAPPED_SIM_FRAMERATE = 120;
214static const int CAPPED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / CAPPED_SIM_FRAMERATE;
215 213
216static const uint32_t INVALID_FRAME = UINT32_MAX;214static const uint32_t INVALID_FRAME = UINT32_MAX;
217 215
@@ -317,6 +315,9 @@ bool setupEssentials(int& argc, char** argv) { · 99 unmodified lines
317 315
318 Setting::preInit();316 Setting::preInit();
319 317
318 LogHandler::getInstance().setShouldDisplayMilliseconds(true);
319 LogHandler::getInstance().setShouldOutputThreadID(true);
320
320 CrashHandler::checkForAndHandleCrash();321 CrashHandler::checkForAndHandleCrash();
321 CrashHandler::writeRunningMarkerFiler();322 CrashHandler::writeRunningMarkerFiler();
322 qAddPostRoutine(CrashHandler::deleteRunningMarkerFile);323 qAddPostRoutine(CrashHandler::deleteRunningMarkerFile);
@@ -967,6 +968,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 644 unmodified lines
967 968
968 connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);969 connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
969 qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);970 qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
971
970 _idleTimer = new QTimer(this);972 _idleTimer = new QTimer(this);
971 connect(_idleTimer, &QTimer::timeout, [=] {973 connect(_idleTimer, &QTimer::timeout, [=] {
972 idle(usecTimestampNow());974 idle(usecTimestampNow());
@@ -975,7 +977,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 2 unmodified lines
975 disconnect(_idleTimer);977 disconnect(_idleTimer);
976 });978 });
977 // Setting the interval to zero forces this to get called whenever there are no messages979 // Setting the interval to zero forces this to get called whenever there are no messages
978 // in the queue, which can be pretty damn frequent. Hence the idle function has a bunch 980 // in the queue, which can be pretty damn frequent. Hence the idle function has a bunch
979 // of logic to abort early if it's being called too often.981 // of logic to abort early if it's being called too often.
980 _idleTimer->start(0);982 _idleTimer->start(0);
981}983}
@@ -1296,6 +1298,7 @@ void Application::initializeUi() { · 314 unmodified lines
1296}1298}
1297 1299
1298void Application::paintGL() {1300void Application::paintGL() {
1301
1299 // paintGL uses a queued connection, so we can get messages from the queue even after we've quit1302 // paintGL uses a queued connection, so we can get messages from the queue even after we've quit
1300 // and the plugins have shutdown1303 // and the plugins have shutdown
1301 if (_aboutToQuit) {1304 if (_aboutToQuit) {
@@ -1321,10 +1324,6 @@ void Application::paintGL() { · 19 unmodified lines
1321 _lastFramesPerSecondUpdate = now;1324 _lastFramesPerSecondUpdate = now;
1322 }1325 }
1323 1326
1324 if (_isGLInitialized) {
1325 idle(now);
1326 }
1327
1328 PROFILE_RANGE(__FUNCTION__);1327 PROFILE_RANGE(__FUNCTION__);
1329 PerformanceTimer perfTimer("paintGL");1328 PerformanceTimer perfTimer("paintGL");
1330 1329
@@ -1619,7 +1618,6 @@ void Application::paintGL() { · 288 unmodified lines
1619 }1618 }
1620 1619
1621 _lastInstantaneousFps = instantaneousFps;1620 _lastInstantaneousFps = instantaneousFps;
1622 _pendingPaint = false;
1623}1621}
1624 1622
1625void Application::runTests() {1623void Application::runTests() {
@@ -2432,10 +2430,11 @@ bool Application::acceptSnapshot(const QString& urlString) { · 806 unmodified lines
2432static uint32_t _renderedFrameIndex { INVALID_FRAME };2430static uint32_t _renderedFrameIndex { INVALID_FRAME };
2433 2431
2434void Application::idle(uint64_t now) {2432void Application::idle(uint64_t now) {
2433
2435 if (_aboutToQuit) {2434 if (_aboutToQuit) {
2436 return; // bail early, nothing to do here.2435 return; // bail early, nothing to do here.
2437 }2436 }
2438 2437
2439 auto displayPlugin = getActiveDisplayPlugin();2438 auto displayPlugin = getActiveDisplayPlugin();
2440 // depending on whether we're throttling or not.2439 // depending on whether we're throttling or not.
2441 // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in2440 // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
@@ -2456,30 +2455,16 @@ void Application::idle(uint64_t now) { · 14 unmodified lines
2456 _renderedFrameIndex = INVALID_FRAME;2455 _renderedFrameIndex = INVALID_FRAME;
2457 }2456 }
2458 2457
2459 // Nested ifs are for clarity in the logic. Don't collapse them into a giant single if.
2460 // Don't saturate the main thread with rendering, no paint calls until the last one is complete2458 // Don't saturate the main thread with rendering, no paint calls until the last one is complete
2461 if (!_pendingPaint) {2459 // Also no paint calls until the display plugin has increased by at least one frame
2462 // Also no paint calls until the display plugin has increased by at least one frame 2460 // (don't render at 90fps if the display plugin only goes at 60)
2463 // (don't render at 90fps if the display plugin only goes at 60)2461 if (_renderedFrameIndex == INVALID_FRAME || presentCount > _renderedFrameIndex) {
2464 if (_renderedFrameIndex == INVALID_FRAME || presentCount > _renderedFrameIndex) {2462 // Record what present frame we're on
2465 // Record what present frame we're on2463 _renderedFrameIndex = presentCount;
2466 _renderedFrameIndex = presentCount;2464
2467 // Don't allow paint requests to stack up in the event queue2465 // But when we DO request a paint, get to it as soon as possible: high priority
2468 _pendingPaint = true;2466 postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
2469 // But when we DO request a paint, get to it as soon as possible: high priority2467 } else {
2470 postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
2471 }
2472 }
2473
2474 // For the rest of idle, we want to cap at the max sim rate, so we might not call
2475 // the remaining idle work every paint frame, or vice versa
2476 // In theory this means we could call idle processing more often than painting,
2477 // but in practice, when the paintGL calls aren't keeping up, there's no room left
2478 // in the main thread to call idle more often than paint.
2479 // This check is mostly to keep idle from burning up CPU cycles by running at
2480 // hundreds of idles per second when the rendering is that fast
2481 if ((timeSinceLastUpdateUs / USECS_PER_MSEC) < CAPPED_SIM_FRAME_PERIOD_MS) {
2482 // No paint this round, but might be time for a new idle, otherwise return
2483 return;2468 return;
2484 }2469 }
2485 2470