History

Merge branch 'master' of github.com:highfidelity/hifi into avatar-entities-3

Seth Alves committed 10 years ago

Commit 3380b2a2 parents 880b52a 8e3b31a24 files · +472 −395Browse files

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

Unified · Split

interface/src/Application.cpp+67−79
@@ -349,19 +349,14 @@ public: · 348 unmodified lines
349349 };
350350 #endif
351351
352−enum CustomEventTypes {
353− Lambda = QEvent::User + 1,
354− Paint = Lambda + 1,
355−};
356−
357352 class LambdaEvent : public QEvent {
358353 std::function<void()> _fun;
359354 public:
360355 LambdaEvent(const std::function<void()> & fun) :
361− QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {
356+ QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) {
362357 }
363358 LambdaEvent(std::function<void()> && fun) :
364− QEvent(static_cast<QEvent::Type>(Lambda)), _fun(fun) {
359+ QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) {
365360 }
366361 void call() const { _fun(); }
367362 };
@@ -1062,18 +1057,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 694 unmodified lines
10621057 connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
10631058 qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
10641059
1065− _idleTimer = new QTimer(this);
1066− connect(_idleTimer, &QTimer::timeout, [=] {
1067− idle(usecTimestampNow());
1068− });
1069− connect(this, &Application::beforeAboutToQuit, [=] {
1070− disconnect(_idleTimer);
1071− });
1072− // Setting the interval to zero forces this to get called whenever there are no messages
1073− // in the queue, which can be pretty damn frequent. Hence the idle function has a bunch
1074− // of logic to abort early if it's being called too often.
1075− _idleTimer->start(0);
1076−
10771060 // After all of the constructor is completed, then set firstRun to false.
10781061 Setting::Handle<bool> firstRun{ Settings::firstRun, true };
10791062 firstRun.set(false);
@@ -1161,10 +1144,16 @@ void Application::cleanupBeforeQuit() { · 81 unmodified lines
11611144
11621145 getEntities()->shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
11631146
1147+ // Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
1148+ QThreadPool::globalInstance()->clear();
1149+
11641150 DependencyManager::get<ScriptEngines>()->saveScripts();
11651151 DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts
11661152 DependencyManager::destroy<ScriptEngines>();
11671153
1154+ // Cleanup all overlays after the scripts, as scripts might add more
1155+ _overlays.cleanupAllOverlays();
1156+
11681157 // first stop all timers directly or by invokeMethod
11691158 // depending on what thread they run in
11701159 locationUpdateTimer.stop();
@@ -1440,23 +1429,15 @@ void Application::initializeUi() { · 269 unmodified lines
14401429 });
14411430 }
14421431
1443−
14441432 void Application::paintGL() {
1445− updateHeartbeat();
1446− // Some plugins process message events, potentially leading to
1447− // re-entering a paint event. don't allow further processing if this
1448− // happens
1449− if (_inPaint) {
1433+ // Some plugins process message events, allowing paintGL to be called reentrantly.
1434+ if (_inPaint || _aboutToQuit) {
14501435 return;
14511436 }
1437+
14521438 _inPaint = true;
1453− Finally clearFlagLambda([this] { _inPaint = false; });
1439+ Finally clearFlag([this] { _inPaint = false; });
14541440
1455− // paintGL uses a queued connection, so we can get messages from the queue even after we've quit
1456− // and the plugins have shutdown
1457− if (_aboutToQuit) {
1458− return;
1459− }
14601441 _frameCount++;
14611442 _frameCounter.increment();
14621443
@@ -1814,13 +1795,30 @@ bool Application::event(QEvent* event) { · 351 unmodified lines
18141795 return false;
18151796 }
18161797
1817− if ((int)event->type() == (int)Lambda) {
1818− static_cast<LambdaEvent*>(event)->call();
1798+ static bool justPresented = false;
1799+ if ((int)event->type() == (int)Present) {
1800+ if (justPresented) {
1801+ justPresented = false;
1802+
1803+ // If presentation is hogging the main thread, repost as low priority to avoid hanging the GUI.
1804+ // This has the effect of allowing presentation to exceed the paint budget by X times and
1805+ // only dropping every (1/X) frames, instead of every ceil(X) frames.
1806+ // (e.g. at a 60FPS target, painting for 17us would fall to 58.82FPS instead of 30FPS).
1807+ removePostedEvents(this, Present);
1808+ postEvent(this, new QEvent(static_cast<QEvent::Type>(Present)), Qt::LowEventPriority);
1809+ return true;
1810+ }
1811+
1812+ idle();
1813+ return true;
1814+ } else if ((int)event->type() == (int)Paint) {
1815+ justPresented = true;
1816+ paintGL();
18191817 return true;
18201818 }
18211819
1822− if ((int)event->type() == (int)Paint) {
1823− paintGL();
1820+ if ((int)event->type() == (int)Lambda) {
1821+ static_cast<LambdaEvent*>(event)->call();
18241822 return true;
18251823 }
18261824
@@ -2598,72 +2596,63 @@ bool Application::acceptSnapshot(const QString& urlString) { · 771 unmodified lines
25982596
25992597 static uint32_t _renderedFrameIndex { INVALID_FRAME };
26002598
2601−void Application::idle(uint64_t now) {
2602− // NOTICE NOTICE NOTICE NOTICE
2603− // Do not insert new code between here and the PROFILE_RANGE declaration
2604− // unless you know exactly what you're doing. This idle function can be
2605− // called thousands per second or more, so any additional work that's done
2606− // here will have a serious impact on CPU usage. Only add code after all
2607− // the thottling logic, i.e. after PROFILE_RANGE
2608− // NOTICE NOTICE NOTICE NOTICE
2609− updateHeartbeat();
2610−
2611− if (_aboutToQuit || _inPaint) {
2612− return; // bail early, nothing to do here.
2599+void Application::idle() {
2600+ // idle is called on a queued connection, so make sure we should be here.
2601+ if (_inPaint || _aboutToQuit) {
2602+ return;
26132603 }
26142604
26152605 auto displayPlugin = getActiveDisplayPlugin();
2616− // depending on whether we're throttling or not.
2617− // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
2618− // perpetuity and not expect events to get backed up.
2619− bool isThrottled = displayPlugin->isThrottled();
2620− // Only run simulation code if more than the targetFramePeriod have passed since last time we ran
2621− // This attempts to lock the simulation at 60 updates per second, regardless of framerate
2622− float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC;
2623− float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND;
26242606
2625− if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) {
2626− // Throttling both rendering and idle
2627− return; // bail early, we're throttled and not enough time has elapsed
2628− }
2607+#ifdef DEBUG_PAINT_DELAY
2608+ static uint64_t paintDelaySamples{ 0 };
2609+ static uint64_t paintDelayUsecs{ 0 };
2610+
2611+ paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
26292612
2630− auto presentCount = displayPlugin->presentCount();
2631− if (presentCount < _renderedFrameIndex) {
2632− _renderedFrameIndex = INVALID_FRAME;
2613+ static const int PAINT_DELAY_THROTTLE = 1000;
2614+ if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
2615+ qCDebug(interfaceapp).nospace() <<
2616+ "Paint delay (" << paintDelaySamples << " samples): " <<
2617+ (float)paintDelaySamples / paintDelayUsecs << "us";
26332618 }
2619+#endif
26342620
2635− // Don't saturate the main thread with rendering and simulation,
2636− // unless display plugin has increased by at least one frame
2637− if (_renderedFrameIndex == INVALID_FRAME || presentCount > _renderedFrameIndex) {
2638− // Record what present frame we're on
2639− _renderedFrameIndex = presentCount;
2621+ float msecondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC / USECS_PER_MSEC;
26402622
2641− // request a paint, get to it as soon as possible: high priority
2642− postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
2643− } else {
2644− // there's no use in simulating or rendering faster then the present rate.
2623+ // Throttle if requested
2624+ if (displayPlugin->isThrottled() && (msecondsSinceLastUpdate < THROTTLED_SIM_FRAME_PERIOD_MS)) {
26452625 return;
26462626 }
26472627
2648− // NOTICE NOTICE NOTICE NOTICE
2649− // do NOT add new code above this line unless you want it to be executed potentially
2650− // thousands of times per second
2651− // NOTICE NOTICE NOTICE NOTICE
2628+ // Sync up the _renderedFrameIndex
2629+ _renderedFrameIndex = displayPlugin->presentCount();
26522630
2653− PROFILE_RANGE(__FUNCTION__);
2631+ // Request a paint ASAP
2632+ postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority + 1);
2633+
2634+ // Update the deadlock watchdog
2635+ updateHeartbeat();
2636+
2637+ auto offscreenUi = DependencyManager::get<OffscreenUi>();
26542638
26552639 // These tasks need to be done on our first idle, because we don't want the showing of
26562640 // overlay subwindows to do a showDesktop() until after the first time through
26572641 static bool firstIdle = true;
26582642 if (firstIdle) {
26592643 firstIdle = false;
2660− auto offscreenUi = DependencyManager::get<OffscreenUi>();
26612644 connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
26622645 _overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays));
2646+ } else {
2647+ // FIXME: AvatarInputs are positioned incorrectly if instantiated before the first paint
2648+ AvatarInputs::getInstance()->update();
26632649 }
26642650
2651+ PROFILE_RANGE(__FUNCTION__);
2652+
2653+ float secondsSinceLastUpdate = msecondsSinceLastUpdate / MSECS_PER_SECOND;
2654+
26652655 // If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
2666− auto offscreenUi = DependencyManager::get<OffscreenUi>();
26672656 if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
26682657 _keyboardMouseDevice->pluginFocusOutEvent();
26692658 _keyboardDeviceHasFocus = false;
@@ -2679,7 +2668,6 @@ void Application::idle(uint64_t now) { · 9 unmodified lines
26792668 checkChangeCursor();
26802669
26812670 Stats::getInstance()->updateStats();
2682− AvatarInputs::getInstance()->update();
26832671
26842672 _simCounter.increment();
26852673