History

Merge branch 'master' of https://github.com/highfidelity/hifi into red

samcake committed 10 years ago

Commit 545f2762 parents 21c9b74 376c23f65 files · +732 −274Browse files

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

Unified · Split

interface/src/Application.cpp+71−26
@@ -210,6 +210,10 @@ 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 = 60;
214static const int CAPPED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / CAPPED_SIM_FRAMERATE;
215
216static const uint32_t INVALID_FRAME = UINT32_MAX;
213 217
214static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation218static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation
215 219
@@ -273,7 +277,8 @@ public: · 57 unmodified lines
273#endif277#endif
274 278
275enum CustomEventTypes {279enum CustomEventTypes {
276 Lambda = QEvent::User + 1280 Lambda = QEvent::User + 1,
281 Paint = Lambda + 1,
277};282};
278 283
279class LambdaEvent : public QEvent {284class LambdaEvent : public QEvent {
@@ -984,6 +989,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 704 unmodified lines
984 989
985 connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);990 connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
986 qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);991 qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
992 _idleTimer = new QTimer(this);
993 connect(_idleTimer, &QTimer::timeout, [=] {
994 idle(usecTimestampNow());
995 });
996 connect(this, &Application::beforeAboutToQuit, [=] {
997 disconnect(_idleTimer);
998 });
999 // Setting the interval to zero forces this to get called whenever there are no messages
1000 // in the queue, which can be pretty damn frequent. Hence the idle function has a bunch
1001 // of logic to abort early if it's being called too often.
1002 _idleTimer->start(0);
987}1003}
988 1004
989void Application::aboutToQuit() {1005void Application::aboutToQuit() {
@@ -1297,9 +1313,6 @@ void Application::initializeUi() { · 307 unmodified lines
1297}1313}
1298 1314
1299void Application::paintGL() {1315void Application::paintGL() {
1300
1301
1302
1303 // paintGL uses a queued connection, so we can get messages from the queue even after we've quit1316 // paintGL uses a queued connection, so we can get messages from the queue even after we've quit
1304 // and the plugins have shutdown1317 // and the plugins have shutdown
1305 if (_aboutToQuit) {1318 if (_aboutToQuit) {
@@ -1629,6 +1642,7 @@ void Application::paintGL() { · 323 unmodified lines
1629 // Store both values now for use by next cycle.1642 // Store both values now for use by next cycle.
1630 _lastInstantaneousFps = instantaneousFps;1643 _lastInstantaneousFps = instantaneousFps;
1631 _lastUnsynchronizedFps = 1.0f / (((usecTimestampNow() - now) / (float)USECS_PER_SECOND) + paintWaitAndQTTimerAllowance);1644 _lastUnsynchronizedFps = 1.0f / (((usecTimestampNow() - now) / (float)USECS_PER_SECOND) + paintWaitAndQTTimerAllowance);
1645 _pendingPaint = false;
1632}1646}
1633 1647
1634void Application::runTests() {1648void Application::runTests() {
@@ -1717,6 +1731,10 @@ bool Application::event(QEvent* event) { · 82 unmodified lines
1717 return true;1731 return true;
1718 }1732 }
1719 1733
1734 if ((int)event->type() == (int)Paint) {
1735 paintGL();
1736 }
1737
1720 if (!_keyboardFocusedItem.isInvalidID()) {1738 if (!_keyboardFocusedItem.isInvalidID()) {
1721 switch (event->type()) {1739 switch (event->type()) {
1722 case QEvent::KeyPress:1740 case QEvent::KeyPress:
@@ -2401,26 +2419,62 @@ bool Application::acceptSnapshot(const QString& urlString) { · 678 unmodified lines
2401 return true;2419 return true;
2402}2420}
2403 2421
2422static uint32_t _renderedFrameIndex { INVALID_FRAME };
2423
2404void Application::idle(uint64_t now) {2424void Application::idle(uint64_t now) {
2405 if (_aboutToQuit) {2425 if (_aboutToQuit) {
2406 return; // bail early, nothing to do here.2426 return; // bail early, nothing to do here.
2407 }2427 }
2408 2428
2429 auto displayPlugin = getActiveDisplayPlugin();
2409 // depending on whether we're throttling or not.2430 // depending on whether we're throttling or not.
2410 // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in2431 // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
2411 // perpetuity and not expect events to get backed up.2432 // perpetuity and not expect events to get backed up.
2412 bool isThrottled = getActiveDisplayPlugin()->isThrottled();2433 bool isThrottled = displayPlugin->isThrottled();
2413 // Only run simulation code if more than the targetFramePeriod have passed since last time we ran2434 // Only run simulation code if more than the targetFramePeriod have passed since last time we ran
2414 // This attempts to lock the simulation at 60 updates per second, regardless of framerate2435 // This attempts to lock the simulation at 60 updates per second, regardless of framerate
2415 float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC;2436 float timeSinceLastUpdateUs = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_USEC;
2416 float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND;2437 float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND;
2417 2438
2418 if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) {2439 if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) {
2440 // Throttling both rendering and idle
2419 return; // bail early, we're throttled and not enough time has elapsed2441 return; // bail early, we're throttled and not enough time has elapsed
2420 }2442 }
2421 2443
2422 _lastTimeUpdated.start();2444 auto presentCount = displayPlugin->presentCount();
2445 if (presentCount < _renderedFrameIndex) {
2446 _renderedFrameIndex = INVALID_FRAME;
2447 }
2448
2449 // Nested ifs are for clarity in the logic. Don't collapse them into a giant single if.
2450 // Don't saturate the main thread with rendering, no paint calls until the last one is complete
2451 if (!_pendingPaint) {
2452 // Also no paint calls until the display plugin has increased by at least one frame
2453 // (don't render at 90fps if the display plugin only goes at 60)
2454 if (_renderedFrameIndex == INVALID_FRAME || presentCount > _renderedFrameIndex) {
2455 // Record what present frame we're on
2456 _renderedFrameIndex = presentCount;
2457 // Don't allow paint requests to stack up in the event queue
2458 _pendingPaint = true;
2459 // But when we DO request a paint, get to it as soon as possible: high priority
2460 postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
2461 }
2462 }
2463
2464 // For the rest of idle, we want to cap at the max sim rate, so we might not call
2465 // the remaining idle work every paint frame, or vice versa
2466 // In theory this means we could call idle processing more often than painting,
2467 // but in practice, when the paintGL calls aren't keeping up, there's no room left
2468 // in the main thread to call idle more often than paint.
2469 // This check is mostly to keep idle from burning up CPU cycles by running at
2470 // hundreds of idles per second when the rendering is that fast
2471 if ((timeSinceLastUpdateUs / USECS_PER_MSEC) < CAPPED_SIM_FRAME_PERIOD_MS) {
2472 // No paint this round, but might be time for a new idle, otherwise return
2473 return;
2474 }
2423 2475
2476 // We're going to execute idle processing, so restart the last idle timer
2477 _lastTimeUpdated.start();
2424 2478
2425 {2479 {
2426 PROFILE_RANGE(__FUNCTION__);2480 PROFILE_RANGE(__FUNCTION__);
@@ -3071,13 +3125,18 @@ void Application::update(float deltaTime) { · 644 unmodified lines
3071 3125
3072 auto myAvatar = getMyAvatar();3126 auto myAvatar = getMyAvatar();
3073 auto userInputMapper = DependencyManager::get<UserInputMapper>();3127 auto userInputMapper = DependencyManager::get<UserInputMapper>();
3074 userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix());
3075 userInputMapper->update(deltaTime);3128 userInputMapper->update(deltaTime);
3076 3129
3130 controller::InputCalibrationData calibrationData = {
3131 myAvatar->getSensorToWorldMatrix(),
3132 createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()),
3133 myAvatar->getHMDSensorMatrix()
3134 };
3135
3077 bool jointsCaptured = false;3136 bool jointsCaptured = false;
3078 for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {3137 for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
3079 if (inputPlugin->isActive()) {3138 if (inputPlugin->isActive()) {
3080 inputPlugin->pluginUpdate(deltaTime, jointsCaptured);3139 inputPlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured);
3081 if (inputPlugin->isJointController()) {3140 if (inputPlugin->isJointController()) {
3082 jointsCaptured = true;3141 jointsCaptured = true;
3083 }3142 }
@@ -4777,17 +4836,9 @@ void Application::updateDisplayMode() { · 1693 unmodified lines
4777 4836
4778 foreach(auto displayPlugin, standard) {4837 foreach(auto displayPlugin, standard) {
4779 addDisplayPluginToMenu(displayPlugin, first);4838 addDisplayPluginToMenu(displayPlugin, first);
4780 // This must be a queued connection to avoid a deadlock
4781 QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, [=] {
4782 postEvent(this, new LambdaEvent([=] {
4783 paintGL();
4784 }), Qt::HighEventPriority);
4785 });
4786
4787 QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) {4839 QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) {
4788 resizeGL();4840 resizeGL();
4789 });4841 });
4790
4791 first = false;4842 first = false;
4792 }4843 }
4793 4844
@@ -4979,17 +5030,11 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de · 185 unmodified lines
4979 // of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about5030 // of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about
4980 // controller::Pose. More work is needed to clean this up.5031 // controller::Pose. More work is needed to clean this up.
4981 hand->modifyPalm(whichHand, [&](PalmData& palm) {5032 hand->modifyPalm(whichHand, [&](PalmData& palm) {
4982 auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
4983 palm.setActive(pose.isValid());5033 palm.setActive(pose.isValid());
4984 5034
4985 // transform from sensor space, to world space, to avatar model space.5035 // controller pose is in Avatar frame.
4986 glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation() * myAvatar->getScale());5036 glm::vec3 position = pose.getTranslation();
4987 glm::mat4 sensorToWorldMat = myAvatar->getSensorToWorldMatrix();5037 glm::quat rotation = pose.getRotation();
4988 glm::mat4 modelMat = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());
4989 glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
4990
4991 glm::vec3 position = extractTranslation(objectPose);
4992 glm::quat rotation = glm::quat_cast(objectPose);
4993 5038
4994 // Compute current velocity from position change5039 // Compute current velocity from position change
4995 glm::vec3 rawVelocity;5040 glm::vec3 rawVelocity;