From 54877cdd47d837950bd0b65f4abb225c4d6f9a65 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 26 Aug 2015 11:59:12 -0700 Subject: [PATCH] Use GenericThread, and use usleep instead of QTimer (which is incompatible with GenericThread). --- interface/src/avatar/AvatarUpdate.cpp | 83 +++++++-------------------- interface/src/avatar/AvatarUpdate.h | 40 +++---------- 2 files changed, 29 insertions(+), 94 deletions(-) diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 7f5131f94b..9c6f4a6f25 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -24,50 +24,22 @@ // As it turns out, all the other subclasses of GenericThread (at this time) do not init // GenericThread(parent), so things work as expected. Here we explicitly init GenericThread(nullptr) // so that there is no confusion and no chance for a hillarious thread debugging session. -AvatarUpdate::AvatarUpdate() : QObject(nullptr), _lastAvatarUpdate(0), _timer(nullptr), _thread(nullptr)/*FIXME remove*/ { +AvatarUpdate::AvatarUpdate() : GenericThread(nullptr), _lastAvatarUpdate(0)/*, _timer(nullptr), _thread(nullptr)FIXME remove*/ { setObjectName("Avatar Update"); // GenericThread::initialize uses this to set the thread name. Settings settings; const int DEFAULT_TARGET_AVATAR_SIMRATE = 60; _targetInterval = USECS_PER_SECOND / settings.value("AvatarUpdateTargetSimrate", DEFAULT_TARGET_AVATAR_SIMRATE).toInt(); - _type = settings.value("AvatarUpdateType", UpdateType::Synchronous).toInt(); - qCDebug(interfaceapp) << "AvatarUpdate using" << _type << "at" << _targetInterval << "microseconds"; + _isToBeThreaded = settings.value("AvatarUpdateIsThreaded", true).toBool(); + if (_isToBeThreaded) { + qCDebug(interfaceapp) << "AvatarUpdate threaded at" << _targetInterval << "microsecond interval."; + } else { + qCDebug(interfaceapp) << "AvatarUpdate unthreaded."; + } } // We could have the constructor call initialize(), but GenericThread::initialize can take parameters. // Keeping it separately called by the client allows that client to pass those without our // constructor needing to know about them. -// GenericThread::terimate() calls terminating() only when _isThreaded, so it's not good enough -// to just override terminating(). Instead, we extend terminate(); -void AvatarUpdate::terminate() { - if (_timer) { - _timer->stop(); - } - // FIXME: GenericThread::terminate(); - if (_thread) { - _thread->quit(); - } -} - -// QTimer runs in the thread that starts it. -// threadRoutine() is called once within the separate thread (if any), -// or on each main loop update via synchronousProcess(); -void AvatarUpdate::threadRoutine() { - if (!_timer && (_type != UpdateType::Synchronous)) { - initTimer(); - } - if (!_timer) { - process(); - } -} -void AvatarUpdate::initTimer() { - _timer = new QTimer(this); - /*FIXME connect(_timer, &QTimer::timeout, this, &AvatarUpdate::process); - _timer->start(_targetInterval / USECS_PER_MSEC);*/ - while (true) { - process(); - } -} - void AvatarUpdate::synchronousProcess() { // Keep our own updated value, so that our asynchronous code can consult it. @@ -78,14 +50,17 @@ void AvatarUpdate::synchronousProcess() { Application::getInstance()->getMyAvatar()->doUpdateBillboard(); } - //threadRoutine(); - //process(); //fixme + if (isThreaded()) { + return; + } + process(); } bool AvatarUpdate::process() { PerformanceTimer perfTimer("AvatarUpdate"); quint64 start = usecTimestampNow(); quint64 deltaMicroseconds = start - _lastAvatarUpdate; + _lastAvatarUpdate = start; float deltaSeconds = deltaMicroseconds / (float) USECS_PER_SECOND; Application::getInstance()->setAvatarSimrateSample(1.0f / deltaSeconds); @@ -96,29 +71,15 @@ bool AvatarUpdate::process() { Application::getInstance()->updateMyAvatarLookAtPosition(); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes DependencyManager::get()->updateMyAvatar(deltaSeconds); - - if (isToBeThreaded()) { - int elapsed = (usecTimestampNow() - start); - int usecToSleep = _targetInterval - elapsed; - if (usecToSleep < 0) { - usecToSleep = 1; // always yield - } - usleep(usecToSleep); - } - _lastAvatarUpdate = start; + + if (!isThreaded()) { + return true; + } + int elapsed = (usecTimestampNow() - start); + int usecToSleep = _targetInterval - elapsed; + if (usecToSleep < 0) { + usecToSleep = 1; // always yield + } + usleep(usecToSleep); return true; } - -// To be removed with GenericThread -void AvatarUpdate::initialize(bool isThreaded) { //fixme remove - if (isThreaded) { - initThread(); - } -} -void AvatarUpdate::initThread() { - _thread = new QThread(); - _thread->setObjectName(objectName()); - this->moveToThread(_thread); - connect(_thread, &QThread::started, this, &AvatarUpdate::threadRoutine); - _thread->start(); -} diff --git a/interface/src/avatar/AvatarUpdate.h b/interface/src/avatar/AvatarUpdate.h index fc2f540111..8e3448c533 100644 --- a/interface/src/avatar/AvatarUpdate.h +++ b/interface/src/avatar/AvatarUpdate.h @@ -15,50 +15,24 @@ #include #include -// There are a couple of ways we could do this. -// Right now, the goals are: -// 1. allow development to switch between UpdateType -// e.g.: see uses of UpdateType. -// 2. minimize changes everwhere, particularly outside of Avatars. -// e.g.: we could make Application::isHMDMode() thread safe, but for now we just made AvatarUpdate::isHMDMode() thread safe. - - // Home for the avatarUpdate operations (e.g., whether on a separate thread, pipelined in various ways, etc.) // This might get folded into AvatarManager. -class AvatarUpdate : public QObject { +class AvatarUpdate : public GenericThread { Q_OBJECT public: AvatarUpdate(); void synchronousProcess(); void setRequestBillboardUpdate(bool needsUpdate) { _updateBillboard = needsUpdate; } - void terminate(); // Extends GenericThread::terminate to also kill timer. + bool isToBeThreaded() { return _isToBeThreaded; } private: virtual bool process(); // No reason for other classes to invoke this. - void initTimer(); - quint64 _targetInterval; // microseconds - bool _updateBillboard; quint64 _lastAvatarUpdate; // microsoeconds - - // Goes away when we get rid of the ability to switch back and forth in settings: - enum UpdateType { - Synchronous = 1, - Timer, - Thread - }; - int _type; -public: - bool isToBeThreaded() const { return _type == UpdateType::Thread; } // Currently set by constructor from settings. - void threadRoutine(); - - // Goes away when using GenericThread: - void initialize(bool isThreaded); -private: - QTimer* _timer; - QThread* _thread; - void initThread(); - - // Goes away if Applicaiton::isHMDMode() and friends are made thread safe: + quint64 _targetInterval; // microseconds + bool _isToBeThreaded; + bool _updateBillboard; + + // Goes away if Application::getActiveDisplayPlugin() and friends are made thread safe: public: bool isHMDMode() { return _isHMDMode; } glm::mat4 getHeadPose() { return _headPose; }