From 8006719fda737e7f10ac35758ca04b2e9427755e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:42:23 -0700 Subject: [PATCH 01/51] add new stats to OctreeServer --- assignment-client/src/octree/OctreeServer.cpp | 29 +++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 12 ++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c31beb7831..6c9e5cf70c 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -20,10 +20,13 @@ OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; -SimpleMovingAverage OctreeServer::_averageLoopTime(10000); -SimpleMovingAverage OctreeServer::_averageEncodeTime(10000); -SimpleMovingAverage OctreeServer::_averageTreeWaitTime(10000); -SimpleMovingAverage OctreeServer::_averageNodeWaitTime(10000); +SimpleMovingAverage OctreeServer::_averageLoopTime(100000); +SimpleMovingAverage OctreeServer::_averageEncodeTime(100000); +SimpleMovingAverage OctreeServer::_averageInsideTime(100000); +SimpleMovingAverage OctreeServer::_averageTreeWaitTime(100000); +SimpleMovingAverage OctreeServer::_averageNodeWaitTime(100000); +SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(100000); +SimpleMovingAverage OctreeServer::_averagePacketSendingTime(100000); void OctreeServer::attachQueryNodeToNode(Node* newNode) { if (!newNode->getLinkedData()) { @@ -276,9 +279,20 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& qDebug() << "averageLoopTime=" << averageLoopTime; float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %5.2f msecs\r\n", averageEncodeTime); + statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); qDebug() << "averageEncodeTime=" << averageEncodeTime; + float averageInsideTime = getAverageInsideTime(); + statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); + qDebug() << "averageInsideTime=" << averageInsideTime; + + float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); + statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); + qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; + + float averagePacketSendingTime = getAveragePacketSendingTime(); + statsString += QString().sprintf(" Average packet sending time: %7.2f usecs\r\n", averagePacketSendingTime); + qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; float averageTreeWaitTime = getAverageTreeWaitTime(); statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); @@ -288,6 +302,11 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; + float encodeToInsidePercent = (averageEncodeTime / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" Percent 'inside' time is encode: %5.2f%%\r\n", encodeToInsidePercent); + qDebug() << "averageInsideTime=" << averageInsideTime; + + statsString += QString("\r\n"); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 94dcf18dc8..022da9d658 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -80,11 +80,20 @@ public: static void trackEncodeTime(float time) { _averageEncodeTime.updateAverage(time); } static float getAverageEncodeTime() { return _averageEncodeTime.getAverage(); } + static void trackInsideTime(float time) { _averageInsideTime.updateAverage(time); } + static float getAverageInsideTime() { return _averageInsideTime.getAverage(); } + static void trackTreeWaitTime(float time) { _averageTreeWaitTime.updateAverage(time); } static float getAverageTreeWaitTime() { return _averageTreeWaitTime.getAverage(); } static void trackNodeWaitTime(float time) { _averageNodeWaitTime.updateAverage(time); } static float getAverageNodeWaitTime() { return _averageNodeWaitTime.getAverage(); } + static void trackCompressAndWriteTime(float time) { _averageCompressAndWriteTime.updateAverage(time); } + static float getAverageCompressAndWriteTime() { return _averageCompressAndWriteTime.getAverage(); } + + static void trackPacketSendingTime(float time) { _averagePacketSendingTime.updateAverage(time); } + static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } + bool handleHTTPRequest(HTTPConnection* connection, const QString& path); public slots: /// runs the voxel server assignment @@ -124,8 +133,11 @@ protected: static int _clientCount; static SimpleMovingAverage _averageLoopTime; static SimpleMovingAverage _averageEncodeTime; + static SimpleMovingAverage _averageInsideTime; static SimpleMovingAverage _averageTreeWaitTime; static SimpleMovingAverage _averageNodeWaitTime; + static SimpleMovingAverage _averageCompressAndWriteTime; + static SimpleMovingAverage _averagePacketSendingTime; }; #endif // __octree_server__OctreeServer__ From 8afbcae3657e714723e2423bc3f2c2c0e5bcc85f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:43:11 -0700 Subject: [PATCH 02/51] tweak to seeing load test --- examples/seeingVoxelsExample.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/seeingVoxelsExample.js b/examples/seeingVoxelsExample.js index 62ebd599ee..65907bde40 100644 --- a/examples/seeingVoxelsExample.js +++ b/examples/seeingVoxelsExample.js @@ -13,6 +13,7 @@ var yawDirection = -1; var yaw = 45; var yawMax = 70; var yawMin = 20; +var vantagePoint = {x: 5000, y: 500, z: 5000}; var isLocal = false; @@ -21,10 +22,10 @@ var orientation = Quat.fromPitchYawRoll(0, yaw, 0); function init() { if (isLocal) { - MyAvatar.position = {x: 5000, y: 500, z: 5000}; + MyAvatar.position = vantagePoint; MyAvatar.orientation = orientation; } else { - VoxelViewer.setPosition({x: 5000, y: 500, z: 5000}); + VoxelViewer.setPosition(vantagePoint); VoxelViewer.setOrientation(orientation); VoxelViewer.queryOctree(); Agent.isAvatar = true; From 1f88ede1aa287a0b4e70a60c5bc7b859f0edb144 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:47:50 -0700 Subject: [PATCH 03/51] switch OctreeElementBag to use QSet as it's underlying data store --- libraries/octree/src/OctreeElementBag.cpp | 138 +++++----------------- libraries/octree/src/OctreeElementBag.h | 10 +- 2 files changed, 32 insertions(+), 116 deletions(-) diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp index c3ad44a604..3ecdfaf2e3 100644 --- a/libraries/octree/src/OctreeElementBag.cpp +++ b/libraries/octree/src/OctreeElementBag.cpp @@ -10,9 +10,8 @@ #include OctreeElementBag::OctreeElementBag() : - _bagElements(NULL), - _elementsInUse(0), - _sizeOfElementsArray(0) { + _bagElements() +{ OctreeElement::addDeleteHook(this); }; @@ -21,114 +20,35 @@ OctreeElementBag::~OctreeElementBag() { deleteAll(); } -void OctreeElementBag::deleteAll() { - if (_bagElements) { - delete[] _bagElements; - } - _bagElements = NULL; - _elementsInUse = 0; - _sizeOfElementsArray = 0; -} - - -const int GROW_BAG_BY = 100; - -// put a node into the bag -void OctreeElementBag::insert(OctreeElement* element) { - - // Search for where we should live in the bag (sorted) - // Note: change this to binary search... instead of linear! - int insertAt = _elementsInUse; - for (int i = 0; i < _elementsInUse; i++) { - // just compare the pointers... that's good enough - if (_bagElements[i] == element) { - return; // exit early!! - } - - if (_bagElements[i] > element) { - insertAt = i; - break; - } - } - // at this point, inserAt will be the location we want to insert at. - - // If we don't have room in our bag, then grow the bag - if (_sizeOfElementsArray < _elementsInUse + 1) { - OctreeElement** oldBag = _bagElements; - _bagElements = new OctreeElement*[_sizeOfElementsArray + GROW_BAG_BY]; - _sizeOfElementsArray += GROW_BAG_BY; - - // If we had an old bag... - if (oldBag) { - // copy old elements into the new bag, but leave a space where we need to - // insert the new node - memcpy(_bagElements, oldBag, insertAt * sizeof(OctreeElement*)); - memcpy(&_bagElements[insertAt + 1], &oldBag[insertAt], (_elementsInUse - insertAt) * sizeof(OctreeElement*)); - delete[] oldBag; - } - } else { - // move existing elements further back in the bag array, leave a space where we need to - // insert the new node - memmove(&_bagElements[insertAt + 1], &_bagElements[insertAt], (_elementsInUse - insertAt) * sizeof(OctreeElement*)); - } - _bagElements[insertAt] = element; - _elementsInUse++; -} - -// pull a node out of the bag (could come in any order) -OctreeElement* OctreeElementBag::extract() { - // pull the last node out, and shrink our list... - if (_elementsInUse) { - - // get the last element - OctreeElement* element = _bagElements[_elementsInUse - 1]; - - // reduce the count - _elementsInUse--; - - return element; - } - return NULL; -} - -bool OctreeElementBag::contains(OctreeElement* element) { - for (int i = 0; i < _elementsInUse; i++) { - // just compare the pointers... that's good enough - if (_bagElements[i] == element) { - return true; // exit early!! - } - // if we're past where it should be, then it's not here! - if (_bagElements[i] > element) { - return false; - } - } - // if we made it through the entire bag, it's not here! - return false; -} - -void OctreeElementBag::remove(OctreeElement* element) { - int foundAt = -1; - for (int i = 0; i < _elementsInUse; i++) { - // just compare the pointers... that's good enough - if (_bagElements[i] == element) { - foundAt = i; - break; - } - // if we're past where it should be, then it's not here! - if (_bagElements[i] > element) { - break; - } - } - // if we found it, then we need to remove it.... - if (foundAt != -1) { - memmove(&_bagElements[foundAt], &_bagElements[foundAt + 1], (_elementsInUse - foundAt) * sizeof(OctreeElement*)); - _elementsInUse--; - } -} - - void OctreeElementBag::elementDeleted(OctreeElement* element) { remove(element); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() } +void OctreeElementBag::deleteAll() { + _bagElements.clear(); +} + + +void OctreeElementBag::insert(OctreeElement* element) { + _bagElements.insert(element); +} + +OctreeElement* OctreeElementBag::extract() { + OctreeElement* result = NULL; + + if (_bagElements.size() > 0) { + QSet::iterator front = _bagElements.begin(); + result = *front; + _bagElements.erase(front); + } + return result; +} + +bool OctreeElementBag::contains(OctreeElement* element) { + return _bagElements.contains(element); +} + +void OctreeElementBag::remove(OctreeElement* element) { + _bagElements.remove(element); +} diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index a952b52095..ba74a05516 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -27,18 +27,14 @@ public: bool contains(OctreeElement* element); // is this element in the bag? void remove(OctreeElement* element); // remove a specific element from the bag - bool isEmpty() const { return (_elementsInUse == 0); } - int count() const { return _elementsInUse; } + bool isEmpty() const { return _bagElements.isEmpty(); } + int count() const { return _bagElements.size(); } void deleteAll(); virtual void elementDeleted(OctreeElement* element); private: - - OctreeElement** _bagElements; - int _elementsInUse; - int _sizeOfElementsArray; - //int _hookID; + QSet _bagElements; }; #endif /* defined(__hifi__OctreeElementBag__) */ From af71359c60077b6831deaf83ffa6b456325cf32e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:49:33 -0700 Subject: [PATCH 04/51] remove encode/deleting/start/done guards --- libraries/octree/src/Octree.cpp | 66 +-------------------------------- libraries/octree/src/Octree.h | 34 ----------------- 2 files changed, 1 insertion(+), 99 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 4c8ed8c9f6..15c1b62864 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -355,15 +355,7 @@ void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool colla OctreeElement* node = _rootNode; - // We can't encode and delete nodes at the same time, so we guard against deleting any node that is actively - // being encoded. And we stick that code on our pendingDelete list. - if (isEncoding(codeBuffer)) { - queueForLaterDelete(codeBuffer); - } else { - startDeleting(codeBuffer); - deleteOctalCodeFromTreeRecursion(node, &args); - doneDeleting(codeBuffer); - } + deleteOctalCodeFromTreeRecursion(node, &args); } void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraData) { @@ -796,11 +788,8 @@ int Octree::encodeTreeBitstream(OctreeElement* node, return bytesWritten; } - startEncoding(node); - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { - doneEncoding(node); params.stopReason = EncodeBitstreamParams::OUT_OF_VIEW; return bytesWritten; } @@ -824,7 +813,6 @@ int Octree::encodeTreeBitstream(OctreeElement* node, // If the octalcode couldn't fit, then we can return, because no nodes below us will fit... if (!roomForOctalCode) { - doneEncoding(node); bag.insert(node); // add the node back to the bag so it will eventually get included params.stopReason = EncodeBitstreamParams::DIDNT_FIT; return bytesWritten; @@ -867,8 +855,6 @@ int Octree::encodeTreeBitstream(OctreeElement* node, packetData->endSubTree(); } - doneEncoding(node); - return bytesWritten; } @@ -1622,56 +1608,6 @@ void dumpSetContents(const char* name, std::set set) { */ } -void Octree::startEncoding(OctreeElement* node) { - _encodeSetLock.lock(); - _codesBeingEncoded.insert(node->getOctalCode()); - _encodeSetLock.unlock(); -} - -void Octree::doneEncoding(OctreeElement* node) { - _encodeSetLock.lock(); - _codesBeingEncoded.erase(node->getOctalCode()); - _encodeSetLock.unlock(); - - // if we have any pending delete codes, then delete them now. - emptyDeleteQueue(); -} - -void Octree::startDeleting(const unsigned char* code) { - _deleteSetLock.lock(); - _codesBeingDeleted.insert(code); - _deleteSetLock.unlock(); -} - -void Octree::doneDeleting(const unsigned char* code) { - _deleteSetLock.lock(); - _codesBeingDeleted.erase(code); - _deleteSetLock.unlock(); -} - -bool Octree::isEncoding(const unsigned char* codeBuffer) { - _encodeSetLock.lock(); - bool isEncoding = (_codesBeingEncoded.find(codeBuffer) != _codesBeingEncoded.end()); - _encodeSetLock.unlock(); - return isEncoding; -} - -void Octree::queueForLaterDelete(const unsigned char* codeBuffer) { - _deletePendingSetLock.lock(); - _codesPendingDelete.insert(codeBuffer); - _deletePendingSetLock.unlock(); -} - -void Octree::emptyDeleteQueue() { - _deletePendingSetLock.lock(); - for (std::set::iterator i = _codesPendingDelete.begin(); i != _codesPendingDelete.end(); ++i) { - const unsigned char* codeToDelete = *i; - _codesBeingDeleted.erase(codeToDelete); - deleteOctalCodeFromTree(codeToDelete, COLLAPSE_EMPTY_TREE); - } - _deletePendingSetLock.unlock(); -} - void Octree::cancelImport() { _stopImport = true; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 4c237b5f56..6e53e1f240 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -302,40 +302,6 @@ protected: bool _shouldReaverage; bool _stopImport; - /// Octal Codes of any subtrees currently being encoded. While any of these codes is being encoded, ancestors and - /// descendants of them can not be deleted. - std::set _codesBeingEncoded; - /// mutex lock to protect the encoding set - QMutex _encodeSetLock; - - /// Called to indicate that a OctreeElement is in the process of being encoded. - void startEncoding(OctreeElement* node); - /// Called to indicate that a OctreeElement is done being encoded. - void doneEncoding(OctreeElement* node); - /// Is the Octal Code currently being deleted? - bool isEncoding(const unsigned char* codeBuffer); - - /// Octal Codes of any subtrees currently being deleted. While any of these codes is being deleted, ancestors and - /// descendants of them can not be encoded. - std::set _codesBeingDeleted; - /// mutex lock to protect the deleting set - QMutex _deleteSetLock; - - /// Called to indicate that an octal code is in the process of being deleted. - void startDeleting(const unsigned char* code); - /// Called to indicate that an octal code is done being deleted. - void doneDeleting(const unsigned char* code); - /// Octal Codes that were attempted to be deleted but couldn't be because they were actively being encoded, and were - /// instead queued for later delete - std::set _codesPendingDelete; - /// mutex lock to protect the deleting set - QMutex _deletePendingSetLock; - - /// Adds an Octal Code to the set of codes that needs to be deleted - void queueForLaterDelete(const unsigned char* codeBuffer); - /// flushes out any Octal Codes that had to be queued - void emptyDeleteQueue(); - QReadWriteLock _lock; /// This tree is receiving inbound viewer datagrams. From 0d4066a347b66372884fc31b0288e4b2c35385d0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 10:07:26 -0700 Subject: [PATCH 05/51] added note --- libraries/octree/src/ViewFrustum.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index aeffcc4968..66f1445ddc 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -277,6 +277,10 @@ ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const { return keyholeResult; } + // TODO: These calculations are expensive, taking up 80% of our time in this function. + // This appears to be expensive because we have to test the distance to each plane. + // One suggested optimization is to first check against the approximated cone. We might + // also be able to test against the cone to the bounding sphere of the box. for(int i=0; i < 6; i++) { const glm::vec3& normal = _planes[i].getNormal(); const glm::vec3& boxVertexP = box.getVertexP(normal); From 4c39a891be141c305861c2a67f15ee75cb3e13af Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 10:23:07 -0700 Subject: [PATCH 06/51] add more packet sending statistics to server --- .../src/octree/OctreeSendThread.cpp | 44 +++++++++++++++++-- assignment-client/src/octree/OctreeServer.cpp | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index ef69771607..7f75f17252 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -414,6 +414,13 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int extraPackingAttempts = 0; bool completedScene = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { + float lockWaitElapsedUsec = 0.0f; + float encodeElapsedUsec = 0.0f; + float compressAndWriteElapsedUsec = 0.0f; + float packetSendingElapsedUsec = 0.0f; + + quint64 startInside = usecTimestampNow(); + if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d", truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), @@ -442,7 +449,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->lockForRead(); quint64 lockWaitEnd = usecTimestampNow(); - float lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); + lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); nodeData->stats.encodeStarted(); @@ -450,8 +457,8 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); - int encodeElapsedMsec = (encodeEnd - encodeStart)/USECS_PER_MSEC; - OctreeServer::trackEncodeTime(encodeElapsedMsec); + encodeElapsedUsec = (encodeEnd - encodeStart)/USECS_PER_MSEC; + OctreeServer::trackEncodeTime(encodeElapsedUsec); // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've // sent the entire scene. We want to know this below so we'll actually write this content into @@ -491,6 +498,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // mean we should send the previous packet contents and reset it. if (completedScene || lastNodeDidntFit) { if (_packetData.hasContent()) { + + quint64 compressAndWriteStart = usecTimestampNow(); + // if for some reason the finalized size is greater than our available size, then probably the "compressed" // form actually inflated beyond our padding, and in this case we will send the current packet, then // write to out new packet... @@ -514,11 +524,15 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue } nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); extraPackingAttempts = 0; + quint64 compressAndWriteEnd = usecTimestampNow(); + compressAndWriteElapsedUsec = (float)(compressAndWriteEnd - compressAndWriteStart); } // If we're not running compressed, then we know we can just send now. Or if we're running compressed, but // the packet doesn't have enough space to bother attempting to pack more... bool sendNow = true; + + quint64 packetSendingStart = usecTimestampNow(); if (nodeData->getCurrentPacketIsCompressed() && nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && @@ -549,7 +563,27 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue debug::valueOf(nodeData->getWantCompression()), targetSize); } _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset + + quint64 packetSendingEnd = usecTimestampNow(); + packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); } + OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); + OctreeServer::trackEncodeTime(encodeElapsedUsec); + OctreeServer::trackCompressAndWriteTime(compressAndWriteElapsedUsec); + OctreeServer::trackPacketSendingTime(packetSendingElapsedUsec); + + quint64 endInside = usecTimestampNow(); + quint64 elapsedInsideUsecs = endInside - startInside; + OctreeServer::trackInsideTime((float)elapsedInsideUsecs); + + float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; + if (insideMsecs > 1.0f) { + qDebug()<< "inside msecs=" << insideMsecs + << "lockWait usec=" << lockWaitElapsedUsec + << "encode usec=" << encodeElapsedUsec + << "compress usec=" << compressAndWriteElapsedUsec + << "sending usec=" << packetSendingElapsedUsec; + } } @@ -614,6 +648,10 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue } // end if bag wasn't empty, and so we sent stuff... + if (truePacketsSent > 0 || packetsSentThisInterval > 0) { + qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; + } + return truePacketsSent; } diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 6c9e5cf70c..04467c87e6 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -302,7 +302,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; - float encodeToInsidePercent = (averageEncodeTime / averageInsideTime) * AS_PERCENT; + float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; statsString += QString().sprintf(" Percent 'inside' time is encode: %5.2f%%\r\n", encodeToInsidePercent); qDebug() << "averageInsideTime=" << averageInsideTime; From 21458036cc7288a0ae9ddd6bba99787e7df51529 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 10:37:41 -0700 Subject: [PATCH 07/51] clean up formatting of sending stats --- .../src/octree/OctreeSendThread.cpp | 2 +- assignment-client/src/octree/OctreeServer.cpp | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 7f75f17252..ef47b4faef 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -457,7 +457,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); - encodeElapsedUsec = (encodeEnd - encodeStart)/USECS_PER_MSEC; + encodeElapsedUsec = (float)(encodeEnd - encodeStart); OctreeServer::trackEncodeTime(encodeElapsedUsec); // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 04467c87e6..7be8c34087 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -278,33 +278,43 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); qDebug() << "averageLoopTime=" << averageLoopTime; - float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); - qDebug() << "averageEncodeTime=" << averageEncodeTime; - float averageInsideTime = getAverageInsideTime(); statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); qDebug() << "averageInsideTime=" << averageInsideTime; + float averageTreeWaitTime = getAverageTreeWaitTime(); + statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); + qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; + + float averageEncodeTime = getAverageEncodeTime(); + statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); + qDebug() << "averageEncodeTime=" << averageEncodeTime; + float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %7.2f usecs\r\n", averagePacketSendingTime); + statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", + averagePacketSendingTime); + qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; - float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); - qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; - float averageNodeWaitTime = getAverageNodeWaitTime(); statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; + statsString += QString().sprintf("---------------------------------------------------\r\n"); + float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" Percent 'inside' time is encode: %5.2f%%\r\n", encodeToInsidePercent); - qDebug() << "averageInsideTime=" << averageInsideTime; + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + encodeToInsidePercent); + qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; + + float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f + : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + qDebug() << "waitToInsidePercent=" << waitToInsidePercent; From cbdd1592134b5b3c4f5b0b33cfcec447398a6e32 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 10:55:43 -0700 Subject: [PATCH 08/51] fix constness --- libraries/shared/src/SimpleMovingAverage.cpp | 4 ++-- libraries/shared/src/SimpleMovingAverage.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index 5a55486216..f52a8b1c3d 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -44,11 +44,11 @@ void SimpleMovingAverage::reset() { _numSamples = 0; } -float SimpleMovingAverage::getEventDeltaAverage() { +float SimpleMovingAverage::getEventDeltaAverage() const { return (ONE_MINUS_WEIGHTING * _eventDeltaAverage) + (WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000.0f)); } -float SimpleMovingAverage::getAverageSampleValuePerSecond() { +float SimpleMovingAverage::getAverageSampleValuePerSecond() const { return _average * (1 / getEventDeltaAverage()); } \ No newline at end of file diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h index 9788aafe58..f11cd16e58 100644 --- a/libraries/shared/src/SimpleMovingAverage.h +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -20,10 +20,10 @@ public: int updateAverage(float sample); void reset(); - int getSampleCount() { return _numSamples; }; - float getAverage() { return _average; }; - float getEventDeltaAverage(); - float getAverageSampleValuePerSecond(); + int getSampleCount() const { return _numSamples; }; + float getAverage() const { return _average; }; + float getEventDeltaAverage() const; + float getAverageSampleValuePerSecond() const; private: int _numSamples; uint64_t _lastEventTimestamp; From a448b90726a43a8ecf076303a9a3f62145be2b0e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 10:57:39 -0700 Subject: [PATCH 09/51] fix some Q_OBJECT macros in class headers --- interface/src/VoxelHideShowThread.h | 1 + interface/src/VoxelPacketProcessor.h | 1 + 2 files changed, 2 insertions(+) diff --git a/interface/src/VoxelHideShowThread.h b/interface/src/VoxelHideShowThread.h index 2925888022..dc1f2062c1 100644 --- a/interface/src/VoxelHideShowThread.h +++ b/interface/src/VoxelHideShowThread.h @@ -16,6 +16,7 @@ /// Generalized threaded processor for handling received inbound packets. class VoxelHideShowThread : public GenericThread { + Q_OBJECT public: VoxelHideShowThread(VoxelSystem* theSystem); diff --git a/interface/src/VoxelPacketProcessor.h b/interface/src/VoxelPacketProcessor.h index 42040fe446..2acd347e99 100644 --- a/interface/src/VoxelPacketProcessor.h +++ b/interface/src/VoxelPacketProcessor.h @@ -16,6 +16,7 @@ /// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() class VoxelPacketProcessor : public ReceivedPacketProcessor { + Q_OBJECT protected: virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); }; From 96572d3752aca673f2bc11f87162ead57b6a9f44 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 10:57:53 -0700 Subject: [PATCH 10/51] fix some Q_OBJECT macros in class headers --- libraries/shared/src/ReceivedPacketProcessor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/ReceivedPacketProcessor.h b/libraries/shared/src/ReceivedPacketProcessor.h index 7c99218753..f88512639b 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.h +++ b/libraries/shared/src/ReceivedPacketProcessor.h @@ -18,6 +18,7 @@ /// Generalized threaded processor for handling received inbound packets. class ReceivedPacketProcessor : public GenericThread { + Q_OBJECT public: ReceivedPacketProcessor() { } From 981ab7374aa3509a0d8eaf6bd2e9427c00541574 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 11:01:09 -0700 Subject: [PATCH 11/51] fix crash in client shutdown, clean up some debugging, clean up Q_OBJECT --- .../src/octree/OctreeInboundPacketProcessor.h | 2 +- .../src/octree/OctreeQueryNode.cpp | 4 +- .../src/octree/OctreeQueryNode.h | 6 ++ .../src/octree/OctreeSendThread.cpp | 62 +++++++++++-------- .../src/octree/OctreeSendThread.h | 1 + assignment-client/src/octree/OctreeServer.cpp | 7 +-- 6 files changed, 49 insertions(+), 33 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 237a22d954..e2ec1b5c50 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -44,7 +44,7 @@ typedef std::map::iterator NodeToSenderStatsMapIterato /// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() class OctreeInboundPacketProcessor : public ReceivedPacketProcessor { - + Q_OBJECT public: OctreeInboundPacketProcessor(OctreeServer* myServer); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 8cb577d2f9..729b9150d0 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -35,11 +35,13 @@ OctreeQueryNode::OctreeQueryNode() : _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _lodChanged(false), _lodInitialized(false), - _sequenceNumber(0) + _sequenceNumber(0), + _scheduleForDelete(false) { } OctreeQueryNode::~OctreeQueryNode() { +qDebug() << "OctreeQueryNode::~OctreeQueryNode()"; if (_octreeSendThread) { _octreeSendThread->terminate(); delete _octreeSendThread; diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 6d4dee300a..b4df18fbb8 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -23,6 +23,7 @@ class OctreeSendThread; class OctreeServer; class OctreeQueryNode : public OctreeQuery { + Q_OBJECT public: OctreeQueryNode(); virtual ~OctreeQueryNode(); @@ -85,6 +86,9 @@ public: void dumpOutOfView(); + bool isScheduledForDelete() const { return _scheduleForDelete; } + void scheduleForDelete() { _scheduleForDelete = true; } + private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); @@ -119,6 +123,8 @@ private: bool _lodInitialized; OCTREE_PACKET_SEQUENCE _sequenceNumber; + + bool _scheduleForDelete; }; #endif /* defined(__hifi__OctreeQueryNode__) */ diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index ef47b4faef..98c7f2fbf5 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -34,7 +34,6 @@ OctreeSendThread::~OctreeSendThread() { bool OctreeSendThread::process() { - const int MAX_NODE_MISSING_CHECKS = 10; if (_nodeMissingCount > MAX_NODE_MISSING_CHECKS) { qDebug() << "our target node:" << _nodeUUID << "has been missing the last" << _nodeMissingCount @@ -64,6 +63,10 @@ bool OctreeSendThread::process() { } packetsSent = packetDistributor(node, nodeData, viewFrustumChanged); } + if (nodeData->isScheduledForDelete()) { + nodeData->deleteLater(); + node->setLinkedData(NULL); + } } else { _nodeMissingCount++; } @@ -83,7 +86,7 @@ bool OctreeSendThread::process() { PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { - if (true || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { + if ((_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { qDebug() << "Last send took too much time (" << (elapsed / USECS_PER_MSEC) <<" msecs), barely sleeping 1 usec!\n"; } @@ -576,13 +579,16 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 elapsedInsideUsecs = endInside - startInside; OctreeServer::trackInsideTime((float)elapsedInsideUsecs); - float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; - if (insideMsecs > 1.0f) { - qDebug()<< "inside msecs=" << insideMsecs - << "lockWait usec=" << lockWaitElapsedUsec - << "encode usec=" << encodeElapsedUsec - << "compress usec=" << compressAndWriteElapsedUsec - << "sending usec=" << packetSendingElapsedUsec; + const bool wantExtraDebugging = false; + if (wantExtraDebugging) { + float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; + if (insideMsecs > 1.0f) { + qDebug()<< "inside msecs=" << insideMsecs + << "lockWait usec=" << lockWaitElapsedUsec + << "encode usec=" << encodeElapsedUsec + << "compress usec=" << compressAndWriteElapsedUsec + << "sending usec=" << packetSendingElapsedUsec; + } } } @@ -607,24 +613,27 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; - if (elapsedmsec > 100) { - if (elapsedmsec > 1000) { - int elapsedsec = (end - start)/1000000; - qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets %d nodes still to send", - elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } else { - qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " + bool wantsExtraDebugging = false; + if (wantsExtraDebugging) { + if (elapsedmsec > 100) { + if (elapsedmsec > 1000) { + int elapsedsec = (end - start)/1000000; + qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] " + "to generate %d bytes in %d packets %d nodes still to send", + elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, + trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); + } else { + qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " + "to generate %d bytes in %d packets, %d nodes still to send", + elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, + trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); + } + } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { + qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " "to generate %d bytes in %d packets, %d nodes still to send", elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } - } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets, %d nodes still to send", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); } // if after sending packets we've emptied our bag, then we want to remember that we've sent all @@ -648,8 +657,11 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue } // end if bag wasn't empty, and so we sent stuff... - if (truePacketsSent > 0 || packetsSentThisInterval > 0) { - qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; + const bool wantExtraDebugging = false; + if (wantExtraDebugging) { + if (truePacketsSent > 0 || packetsSentThisInterval > 0) { + qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; + } } return truePacketsSent; diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 081e7f411f..39c27911b0 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -19,6 +19,7 @@ /// Threaded processor for sending voxel packets to a single client class OctreeSendThread : public GenericThread { + Q_OBJECT public: OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer); virtual ~OctreeSendThread(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 7be8c34087..4d55455f76 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -766,12 +766,7 @@ void OctreeServer::nodeAdded(SharedNodePointer node) { void OctreeServer::nodeKilled(SharedNodePointer node) { OctreeQueryNode* nodeData = static_cast(node->getLinkedData()); if (nodeData) { - // Note: It should be safe to do this without locking the node, because if any other threads - // are using the SharedNodePointer, then they have a reference to the SharedNodePointer and the deleteLater() - // won't actually delete it until all threads have released their references to the pointer. - // But we can and should clear the linked data so that no one else tries to access it. - nodeData->deleteLater(); - node->setLinkedData(NULL); + nodeData->scheduleForDelete(); } } From 07adfed6b4e8cc8796f1522a7f3c33dc10b5bf83 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 13:47:05 -0700 Subject: [PATCH 12/51] call setLastHeardFromMicrostamp() when we get packets from nodes so NodeList doesn't drop them --- assignment-client/src/Agent.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 46f4d233c2..16674efcbf 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -95,12 +95,19 @@ void Agent::readPendingDatagrams() { // also give our local particle tree a chance to remap any internal locally created particles _particleViewer.getTree()->handleAddParticleResponse(receivedPacket); + // Make sure our Node and NodeList knows we've heard from this node. + SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket); + sourceNode->setLastHeardMicrostamp(usecTimestampNow()); + } else if (datagramPacketType == PacketTypeParticleData || datagramPacketType == PacketTypeParticleErase || datagramPacketType == PacketTypeOctreeStats || datagramPacketType == PacketTypeVoxelData ) { + // Make sure our Node and NodeList knows we've heard from this node. SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket); + sourceNode->setLastHeardMicrostamp(usecTimestampNow()); + QByteArray mutablePacket = receivedPacket; ssize_t messageLength = mutablePacket.size(); From 59b272d8db467a005e9908cf64c7fbf97fc47e8c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 13:47:46 -0700 Subject: [PATCH 13/51] make seeing voxels less noisy and more random --- examples/seeingVoxelsExample.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/seeingVoxelsExample.js b/examples/seeingVoxelsExample.js index 330634f5af..0cfe54d89e 100644 --- a/examples/seeingVoxelsExample.js +++ b/examples/seeingVoxelsExample.js @@ -20,6 +20,10 @@ var isLocal = false; // set up our VoxelViewer with a position and orientation var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + function init() { if (isLocal) { MyAvatar.position = vantagePoint; @@ -39,21 +43,26 @@ function keepLooking(deltaTime) { init(); } count++; - if (count % 10 == 0) { + if (count % getRandomInt(5, 15) == 0) { yaw += yawDirection; orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0); if (yaw > yawMax || yaw < yawMin) { yawDirection = yawDirection * -1; } - print("calling VoxelViewer.queryOctree()... count=" + count + " yaw=" + yaw); + if (count % 10000 == 0) { + print("calling VoxelViewer.queryOctree()... count=" + count + " yaw=" + yaw); + } if (isLocal) { MyAvatar.orientation = orientation; } else { VoxelViewer.setOrientation(orientation); VoxelViewer.queryOctree(); - print("VoxelViewer.getOctreeElementsCount()=" + VoxelViewer.getOctreeElementsCount()); + + if (count % 10000 == 0) { + print("VoxelViewer.getOctreeElementsCount()=" + VoxelViewer.getOctreeElementsCount()); + } } } From e9684c0ee537d86e889834f84cd4fba47bc2f01f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 16:11:00 -0700 Subject: [PATCH 14/51] added more stats to octree server stats page --- .../src/octree/OctreeSendThread.cpp | 6 +- assignment-client/src/octree/OctreeServer.cpp | 104 ++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 11 +- 3 files changed, 97 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index fd4bbbd7a9..dc8cd64ebe 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -117,7 +117,7 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node, OctreeQuer quint64 lockWaitEnd = usecTimestampNow(); float lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); OctreeServer::trackNodeWaitTime(lockWaitElapsedUsec); - + const HifiSockAddr* nodeAddress = node->getActiveSocket(); if (!nodeAddress) { return packetsSent; // without sending... @@ -452,15 +452,13 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue _myServer->getOctree()->lockForRead(); quint64 lockWaitEnd = usecTimestampNow(); lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); - + nodeData->stats.encodeStarted(); quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); encodeElapsedUsec = (float)(encodeEnd - encodeStart); - OctreeServer::trackEncodeTime(encodeElapsedUsec); // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've // sent the entire scene. We want to know this below so we'll actually write this content into diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 4d55455f76..22bdae16d8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -20,13 +20,54 @@ OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; -SimpleMovingAverage OctreeServer::_averageLoopTime(100000); -SimpleMovingAverage OctreeServer::_averageEncodeTime(100000); -SimpleMovingAverage OctreeServer::_averageInsideTime(100000); -SimpleMovingAverage OctreeServer::_averageTreeWaitTime(100000); -SimpleMovingAverage OctreeServer::_averageNodeWaitTime(100000); -SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(100000); -SimpleMovingAverage OctreeServer::_averagePacketSendingTime(100000); +const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; +SimpleMovingAverage OctreeServer::_averageLoopTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageInsideTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeShortWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageTreeExtraLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageNodeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_extraLongTreeWait = 0; +int OctreeServer::_longTreeWait = 0; +int OctreeServer::_shortTreeWait = 0; + + +void OctreeServer::resetSendingStats() { + _averageLoopTime.reset(); + _averageEncodeTime.reset(); + _averageInsideTime.reset(); + _averageTreeWaitTime.reset(); + _averageTreeShortWaitTime.reset(); + _averageTreeLongWaitTime.reset(); + _averageTreeExtraLongWaitTime.reset(); + _averageNodeWaitTime.reset(); + _averageCompressAndWriteTime.reset(); + _averagePacketSendingTime.reset(); + _extraLongTreeWait = 0; + _longTreeWait = 0; + _shortTreeWait = 0; +} + +void OctreeServer::trackTreeWaitTime(float time) { + _averageTreeWaitTime.updateAverage(time); + const float MAX_SHORT_TIME = 10.0f; + const float MAX_LONG_TIME = 100.0f; + if (time <= MAX_SHORT_TIME) { + _shortTreeWait++; + _averageTreeShortWaitTime.updateAverage(time); + } else if (time <= MAX_LONG_TIME) { + _longTreeWait++; + _averageTreeLongWaitTime.updateAverage(time); + } else { + _extraLongTreeWait++; + _averageTreeExtraLongWaitTime.updateAverage(time); + } +} + void OctreeServer::attachQueryNodeToNode(Node* newNode) { if (!newNode->getLinkedData()) { @@ -124,6 +165,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& showStats = true; } else if (path == "/resetStats") { _octreeInboundPacketProcessor->resetStats(); + resetSendingStats(); showStats = true; } } @@ -258,7 +300,9 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& statsString += "\r\n"; // display outbound packet stats - statsString += QString("%1 Outbound Packet Statistics...\r\n").arg(getMyServerName()); + statsString += QString("%1 Outbound Packet Statistics... " + "[RESET]\r\n").arg(getMyServerName()); + quint64 totalOutboundPackets = OctreeSendThread::_totalPackets; quint64 totalOutboundBytes = OctreeSendThread::_totalBytes; quint64 totalWastedBytes = OctreeSendThread::_totalWastedBytes; @@ -266,7 +310,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& quint64 totalBytesOfBitMasks = OctreePacketData::getTotalBytesOfBitMasks(); quint64 totalBytesOfColor = OctreePacketData::getTotalBytesOfColor(); - const int COLUMN_WIDTH = 10; + const int COLUMN_WIDTH = 19; statsString += QString(" Configured Max PPS/Client: %1 pps/client\r\n") .arg(locale.toString((uint)getPacketsPerClientPerSecond()).rightJustified(COLUMN_WIDTH, ' ')); statsString += QString(" Configured Max PPS/Server: %1 pps/server\r\n\r\n") @@ -275,45 +319,66 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); float averageLoopTime = getAverageLoopTime(); - statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); + statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); qDebug() << "averageLoopTime=" << averageLoopTime; float averageInsideTime = getAverageInsideTime(); - statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); + statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); qDebug() << "averageInsideTime=" << averageInsideTime; + int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait; + float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs\r\n", averageTreeWaitTime); + statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs samples: %12d \r\n", + averageTreeWaitTime, allWaitTimes); qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; + float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock short wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeShortWaitTime.getAverage(), + shortVsTotal * AS_PERCENT, _shortTreeWait); + qDebug() << "averageTreeShortWaitTime=" << _averageTreeShortWaitTime.getAverage(); + + float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeLongWaitTime.getAverage(), + longVsTotal * AS_PERCENT, _longTreeWait); + qDebug() << "averageTreeLongWaitTime=" << _averageTreeLongWaitTime.getAverage(); + + float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf("Avg tree lock extra long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeExtraLongWaitTime.getAverage(), + extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); + qDebug() << "averageTreeExtraLongWaitTime=" << _averageTreeExtraLongWaitTime.getAverage(); + float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); + statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); qDebug() << "averageEncodeTime=" << averageEncodeTime; float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); - statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); + statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", + statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", averagePacketSendingTime); qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; float averageNodeWaitTime = getAverageNodeWaitTime(); - statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); + statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; - statsString += QString().sprintf("---------------------------------------------------\r\n"); + statsString += QString().sprintf("----------------------------------------------------\r\n"); float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", encodeToInsidePercent); qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); qDebug() << "waitToInsidePercent=" << waitToInsidePercent; @@ -761,6 +826,7 @@ void OctreeServer::run() { void OctreeServer::nodeAdded(SharedNodePointer node) { // we might choose to use this notifier to track clients in a pending state + qDebug() << "OctreeServer::nodeAdded() node:" << *node; } void OctreeServer::nodeKilled(SharedNodePointer node) { diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 022da9d658..636ecb8365 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -83,8 +83,9 @@ public: static void trackInsideTime(float time) { _averageInsideTime.updateAverage(time); } static float getAverageInsideTime() { return _averageInsideTime.getAverage(); } - static void trackTreeWaitTime(float time) { _averageTreeWaitTime.updateAverage(time); } + static void trackTreeWaitTime(float time); static float getAverageTreeWaitTime() { return _averageTreeWaitTime.getAverage(); } + static void trackNodeWaitTime(float time) { _averageNodeWaitTime.updateAverage(time); } static float getAverageNodeWaitTime() { return _averageNodeWaitTime.getAverage(); } @@ -95,6 +96,7 @@ public: static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } bool handleHTTPRequest(HTTPConnection* connection, const QString& path); + public slots: /// runs the voxel server assignment void run(); @@ -105,6 +107,7 @@ public slots: protected: void parsePayload(); void initHTTPManager(int port); + void resetSendingStats(); int _argc; const char** _argv; @@ -135,9 +138,15 @@ protected: static SimpleMovingAverage _averageEncodeTime; static SimpleMovingAverage _averageInsideTime; static SimpleMovingAverage _averageTreeWaitTime; + static SimpleMovingAverage _averageTreeShortWaitTime; + static SimpleMovingAverage _averageTreeLongWaitTime; + static SimpleMovingAverage _averageTreeExtraLongWaitTime; static SimpleMovingAverage _averageNodeWaitTime; static SimpleMovingAverage _averageCompressAndWriteTime; static SimpleMovingAverage _averagePacketSendingTime; + static int _extraLongTreeWait; + static int _longTreeWait; + static int _shortTreeWait; }; #endif // __octree_server__OctreeServer__ From 9411519dc980802e7fc1baef7e7c1674b16eded7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 16:37:07 -0700 Subject: [PATCH 15/51] fix SimpleMovingAverage::reset() --- libraries/shared/src/SimpleMovingAverage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index f52a8b1c3d..676c85598e 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -42,6 +42,8 @@ int SimpleMovingAverage::updateAverage(float sample) { void SimpleMovingAverage::reset() { _numSamples = 0; + _average = 0; + _eventDeltaAverage = 0; } float SimpleMovingAverage::getEventDeltaAverage() const { From 14f8245dd8f416bc6b59a4654fc3e230f78426ce Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 17:07:42 -0700 Subject: [PATCH 16/51] adding threading and read write lock tests --- tests/threads/CMakeLists.txt | 36 ++++++++++++ tests/threads/src/SampleReadThread.cpp | 65 ++++++++++++++++++++++ tests/threads/src/SampleReadThread.h | 31 +++++++++++ tests/threads/src/SampleWriteThread.cpp | 47 ++++++++++++++++ tests/threads/src/SampleWriteThread.h | 30 ++++++++++ tests/threads/src/SharedResource.cpp | 38 +++++++++++++ tests/threads/src/SharedResource.h | 40 ++++++++++++++ tests/threads/src/ThreadsTests.cpp | 73 +++++++++++++++++++++++++ tests/threads/src/ThreadsTests.h | 16 ++++++ tests/threads/src/main.cpp | 11 ++++ 10 files changed, 387 insertions(+) create mode 100644 tests/threads/CMakeLists.txt create mode 100644 tests/threads/src/SampleReadThread.cpp create mode 100644 tests/threads/src/SampleReadThread.h create mode 100644 tests/threads/src/SampleWriteThread.cpp create mode 100644 tests/threads/src/SampleWriteThread.h create mode 100644 tests/threads/src/SharedResource.cpp create mode 100644 tests/threads/src/SharedResource.h create mode 100644 tests/threads/src/ThreadsTests.cpp create mode 100644 tests/threads/src/ThreadsTests.h create mode 100644 tests/threads/src/main.cpp diff --git a/tests/threads/CMakeLists.txt b/tests/threads/CMakeLists.txt new file mode 100644 index 0000000000..f12a124b0c --- /dev/null +++ b/tests/threads/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8) + +if (WIN32) + cmake_policy (SET CMP0020 NEW) +endif (WIN32) + +set(TARGET_NAME threads-tests) + +set(ROOT_DIR ../..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") + +find_package(Qt5Core REQUIRED) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE) + +include(${MACRO_DIR}/AutoMTC.cmake) +auto_mtc(${TARGET_NAME} ${ROOT_DIR}) + +qt5_use_modules(${TARGET_NAME} Core) + +#include glm +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +# link in the shared libraries +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) + +IF (WIN32) + #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) +ENDIF(WIN32) + diff --git a/tests/threads/src/SampleReadThread.cpp b/tests/threads/src/SampleReadThread.cpp new file mode 100644 index 0000000000..129c3f098b --- /dev/null +++ b/tests/threads/src/SampleReadThread.cpp @@ -0,0 +1,65 @@ +// +// SampleReadThread.cpp +// interface +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. +// + +#include + +#include + +#include "SharedResource.h" +#include "SampleReadThread.h" + +SampleReadThread::SampleReadThread(SharedResource* theResource, int id) : + _theResource(theResource), + _myID(id) { +} + +bool SampleReadThread::process() { + const quint64 FRAME_RATE = 60; + const quint64 USECS_PER_FRAME = USECS_PER_SECOND / FRAME_RATE; // every 60fps + + quint64 start = usecTimestampNow(); + _theResource->lockForRead(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + + int theValue = _theResource->getValue(); + + bool wantDebugging = true; + if (wantDebugging) { + qDebug() << "SampleReadThread::process()... _myID=" << _myID << "lockForRead() took" << elapsed << "usecs" << + " _theResource->getValue()=" << theValue; + } + + quint64 startWork = usecTimestampNow(); + { + const int LOTS_OF_OPERATIONS = 100000; + for(int i = 0; i < LOTS_OF_OPERATIONS; i++) { + float x = rand(); + float y = rand(); + float z = x * y; + } + } + quint64 endWork = usecTimestampNow(); + quint64 elapsedWork = endWork - startWork; + qDebug() << "SampleReadThread::process()... _myID=" << _myID << " work took" << elapsedWork << "usecs"; + + _theResource->unlock(); + + + if (isStillRunning()) { + if (elapsed < USECS_PER_FRAME) { + quint64 sleepFor = USECS_PER_FRAME - elapsed; + usleep(sleepFor); + } else { + usleep(5); // sleep at least a little + } + } + return isStillRunning(); // keep running till they terminate us +} diff --git a/tests/threads/src/SampleReadThread.h b/tests/threads/src/SampleReadThread.h new file mode 100644 index 0000000000..a9a25ac7a1 --- /dev/null +++ b/tests/threads/src/SampleReadThread.h @@ -0,0 +1,31 @@ +// +// SampleReadThread.h +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__SampleReadThread__ +#define __interface__SampleReadThread__ + +#include + +class SharedResource; + +/// Generalized threaded processor for handling received inbound packets. +class SampleReadThread : public GenericThread { + Q_OBJECT +public: + SampleReadThread(SharedResource* theResource, int id); + +protected: + /// Implements generic processing behavior for this thread. + virtual bool process(); + +private: + SharedResource* _theResource; + int _myID; +}; + +#endif // __interface__SampleReadThread__ diff --git a/tests/threads/src/SampleWriteThread.cpp b/tests/threads/src/SampleWriteThread.cpp new file mode 100644 index 0000000000..0fbe68904d --- /dev/null +++ b/tests/threads/src/SampleWriteThread.cpp @@ -0,0 +1,47 @@ +// +// SampleWriteThread.cpp +// interface +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. +// + +#include + +#include + +#include "SharedResource.h" +#include "SampleWriteThread.h" + +SampleWriteThread::SampleWriteThread(SharedResource* theResource) : + _theResource(theResource) { +} + +bool SampleWriteThread::process() { + const quint64 USECS_PER_OPERATION = USECS_PER_SECOND * 1; // once every second. + + quint64 start = usecTimestampNow(); + _theResource->lockForWrite(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + + int theValue = _theResource->incrementValue(); + + bool wantDebugging = false; + if (wantDebugging) { + qDebug() << "SampleWriteThread::process()... lockForWrite() took" << elapsed << "usecs" << + " _theResource->incrementValue()=" << theValue; + } + _theResource->unlock(); + + + if (isStillRunning()) { + if (elapsed < USECS_PER_OPERATION) { + quint64 sleepFor = USECS_PER_OPERATION - elapsed; + usleep(sleepFor); + } + } + return isStillRunning(); // keep running till they terminate us +} diff --git a/tests/threads/src/SampleWriteThread.h b/tests/threads/src/SampleWriteThread.h new file mode 100644 index 0000000000..970b4435a9 --- /dev/null +++ b/tests/threads/src/SampleWriteThread.h @@ -0,0 +1,30 @@ +// +// SampleWriteThread.h +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__SampleWriteThread__ +#define __interface__SampleWriteThread__ + +#include + +class SharedResource; + +/// Generalized threaded processor for handling received inbound packets. +class SampleWriteThread : public GenericThread { + Q_OBJECT +public: + SampleWriteThread(SharedResource* theResource); + +protected: + /// Implements generic processing behavior for this thread. + virtual bool process(); + +private: + SharedResource* _theResource; +}; + +#endif // __interface__SampleWriteThread__ diff --git a/tests/threads/src/SharedResource.cpp b/tests/threads/src/SharedResource.cpp new file mode 100644 index 0000000000..c397e6a7db --- /dev/null +++ b/tests/threads/src/SharedResource.cpp @@ -0,0 +1,38 @@ +// +// SharedResource.cpp +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "SharedResource.h" + +const int MOVING_AVERAGE_SAMPLES = 10000; + +SharedResource::SharedResource() : + _value(0), + _lockAverage(MOVING_AVERAGE_SAMPLES), + _lockForReadAverage(MOVING_AVERAGE_SAMPLES), + _lockForWriteAverage(MOVING_AVERAGE_SAMPLES) +{ +}; + +void SharedResource::lockForRead() { + quint64 start = usecTimestampNow(); + _lock.lockForRead(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + _lockForReadAverage.updateAverage(elapsed); + _lockAverage.updateAverage(elapsed); +} +void SharedResource::lockForWrite() { + quint64 start = usecTimestampNow(); + _lock.lockForWrite(); + quint64 end = usecTimestampNow(); + quint64 elapsed = end - start; + _lockForWriteAverage.updateAverage(elapsed); + _lockAverage.updateAverage(elapsed); +} diff --git a/tests/threads/src/SharedResource.h b/tests/threads/src/SharedResource.h new file mode 100644 index 0000000000..1426471f16 --- /dev/null +++ b/tests/threads/src/SharedResource.h @@ -0,0 +1,40 @@ +// +// SharedResource.h +// tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__SharedResource__ +#define __interface__SharedResource__ + +#include + +#include + +/// Generalized threaded processor for handling received inbound packets. +class SharedResource { +public: + SharedResource(); + + void lockForRead(); + void lockForWrite(); + void unlock() { _lock.unlock(); } + + int getValue() const { return _value; } + int incrementValue() { return ++_value; } + + float getAverageLockTime() const { return _lockAverage.getAverage(); } + float getAverageLockForReadTime() const { return _lockForReadAverage.getAverage(); } + float getAverageLockForWriteTime() const { return _lockForWriteAverage.getAverage(); } + +private: + QReadWriteLock _lock; + int _value; + SimpleMovingAverage _lockAverage; + SimpleMovingAverage _lockForReadAverage; + SimpleMovingAverage _lockForWriteAverage; +}; + +#endif // __interface__SharedResource__ diff --git a/tests/threads/src/ThreadsTests.cpp b/tests/threads/src/ThreadsTests.cpp new file mode 100644 index 0000000000..15b1c66e63 --- /dev/null +++ b/tests/threads/src/ThreadsTests.cpp @@ -0,0 +1,73 @@ +// +// ThreadsTests.cpp +// thread-tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#include +#include + +#include +#include + +#include "SampleReadThread.h" +#include "SampleWriteThread.h" +#include "SharedResource.h" +#include "ThreadsTests.h" + + +void ThreadsTests::runAllTests() { + qDebug() << "START ThreadsTests::runAllTests()"; + + const quint64 TOTAL_RUN_TIME = USECS_PER_SECOND * 10; // run for 2 minutes + const quint64 MAIN_THREAD_SLEEP = USECS_PER_SECOND * 0.25; // main thread checks in every 1/4 second + quint64 start = usecTimestampNow(); + quint64 now = usecTimestampNow(); + + SharedResource resource; + + const int NUMBER_OF_READERS = 125; // + 3 = 128, Max number of QThreads on the mac. + QVector readThreads; + for(int i = 0; i < NUMBER_OF_READERS; i++) { + SampleReadThread* newReader = new SampleReadThread(&resource, i); + newReader->initialize(); + readThreads.append(newReader); + } + + SampleWriteThread write(&resource); + write.initialize(); + + while(now - start < TOTAL_RUN_TIME) { + float elapsed = (float)(now - start) / (float)USECS_PER_SECOND; + qDebug() << "Main thread still running... elapsed:" << elapsed << "seconds"; + qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; + qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; + qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; + qDebug() << " resource.value:" << resource.getValue(); + + + usleep(MAIN_THREAD_SLEEP); + now = usecTimestampNow(); + } + write.terminate(); + + foreach(SampleReadThread* readThread, readThreads) { + readThread->terminate(); + delete readThread; + } + readThreads.clear(); + + qDebug() << "DONE running..."; + qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; + qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; + qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; + qDebug() << " resource.value:" << resource.getValue(); + + qDebug() << "END ThreadsTests::runAllTests()"; + + qDebug() << "_POSIX_THREAD_THREADS_MAX" << _POSIX_THREAD_THREADS_MAX; + qDebug() << "QThread::idealThreadCount()" << QThread::idealThreadCount(); + +} diff --git a/tests/threads/src/ThreadsTests.h b/tests/threads/src/ThreadsTests.h new file mode 100644 index 0000000000..29bd9aebd4 --- /dev/null +++ b/tests/threads/src/ThreadsTests.h @@ -0,0 +1,16 @@ +// +// ThreadsTests.h +// threads-tests +// +// Created by Brad Hefta-Gaub on 2014.03.17 +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#ifndef __tests__ThreadsTests__ +#define __tests__ThreadsTests__ + +namespace ThreadsTests { + void runAllTests(); +} + +#endif // __tests__ThreadsTests__ diff --git a/tests/threads/src/main.cpp b/tests/threads/src/main.cpp new file mode 100644 index 0000000000..16f3ea0900 --- /dev/null +++ b/tests/threads/src/main.cpp @@ -0,0 +1,11 @@ +// +// main.cpp +// threads-tests +// + +#include "ThreadsTests.h" + +int main(int argc, char** argv) { + ThreadsTests::runAllTests(); + return 0; +} From 62dabd9c1c7448ab66ad9d83f39a81b095f642a7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 17:49:50 -0700 Subject: [PATCH 17/51] formatting of stats --- assignment-client/src/octree/OctreeServer.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 22bdae16d8..2fd9caea50 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -319,66 +319,66 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); float averageLoopTime = getAverageLoopTime(); - statsString += QString().sprintf(" Average packetLoop() time: %5.2f msecs\r\n", averageLoopTime); + statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs\r\n", averageLoopTime); qDebug() << "averageLoopTime=" << averageLoopTime; float averageInsideTime = getAverageInsideTime(); - statsString += QString().sprintf(" Average 'inside' time: %7.2f usecs\r\n", averageInsideTime); + statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs\r\n", averageInsideTime); qDebug() << "averageInsideTime=" << averageInsideTime; int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait; float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %7.2f usecs samples: %12d \r\n", + statsString += QString().sprintf(" Average tree lock wait time: %9.2f usecs samples: %12d \r\n", averageTreeWaitTime, allWaitTimes); qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock short wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + statsString += QString().sprintf(" Avg tree lock short wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageTreeShortWaitTime.getAverage(), shortVsTotal * AS_PERCENT, _shortTreeWait); qDebug() << "averageTreeShortWaitTime=" << _averageTreeShortWaitTime.getAverage(); float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + statsString += QString().sprintf(" Avg tree lock long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageTreeLongWaitTime.getAverage(), longVsTotal * AS_PERCENT, _longTreeWait); qDebug() << "averageTreeLongWaitTime=" << _averageTreeLongWaitTime.getAverage(); float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf("Avg tree lock extra long wait time: %7.2f usecs (%6.2f%%) samples: %12d \r\n", + statsString += QString().sprintf("Avg tree lock extra long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageTreeExtraLongWaitTime.getAverage(), extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); qDebug() << "averageTreeExtraLongWaitTime=" << _averageTreeExtraLongWaitTime.getAverage(); float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %7.2f usecs\r\n", averageEncodeTime); + statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); qDebug() << "averageEncodeTime=" << averageEncodeTime; float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); - statsString += QString().sprintf(" Average compress and write time: %7.2f usecs\r\n", averageCompressAndWriteTime); + statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", averageCompressAndWriteTime); qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %7.2f usecs (includes node lock)\r\n", + statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", averagePacketSendingTime); qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; float averageNodeWaitTime = getAverageNodeWaitTime(); - statsString += QString().sprintf(" Average node lock wait time: %7.2f usecs\r\n", averageNodeWaitTime); + statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; - statsString += QString().sprintf("----------------------------------------------------\r\n"); + statsString += QString().sprintf("------------------------------------------------------\r\n"); float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", encodeToInsidePercent); qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); qDebug() << "waitToInsidePercent=" << waitToInsidePercent; From c09974bcda41415f23e6c073f76528e7eb0ce855 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 17:51:09 -0700 Subject: [PATCH 18/51] use parents inFrustum status to optimize children --- libraries/octree/src/Octree.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 63a7fb8e88..2776af6dab 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -892,6 +892,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, return bytesAtThisLevel; } } + + ViewFrustum::location nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside // caller can pass NULL as viewFrustum if they want everything if (params.viewFrustum) { @@ -907,11 +909,13 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, params.stopReason = EncodeBitstreamParams::LOD_SKIP; return bytesAtThisLevel; } + + nodeLocationThisView = node->inFrustum(*params.viewFrustum); // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view - if (!node->isInView(*params.viewFrustum)) { + if (nodeLocationThisView == ViewFrustum::OUTSIDE) { if (params.stats) { params.stats->skippedOutOfView(node); } @@ -1065,7 +1069,11 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, OctreeElement* childNode = sortedChildren[i]; int originalIndex = indexOfChildren[i]; - bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum))); + bool childIsInView = (childNode && + ( !params.viewFrustum || // no view frustum was given, everything is assumed in view + (nodeLocationThisView == ViewFrustum::INSIDE) || // the parent was fully in view, we can assume ALL children are + (nodeLocationThisView == ViewFrustum::INTERSECT && childNode->isInView(*params.viewFrustum)) // the parent intersects and the child is in view + )); if (!childIsInView) { // must check childNode here, because it could be we got here because there was no childNode From 28766bebc81e14d210215b9c0f15878cba22cac8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 18:30:08 -0700 Subject: [PATCH 19/51] pass down parents inFrustum() state to recursion to allow further optimization --- libraries/octree/src/Octree.cpp | 20 +++++++++++++++----- libraries/octree/src/Octree.h | 3 ++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 2776af6dab..58cfd9b15d 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -829,7 +829,10 @@ int Octree::encodeTreeBitstream(OctreeElement* node, params.stats->traversed(node); } - int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, currentEncodeLevel); + ViewFrustum::location parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully + + int childBytesWritten = encodeTreeBitstreamRecursion(node, packetData, bag, params, + currentEncodeLevel, parentLocationThisView); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -861,7 +864,8 @@ int Octree::encodeTreeBitstream(OctreeElement* node, int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params, int& currentEncodeLevel) const { + EncodeBitstreamParams& params, int& currentEncodeLevel, + const ViewFrustum::location& parentLocationThisView) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -909,8 +913,13 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, params.stopReason = EncodeBitstreamParams::LOD_SKIP; return bytesAtThisLevel; } - - nodeLocationThisView = node->inFrustum(*params.viewFrustum); + + // if the parent isn't known to be INSIDE, then it must be INTERSECT, and we should double check to see + // if we are INSIDE, INTERSECT, or OUTSIDE + if (parentLocationThisView != ViewFrustum::INSIDE) { + assert(parentLocationThisView != ViewFrustum::OUTSIDE); // we shouldn't be here if our parent was OUTSIDE! + nodeLocationThisView = node->inFrustum(*params.viewFrustum); + } // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if @@ -1300,7 +1309,8 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* node, // This only applies in the view frustum case, in other cases, like file save and copy/past where // no viewFrustum was requested, we still want to recurse the child tree. if (!params.viewFrustum || !oneAtBit(childrenColoredBits, originalIndex)) { - childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, thisLevel); + childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, packetData, bag, params, + thisLevel, nodeLocationThisView); } // remember this for reshuffling diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 6e53e1f240..f029431d87 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -287,7 +287,8 @@ protected: int encodeTreeBitstreamRecursion(OctreeElement* node, OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params, int& currentEncodeLevel) const; + EncodeBitstreamParams& params, int& currentEncodeLevel, + const ViewFrustum::location& parentLocationThisView) const; static bool countOctreeElementsOperation(OctreeElement* node, void* extraData); From fc50cc0604a4d53a83985b22ee8e10540ef738ea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 17 Mar 2014 23:40:07 -0700 Subject: [PATCH 20/51] improving server stats --- .../src/octree/OctreeSendThread.cpp | 6 +- assignment-client/src/octree/OctreeServer.cpp | 227 ++++++++++++++---- assignment-client/src/octree/OctreeServer.h | 33 ++- 3 files changed, 215 insertions(+), 51 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index dc8cd64ebe..e91b999c20 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -416,9 +416,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int extraPackingAttempts = 0; bool completedScene = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { - float lockWaitElapsedUsec = 0.0f; - float encodeElapsedUsec = 0.0f; - float compressAndWriteElapsedUsec = 0.0f; + float lockWaitElapsedUsec = OctreeServer::SKIP_TIME; + float encodeElapsedUsec = OctreeServer::SKIP_TIME; + float compressAndWriteElapsedUsec = OctreeServer::SKIP_TIME; float packetSendingElapsedUsec = 0.0f; quint64 startInside = usecTimestampNow(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 2fd9caea50..377ff0ea7a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -21,42 +21,107 @@ OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; + +float OctreeServer::SKIP_TIME = -1.0f; // use this for trackXXXTime() calls for non-times + SimpleMovingAverage OctreeServer::_averageLoopTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averageEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageInsideTime(MOVING_AVERAGE_SAMPLE_COUNTS); + +SimpleMovingAverage OctreeServer::_averageEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageShortEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageLongEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageExtraLongEncodeTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_extraLongEncode = 0; +int OctreeServer::_longEncode = 0; +int OctreeServer::_shortEncode = 0; +int OctreeServer::_noEncode = 0; + SimpleMovingAverage OctreeServer::_averageTreeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageTreeShortWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageTreeLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); SimpleMovingAverage OctreeServer::_averageTreeExtraLongWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averageNodeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(MOVING_AVERAGE_SAMPLE_COUNTS); -SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); int OctreeServer::_extraLongTreeWait = 0; int OctreeServer::_longTreeWait = 0; int OctreeServer::_shortTreeWait = 0; +int OctreeServer::_noTreeWait = 0; + +SimpleMovingAverage OctreeServer::_averageNodeWaitTime(MOVING_AVERAGE_SAMPLE_COUNTS); + +SimpleMovingAverage OctreeServer::_averageCompressAndWriteTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageShortCompressTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageLongCompressTime(MOVING_AVERAGE_SAMPLE_COUNTS); +SimpleMovingAverage OctreeServer::_averageExtraLongCompressTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_extraLongCompress = 0; +int OctreeServer::_longCompress = 0; +int OctreeServer::_shortCompress = 0; +int OctreeServer::_noCompress = 0; + +SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); void OctreeServer::resetSendingStats() { _averageLoopTime.reset(); + _averageEncodeTime.reset(); + _averageShortEncodeTime.reset(); + _averageLongEncodeTime.reset(); + _averageExtraLongEncodeTime.reset(); + _extraLongEncode = 0; + _longEncode = 0; + _shortEncode = 0; + _noEncode = 0; + _averageInsideTime.reset(); _averageTreeWaitTime.reset(); _averageTreeShortWaitTime.reset(); _averageTreeLongWaitTime.reset(); _averageTreeExtraLongWaitTime.reset(); - _averageNodeWaitTime.reset(); - _averageCompressAndWriteTime.reset(); - _averagePacketSendingTime.reset(); _extraLongTreeWait = 0; _longTreeWait = 0; _shortTreeWait = 0; + _noTreeWait = 0; + + _averageNodeWaitTime.reset(); + + _averageCompressAndWriteTime.reset(); + _averageShortCompressTime.reset(); + _averageLongCompressTime.reset(); + _averageExtraLongCompressTime.reset(); + _extraLongCompress = 0; + _longCompress = 0; + _shortCompress = 0; + _noCompress = 0; + + _averagePacketSendingTime.reset(); +} + +void OctreeServer::trackEncodeTime(float time) { + const float MAX_SHORT_TIME = 10.0f; + const float MAX_LONG_TIME = 100.0f; + + if (time == SKIP_TIME) { + _noEncode++; + time = 0.0f; + } else if (time <= MAX_SHORT_TIME) { + _shortEncode++; + _averageShortEncodeTime.updateAverage(time); + } else if (time <= MAX_LONG_TIME) { + _longEncode++; + _averageLongEncodeTime.updateAverage(time); + } else { + _extraLongEncode++; + _averageExtraLongEncodeTime.updateAverage(time); + } + _averageEncodeTime.updateAverage(time); } void OctreeServer::trackTreeWaitTime(float time) { - _averageTreeWaitTime.updateAverage(time); const float MAX_SHORT_TIME = 10.0f; const float MAX_LONG_TIME = 100.0f; - if (time <= MAX_SHORT_TIME) { + if (time == SKIP_TIME) { + _noTreeWait++; + time = 0.0f; + } else if (time <= MAX_SHORT_TIME) { _shortTreeWait++; _averageTreeShortWaitTime.updateAverage(time); } else if (time <= MAX_LONG_TIME) { @@ -66,6 +131,26 @@ void OctreeServer::trackTreeWaitTime(float time) { _extraLongTreeWait++; _averageTreeExtraLongWaitTime.updateAverage(time); } + _averageTreeWaitTime.updateAverage(time); +} + +void OctreeServer::trackCompressAndWriteTime(float time) { + const float MAX_SHORT_TIME = 10.0f; + const float MAX_LONG_TIME = 100.0f; + if (time == SKIP_TIME) { + _noCompress++; + time = 0.0f; + } else if (time <= MAX_SHORT_TIME) { + _shortCompress++; + _averageShortCompressTime.updateAverage(time); + } else if (time <= MAX_LONG_TIME) { + _longCompress++; + _averageLongCompressTime.updateAverage(time); + } else { + _extraLongCompress++; + _averageExtraLongCompressTime.updateAverage(time); + } + _averageCompressAndWriteTime.updateAverage(time); } @@ -319,67 +404,123 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& .arg(locale.toString((uint)getCurrentClientCount()).rightJustified(COLUMN_WIDTH, ' ')); float averageLoopTime = getAverageLoopTime(); - statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs\r\n", averageLoopTime); - qDebug() << "averageLoopTime=" << averageLoopTime; + statsString += QString().sprintf(" Average packetLoop() time: %7.2f msecs\r\n", averageLoopTime); float averageInsideTime = getAverageInsideTime(); - statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs\r\n", averageInsideTime); - qDebug() << "averageInsideTime=" << averageInsideTime; + statsString += QString().sprintf(" Average 'inside' time: %9.2f usecs\r\n\r\n", averageInsideTime); - int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait; + int allWaitTimes = _extraLongTreeWait +_longTreeWait + _shortTreeWait + _noTreeWait; float averageTreeWaitTime = getAverageTreeWaitTime(); - statsString += QString().sprintf(" Average tree lock wait time: %9.2f usecs samples: %12d \r\n", - averageTreeWaitTime, allWaitTimes); - qDebug() << "averageTreeWaitTime=" << averageTreeWaitTime; + statsString += QString().sprintf(" Average tree lock wait time:" + " %9.2f usecs samples: %12d \r\n", + averageTreeWaitTime, allWaitTimes); + + float zeroVsTotal = (allWaitTimes > 0) ? ((float)_noTreeWait / (float)allWaitTimes) : 0.0f; + statsString += QString().sprintf(" No Lock Wait:" + " (%6.2f%%) samples: %12d \r\n", + zeroVsTotal * AS_PERCENT, _noTreeWait); float shortVsTotal = (allWaitTimes > 0) ? ((float)_shortTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock short wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", - _averageTreeShortWaitTime.getAverage(), - shortVsTotal * AS_PERCENT, _shortTreeWait); - qDebug() << "averageTreeShortWaitTime=" << _averageTreeShortWaitTime.getAverage(); + statsString += QString().sprintf(" Avg tree lock short wait time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeShortWaitTime.getAverage(), + shortVsTotal * AS_PERCENT, _shortTreeWait); float longVsTotal = (allWaitTimes > 0) ? ((float)_longTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", - _averageTreeLongWaitTime.getAverage(), - longVsTotal * AS_PERCENT, _longTreeWait); - qDebug() << "averageTreeLongWaitTime=" << _averageTreeLongWaitTime.getAverage(); + statsString += QString().sprintf(" Avg tree lock long wait time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageTreeLongWaitTime.getAverage(), + longVsTotal * AS_PERCENT, _longTreeWait); float extraLongVsTotal = (allWaitTimes > 0) ? ((float)_extraLongTreeWait / (float)allWaitTimes) : 0.0f; - statsString += QString().sprintf("Avg tree lock extra long wait time: %9.2f usecs (%6.2f%%) samples: %12d \r\n", - _averageTreeExtraLongWaitTime.getAverage(), - extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); - qDebug() << "averageTreeExtraLongWaitTime=" << _averageTreeExtraLongWaitTime.getAverage(); + statsString += QString().sprintf(" Avg tree lock extra long wait time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", + _averageTreeExtraLongWaitTime.getAverage(), + extraLongVsTotal * AS_PERCENT, _extraLongTreeWait); float averageEncodeTime = getAverageEncodeTime(); - statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); - qDebug() << "averageEncodeTime=" << averageEncodeTime; + statsString += QString().sprintf(" Average encode time: %9.2f usecs\r\n", averageEncodeTime); + + int allEncodeTimes = _noEncode + _shortEncode + _longEncode + _extraLongEncode; + + float zeroVsTotalEncode = (allEncodeTimes > 0) ? ((float)_noEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf(" No Encode:" + " (%6.2f%%) samples: %12d \r\n", + zeroVsTotalEncode * AS_PERCENT, _noEncode); + + float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock short encode time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageShortEncodeTime.getAverage(), + shortVsTotalEncode * AS_PERCENT, _shortEncode); + + float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf(" Avg tree lock long encode time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageLongEncodeTime.getAverage(), + longVsTotalEncode * AS_PERCENT, _longEncode); + + float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f; + statsString += QString().sprintf("Avg tree lock extra long encode time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", + _averageExtraLongEncodeTime.getAverage(), + extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode); + float averageCompressAndWriteTime = getAverageCompressAndWriteTime(); - statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", averageCompressAndWriteTime); - qDebug() << "averageCompressAndWriteTime=" << averageCompressAndWriteTime; + statsString += QString().sprintf(" Average compress and write time: %9.2f usecs\r\n", averageCompressAndWriteTime); + + int allCompressTimes = _noCompress + _shortCompress + _longCompress + _extraLongCompress; + + float zeroVsTotalCompress = (allCompressTimes > 0) ? ((float)_noCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" No compression:" + " (%6.2f%%) samples: %12d \r\n", + zeroVsTotalCompress * AS_PERCENT, _noCompress); + + float shortVsTotalCompress = (allCompressTimes > 0) ? ((float)_shortCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" Avg short compress time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageShortCompressTime.getAverage(), + shortVsTotalCompress * AS_PERCENT, _shortCompress); + + float longVsTotalCompress = (allCompressTimes > 0) ? ((float)_longCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" Avg long compress time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n", + _averageLongCompressTime.getAverage(), + longVsTotalCompress * AS_PERCENT, _longCompress); + + float extraLongVsTotalCompress = (allCompressTimes > 0) ? ((float)_extraLongCompress / (float)allCompressTimes) : 0.0f; + statsString += QString().sprintf(" Avg extra long compress time:" + " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", + _averageExtraLongCompressTime.getAverage(), + extraLongVsTotalCompress * AS_PERCENT, _extraLongCompress); float averagePacketSendingTime = getAveragePacketSendingTime(); - statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", + statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", averagePacketSendingTime); - qDebug() << "averagePacketSendingTime=" << averagePacketSendingTime; - float averageNodeWaitTime = getAverageNodeWaitTime(); - statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); - qDebug() << "averageNodeWaitTime=" << averageNodeWaitTime; + statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); - statsString += QString().sprintf("------------------------------------------------------\r\n"); + statsString += QString().sprintf("--------------------------------------------------------------\r\n"); float encodeToInsidePercent = averageInsideTime == 0.0f ? 0.0f : (averageEncodeTime / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", + statsString += QString().sprintf(" encode ratio: %5.2f%%\r\n", encodeToInsidePercent); - qDebug() << "encodeToInsidePercent=" << encodeToInsidePercent; float waitToInsidePercent = averageInsideTime == 0.0f ? 0.0f : ((averageTreeWaitTime + averageNodeWaitTime) / averageInsideTime) * AS_PERCENT; - statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); - qDebug() << "waitToInsidePercent=" << waitToInsidePercent; + statsString += QString().sprintf(" waiting ratio: %5.2f%%\r\n", waitToInsidePercent); + + float compressAndWriteToInsidePercent = averageInsideTime == 0.0f ? 0.0f + : (averageCompressAndWriteTime / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" compress and write ratio: %5.2f%%\r\n", + compressAndWriteToInsidePercent); + + float sendingToInsidePercent = averageInsideTime == 0.0f ? 0.0f + : (averagePacketSendingTime / averageInsideTime) * AS_PERCENT; + statsString += QString().sprintf(" sending ratio: %5.2f%%\r\n", sendingToInsidePercent); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 636ecb8365..182fef81dd 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -73,11 +73,13 @@ public: virtual int sendSpecialPacket(const SharedNodePointer& node) { return 0; } static void attachQueryNodeToNode(Node* newNode); + + static float SKIP_TIME; // use this for trackXXXTime() calls for non-times static void trackLoopTime(float time) { _averageLoopTime.updateAverage(time); } static float getAverageLoopTime() { return _averageLoopTime.getAverage(); } - static void trackEncodeTime(float time) { _averageEncodeTime.updateAverage(time); } + static void trackEncodeTime(float time); static float getAverageEncodeTime() { return _averageEncodeTime.getAverage(); } static void trackInsideTime(float time) { _averageInsideTime.updateAverage(time); } @@ -89,7 +91,7 @@ public: static void trackNodeWaitTime(float time) { _averageNodeWaitTime.updateAverage(time); } static float getAverageNodeWaitTime() { return _averageNodeWaitTime.getAverage(); } - static void trackCompressAndWriteTime(float time) { _averageCompressAndWriteTime.updateAverage(time); } + static void trackCompressAndWriteTime(float time); static float getAverageCompressAndWriteTime() { return _averageCompressAndWriteTime.getAverage(); } static void trackPacketSendingTime(float time) { _averagePacketSendingTime.updateAverage(time); } @@ -135,18 +137,39 @@ protected: static int _clientCount; static SimpleMovingAverage _averageLoopTime; + static SimpleMovingAverage _averageEncodeTime; + static SimpleMovingAverage _averageShortEncodeTime; + static SimpleMovingAverage _averageLongEncodeTime; + static SimpleMovingAverage _averageExtraLongEncodeTime; + static int _extraLongEncode; + static int _longEncode; + static int _shortEncode; + static int _noEncode; + static SimpleMovingAverage _averageInsideTime; static SimpleMovingAverage _averageTreeWaitTime; static SimpleMovingAverage _averageTreeShortWaitTime; static SimpleMovingAverage _averageTreeLongWaitTime; static SimpleMovingAverage _averageTreeExtraLongWaitTime; - static SimpleMovingAverage _averageNodeWaitTime; - static SimpleMovingAverage _averageCompressAndWriteTime; - static SimpleMovingAverage _averagePacketSendingTime; static int _extraLongTreeWait; static int _longTreeWait; static int _shortTreeWait; + static int _noTreeWait; + + static SimpleMovingAverage _averageNodeWaitTime; + + static SimpleMovingAverage _averageCompressAndWriteTime; + static SimpleMovingAverage _averageShortCompressTime; + static SimpleMovingAverage _averageLongCompressTime; + static SimpleMovingAverage _averageExtraLongCompressTime; + static int _extraLongCompress; + static int _longCompress; + static int _shortCompress; + static int _noCompress; + + static SimpleMovingAverage _averagePacketSendingTime; + }; #endif // __octree_server__OctreeServer__ From 34b2ccb9d71ea867fa26833915a4fa7798f2262f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 00:02:47 -0700 Subject: [PATCH 21/51] adding not sent to stats --- .../src/octree/OctreeSendThread.cpp | 17 +++++------------ assignment-client/src/octree/OctreeServer.cpp | 17 +++++++++++++++++ assignment-client/src/octree/OctreeServer.h | 3 ++- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index e91b999c20..df7a1a91ee 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -419,7 +419,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue float lockWaitElapsedUsec = OctreeServer::SKIP_TIME; float encodeElapsedUsec = OctreeServer::SKIP_TIME; float compressAndWriteElapsedUsec = OctreeServer::SKIP_TIME; - float packetSendingElapsedUsec = 0.0f; + float packetSendingElapsedUsec = OctreeServer::SKIP_TIME; quint64 startInside = usecTimestampNow(); @@ -532,8 +532,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // the packet doesn't have enough space to bother attempting to pack more... bool sendNow = true; - quint64 packetSendingStart = usecTimestampNow(); - if (nodeData->getCurrentPacketIsCompressed() && nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && extraPackingAttempts <= REASONABLE_NUMBER_OF_PACKING_ATTEMPTS) { @@ -542,10 +540,11 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (sendNow) { - if (forceDebugging) { - qDebug("about to call handlePacketSend() .... line: %d -- sendNow = TRUE", __LINE__); - } + quint64 packetSendingStart = usecTimestampNow(); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); + quint64 packetSendingEnd = usecTimestampNow(); + packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); + if (wantCompression) { targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } @@ -558,14 +557,8 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // a larger compressed size then uncompressed size targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d",__LINE__, - debug::valueOf(nodeData->getWantCompression()), targetSize); - } _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset - quint64 packetSendingEnd = usecTimestampNow(); - packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); } OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); OctreeServer::trackEncodeTime(encodeElapsedUsec); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 377ff0ea7a..c3df8fc6ac 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -57,6 +57,7 @@ int OctreeServer::_shortCompress = 0; int OctreeServer::_noCompress = 0; SimpleMovingAverage OctreeServer::_averagePacketSendingTime(MOVING_AVERAGE_SAMPLE_COUNTS); +int OctreeServer::_noSend = 0; void OctreeServer::resetSendingStats() { @@ -93,6 +94,7 @@ void OctreeServer::resetSendingStats() { _noCompress = 0; _averagePacketSendingTime.reset(); + _noSend = 0; } void OctreeServer::trackEncodeTime(float time) { @@ -153,6 +155,15 @@ void OctreeServer::trackCompressAndWriteTime(float time) { _averageCompressAndWriteTime.updateAverage(time); } +void OctreeServer::trackPacketSendingTime(float time) { + if (time == SKIP_TIME) { + _noSend++; + time = 0.0f; + } + _averagePacketSendingTime.updateAverage(time); +} + + void OctreeServer::attachQueryNodeToNode(Node* newNode) { if (!newNode->getLinkedData()) { @@ -499,6 +510,12 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& float averagePacketSendingTime = getAveragePacketSendingTime(); statsString += QString().sprintf(" Average packet sending time: %9.2f usecs (includes node lock)\r\n", averagePacketSendingTime); + + float noVsTotalSend = (_averagePacketSendingTime.getSampleCount() > 0) ? + ((float)_noSend / (float)_averagePacketSendingTime.getSampleCount()) : 0.0f; + statsString += QString().sprintf(" Not sending:" + " (%6.2f%%) samples: %12d \r\n", + noVsTotalSend * AS_PERCENT, _noSend); float averageNodeWaitTime = getAverageNodeWaitTime(); statsString += QString().sprintf(" Average node lock wait time: %9.2f usecs\r\n", averageNodeWaitTime); diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 182fef81dd..44fca6f124 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -94,7 +94,7 @@ public: static void trackCompressAndWriteTime(float time); static float getAverageCompressAndWriteTime() { return _averageCompressAndWriteTime.getAverage(); } - static void trackPacketSendingTime(float time) { _averagePacketSendingTime.updateAverage(time); } + static void trackPacketSendingTime(float time); static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } bool handleHTTPRequest(HTTPConnection* connection, const QString& path); @@ -169,6 +169,7 @@ protected: static int _noCompress; static SimpleMovingAverage _averagePacketSendingTime; + static int _noSend; }; From beffb6deaef6e18bad1d4e9a3357c8fe023a2d13 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 01:04:52 -0700 Subject: [PATCH 22/51] clean up stats --- assignment-client/src/octree/OctreeServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c3df8fc6ac..34b457a8f7 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -461,19 +461,19 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QString& zeroVsTotalEncode * AS_PERCENT, _noEncode); float shortVsTotalEncode = (allEncodeTimes > 0) ? ((float)_shortEncode / (float)allEncodeTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock short encode time:" + statsString += QString().sprintf(" Avg short encode time:" " %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageShortEncodeTime.getAverage(), shortVsTotalEncode * AS_PERCENT, _shortEncode); float longVsTotalEncode = (allEncodeTimes > 0) ? ((float)_longEncode / (float)allEncodeTimes) : 0.0f; - statsString += QString().sprintf(" Avg tree lock long encode time:" + statsString += QString().sprintf(" Avg long encode time:" " %9.2f usecs (%6.2f%%) samples: %12d \r\n", _averageLongEncodeTime.getAverage(), longVsTotalEncode * AS_PERCENT, _longEncode); float extraLongVsTotalEncode = (allEncodeTimes > 0) ? ((float)_extraLongEncode / (float)allEncodeTimes) : 0.0f; - statsString += QString().sprintf("Avg tree lock extra long encode time:" + statsString += QString().sprintf(" Avg extra long encode time:" " %9.2f usecs (%6.2f%%) samples: %12d \r\n\r\n", _averageExtraLongEncodeTime.getAverage(), extraLongVsTotalEncode * AS_PERCENT, _extraLongEncode); From 329d3b37e0c75bd944058dd41fce440652a604ed Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 01:07:45 -0700 Subject: [PATCH 23/51] add last know root timestamp property to query node --- assignment-client/src/octree/OctreeQueryNode.cpp | 4 ++-- assignment-client/src/octree/OctreeQueryNode.h | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 18f2943a3c..cf57c4f1b5 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -36,12 +36,12 @@ OctreeQueryNode::OctreeQueryNode() : _lodChanged(false), _lodInitialized(false), _sequenceNumber(0), - _scheduleForDelete(false) + _scheduleForDelete(false), + _lastRootTimestamp(0) { } OctreeQueryNode::~OctreeQueryNode() { -qDebug() << "OctreeQueryNode::~OctreeQueryNode()"; if (_octreeSendThread) { _octreeSendThread->terminate(); delete _octreeSendThread; diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 18b00877ec..c103d87138 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -89,6 +89,10 @@ public: bool isScheduledForDelete() const { return _scheduleForDelete; } void scheduleForDelete() { _scheduleForDelete = true; } + quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } + void setLastRootTimestamp(quint64 timestamp) { _lastRootTimestamp = timestamp; } + + private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); @@ -125,6 +129,8 @@ private: OCTREE_PACKET_SEQUENCE _sequenceNumber; bool _scheduleForDelete; + + quint64 _lastRootTimestamp; }; #endif /* defined(__hifi__OctreeQueryNode__) */ From 86c2b5baa7c88c47eb2bb84d8cb24eb250f4c863 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 01:51:30 -0700 Subject: [PATCH 24/51] removed some debugging, added some comments, more work on optimizaiton --- .../src/octree/OctreeQueryNode.h | 2 + .../src/octree/OctreeSendThread.cpp | 171 +++++------------- 2 files changed, 52 insertions(+), 121 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index c103d87138..6f17117ca2 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -91,6 +91,8 @@ public: quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } void setLastRootTimestamp(quint64 timestamp) { _lastRootTimestamp = timestamp; } + unsigned int getlastOctreePacketLength() const { return _lastOctreePacketLength; } + int getDuplicatePacketCount() const { return _duplicatePacketCount; } private: diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index df7a1a91ee..132090f15d 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -262,23 +262,8 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // then let's just send that waiting packet. if (!nodeData->getCurrentPacketFormatMatches()) { if (nodeData->isPacketWaiting()) { - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("about to call handlePacketSend() .... line: %d -- format change " - "wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s " - "currentPacketIsCompressed=%s", - __LINE__, - debug::valueOf(wantColor), debug::valueOf(wantCompression), - debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); - } packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } else { - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s", - debug::valueOf(wantColor), debug::valueOf(wantCompression), - debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); - } nodeData->resetOctreePacket(); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; @@ -345,44 +330,25 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // track completed scenes and send out the stats packet accordingly nodeData->stats.sceneCompleted(); - ::endSceneSleepTime = _usleepTime; - unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; + nodeData->setLastRootTimestamp(_myServer->getOctree()->getRoot()->getLastChanged()); - unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); - unsigned long elapsedTime = nodeData->stats.getElapsedTime(); + // TODO: add these to stats page + //::endSceneSleepTime = _usleepTime; + //unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; + //unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); + //unsigned long elapsedTime = nodeData->stats.getElapsedTime(); - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("about to call handlePacketSend() .... line: %d -- completed scene", __LINE__ ); - } int packetsJustSent = handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval += packetsJustSent; - if (forceDebugging) { - qDebug("packetsJustSent=%d packetsSentThisInterval=%d", packetsJustSent, packetsSentThisInterval); - } - - if (forceDebugging || _myServer->wantsDebugSending()) { - qDebug() << "Scene completed at " << usecTimestampNow() - << "encodeTime:" << encodeTime - << " sleepTime:" << sleepTime - << " elapsed:" << elapsedTime - << " Packets:" << _totalPackets - << " Bytes:" << _totalBytes - << " Wasted:" << _totalWastedBytes; - } // If we're starting a full scene, then definitely we want to empty the nodeBag if (isFullScene) { nodeData->nodeBag.deleteAll(); } - if (forceDebugging || _myServer->wantsDebugSending()) { - qDebug() << "Scene started at " << usecTimestampNow() - << " Packets:" << _totalPackets - << " Bytes:" << _totalBytes - << " Wasted:" << _totalWastedBytes; - } - - ::startSceneSleepTime = _usleepTime; + // TODO: add these to stats page + //::startSceneSleepTime = _usleepTime; + // start tracking our stats nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot(), _myServer->getJurisdiction()); @@ -401,8 +367,10 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue if (!nodeData->nodeBag.isEmpty()) { int bytesWritten = 0; quint64 start = usecTimestampNow(); - quint64 startCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; - quint64 startCompressCalls = OctreePacketData::getCompressContentCalls(); + + // TODO: add these to stats page + //quint64 startCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; + //quint64 startCompressCalls = OctreePacketData::getCompressContentCalls(); int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); @@ -432,34 +400,58 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue bool lastNodeDidntFit = false; // assume each node fits if (!nodeData->nodeBag.isEmpty()) { OctreeElement* subTree = nodeData->nodeBag.extract(); + + /* TODO: Looking for a way to prevent locking and encoding a tree that is not + // going to result in any packets being sent... + // + // If our node is root, and the root hasn't changed, and our view hasn't changed, + // and we've already seen at least one duplicate packet, then we probably don't need + // to lock the tree and encode, because the result should be that no bytes will be + // encoded, and this will be a duplicate packet from the last one we sent... + OctreeElement* root = _myServer->getOctree()->getRoot(); + bool skipEncode = false; + if ( + (subTree == root) + && (nodeData->getLastRootTimestamp() == root->getLastChanged()) + && !viewFrustumChanged + && (nodeData->getDuplicatePacketCount() > 0) + ) { + qDebug() << "is root, root not changed, view not changed, already seen a duplicate!" + << "Can we skip it?"; + skipEncode = true; + } + */ + bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - + float voxelSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); - + int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() - ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - + ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, wantOcclusionCulling, coverageMap, boundaryLevelAdjust, voxelSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction()); - + // TODO: should this include the lock time or not? This stat is sent down to the client, + // it seems like it may be a good idea to include the lock time as part of the encode time + // are reported to client. Since you can encode without the lock + nodeData->stats.encodeStarted(); + quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->lockForRead(); quint64 lockWaitEnd = usecTimestampNow(); lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - nodeData->stats.encodeStarted(); - quint64 encodeStart = usecTimestampNow(); bytesWritten = _myServer->getOctree()->encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); quint64 encodeEnd = usecTimestampNow(); encodeElapsedUsec = (float)(encodeEnd - encodeStart); - + // If after calling encodeTreeBitstream() there are no nodes left to send, then we know we've // sent the entire scene. We want to know this below so we'll actually write this content into // the packet and send it @@ -509,19 +501,9 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue if (writtenSize > nodeData->getAvailable()) { - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("about to call handlePacketSend() .... line: %d -- " - "writtenSize[%d] > available[%d] too big, sending packet as is.", - __LINE__, writtenSize, nodeData->getAvailable()); - } packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug(">>>>>> calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%u", - nodeData->getAvailable(), _packetData.getFinalizedSize(), - _packetData.getUncompressedSize(), _packetData.getTargetSize()); - } nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); extraPackingAttempts = 0; quint64 compressAndWriteEnd = usecTimestampNow(); @@ -568,18 +550,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 endInside = usecTimestampNow(); quint64 elapsedInsideUsecs = endInside - startInside; OctreeServer::trackInsideTime((float)elapsedInsideUsecs); - - const bool wantExtraDebugging = false; - if (wantExtraDebugging) { - float insideMsecs = (float)elapsedInsideUsecs / (float)USECS_PER_MSEC; - if (insideMsecs > 1.0f) { - qDebug()<< "inside msecs=" << insideMsecs - << "lockWait usec=" << lockWaitElapsedUsec - << "encode usec=" << encodeElapsedUsec - << "compress usec=" << compressAndWriteElapsedUsec - << "sending usec=" << packetSendingElapsedUsec; - } - } } @@ -597,63 +567,22 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int elapsedmsec = (end - start)/USECS_PER_MSEC; OctreeServer::trackLoopTime(elapsedmsec); - quint64 endCompressCalls = OctreePacketData::getCompressContentCalls(); - int elapsedCompressCalls = endCompressCalls - startCompressCalls; - - quint64 endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; - int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; - - bool wantsExtraDebugging = false; - if (wantsExtraDebugging) { - if (elapsedmsec > 100) { - if (elapsedmsec > 1000) { - int elapsedsec = (end - start)/1000000; - qDebug("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets %d nodes still to send", - elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } else { - qDebug("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets, %d nodes still to send", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } - } else if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] " - "to generate %d bytes in %d packets, %d nodes still to send", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, - trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } - } + // TODO: add these to stats page + //quint64 endCompressCalls = OctreePacketData::getCompressContentCalls(); + //int elapsedCompressCalls = endCompressCalls - startCompressCalls; + //quint64 endCompressTimeMsecs = OctreePacketData::getCompressContentTime() / 1000; + //int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; // if after sending packets we've emptied our bag, then we want to remember that we've sent all // the voxels from the current view frustum if (nodeData->nodeBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - nodeData->map.printStats(); - } nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d " - "server PPI=%d nodePPS=%d nodePPI=%d", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, - _myServer->getPacketsPerClientPerInterval(), nodeData->getMaxOctreePacketsPerSecond(), - clientMaxPacketsPerInterval); - } - } // end if bag wasn't empty, and so we sent stuff... - const bool wantExtraDebugging = false; - if (wantExtraDebugging) { - if (truePacketsSent > 0 || packetsSentThisInterval > 0) { - qDebug() << "truePacketsSent=" << truePacketsSent << "packetsSentThisInterval=" << packetsSentThisInterval; - } - } - return truePacketsSent; } From dfb07e717db9686cad7177e478788a9a17ed0004 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 09:34:24 -0700 Subject: [PATCH 25/51] removed old debugging code --- .../src/octree/OctreeSendThread.cpp | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 132090f15d..6cd5d65340 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -56,9 +56,6 @@ bool OctreeSendThread::process() { // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); - } packetDistributor(node, nodeData, viewFrustumChanged); } if (nodeData->isScheduledForDelete()) { @@ -68,10 +65,6 @@ bool OctreeSendThread::process() { } else { _nodeMissingCount++; } - } else { - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("OctreeSendThread::process() waiting for isInitialLoadComplete()"); - } } // Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap @@ -84,10 +77,6 @@ bool OctreeSendThread::process() { PerformanceWarning warn(false,"OctreeSendThread... usleep()",false,&_usleepTime,&_usleepCalls); usleep(usecToSleep); } else { - if ((_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug() << "Last send took too much time (" << (elapsed / USECS_PER_MSEC) - <<" msecs), barely sleeping 1 usec!\n"; - } const int MIN_USEC_TO_SLEEP = 1; usleep(MIN_USEC_TO_SLEEP); } @@ -270,49 +259,15 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue if (wantCompression) { targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d", __LINE__, - debug::valueOf(wantCompression), targetSize); - } - _packetData.changeSettings(wantCompression, targetSize); } - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s", - debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()), - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving())); - } - const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("packetDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s", - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()), - debug::valueOf(nodeData->getViewSent()) - ); - } - // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { quint64 now = usecTimestampNow(); - if (forceDebugging || (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug())) { - qDebug("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...", - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); - if (nodeData->getLastTimeBagEmpty() > 0) { - float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f; - if (viewFrustumChanged) { - qDebug("viewFrustumChanged resetting after elapsed time to send scene = %f seconds", elapsedSceneSend); - } else { - qDebug("elapsed time to send scene = %f seconds", elapsedSceneSend); - } - qDebug("[ occlusionCulling:%s, wantDelta:%s, wantColor:%s ]", - debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta), - debug::valueOf(wantColor)); - } - } // if our view has changed, we need to reset these things... if (viewFrustumChanged) { @@ -375,12 +330,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxOctreePacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), - nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval); - } - int extraPackingAttempts = 0; bool completedScene = false; while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { @@ -391,12 +340,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue quint64 startInside = usecTimestampNow(); - if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { - qDebug("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), - nodeData->getMaxOctreePacketsPerSecond(), clientMaxPacketsPerInterval); - } - bool lastNodeDidntFit = false; // assume each node fits if (!nodeData->nodeBag.isEmpty()) { OctreeElement* subTree = nodeData->nodeBag.extract(); @@ -585,4 +528,3 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue return truePacketsSent; } - From f2cc227331d4f1ae4f1f3b48e5be470c898c62b3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 10:17:32 -0700 Subject: [PATCH 26/51] Ryan's requested change for rotation smoothing. --- interface/resources/visage/tracker.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/visage/tracker.cfg b/interface/resources/visage/tracker.cfg index b5ed3302fa..10744da6e5 100644 --- a/interface/resources/visage/tracker.cfg +++ b/interface/resources/visage/tracker.cfg @@ -40,7 +40,7 @@ detect_strip_roi_width 2 detect_strip_roi_height 4 smoothing_factors - 150 15 -2 100 -1 50 50 0 + 150 5 -2 100 -1 50 50 0 #translation rotation action_units eyebrows mouth gaze eye_closure other process_eyes 1 From 299dbb93eaedee17696c496e72338e171a2fd15b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 13:57:36 -0700 Subject: [PATCH 27/51] Removed "springiness" bits. --- interface/src/renderer/FBXReader.cpp | 48 +----- interface/src/renderer/FBXReader.h | 4 - interface/src/renderer/GeometryCache.cpp | 19 +-- interface/src/renderer/Model.cpp | 195 ++++++----------------- interface/src/renderer/Model.h | 3 - 5 files changed, 58 insertions(+), 211 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 8bf5583a02..22cd44408e 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1331,14 +1331,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) geometry.staticExtents.reset(); geometry.meshExtents.reset(); - QVariantHash springs = mapping.value("spring").toHash(); - QVariant defaultSpring = springs.value("default"); for (QHash::iterator it = meshes.begin(); it != meshes.end(); it++) { ExtractedMesh& extracted = it.value(); // accumulate local transforms QString modelID = models.contains(it.key()) ? it.key() : parentMap.value(it.key()); - extracted.mesh.springiness = springs.value(models.value(modelID).name, defaultSpring).toFloat(); glm::mat4 modelTransform = getGlobalTransform(parentMap, models, modelID); // compute the mesh extents from the transformed vertices @@ -1591,49 +1588,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); - - // extract spring edges, connections if springy - if (extracted.mesh.springiness > 0.0f) { - QSet > edges; - - extracted.mesh.vertexConnections.resize(extracted.mesh.vertices.size()); - foreach (const FBXMeshPart& part, extracted.mesh.parts) { - for (int i = 0; i < part.quadIndices.size(); i += 4) { - int index0 = part.quadIndices.at(i); - int index1 = part.quadIndices.at(i + 1); - int index2 = part.quadIndices.at(i + 2); - int index3 = part.quadIndices.at(i + 3); - - edges.insert(QPair(qMin(index0, index1), qMax(index0, index1))); - edges.insert(QPair(qMin(index1, index2), qMax(index1, index2))); - edges.insert(QPair(qMin(index2, index3), qMax(index2, index3))); - edges.insert(QPair(qMin(index3, index0), qMax(index3, index0))); - - extracted.mesh.vertexConnections[index0].append(QPair(index3, index1)); - extracted.mesh.vertexConnections[index1].append(QPair(index0, index2)); - extracted.mesh.vertexConnections[index2].append(QPair(index1, index3)); - extracted.mesh.vertexConnections[index3].append(QPair(index2, index0)); - } - for (int i = 0; i < part.triangleIndices.size(); i += 3) { - int index0 = part.triangleIndices.at(i); - int index1 = part.triangleIndices.at(i + 1); - int index2 = part.triangleIndices.at(i + 2); - - edges.insert(QPair(qMin(index0, index1), qMax(index0, index1))); - edges.insert(QPair(qMin(index1, index2), qMax(index1, index2))); - edges.insert(QPair(qMin(index2, index0), qMax(index2, index0))); - - extracted.mesh.vertexConnections[index0].append(QPair(index2, index1)); - extracted.mesh.vertexConnections[index1].append(QPair(index0, index2)); - extracted.mesh.vertexConnections[index2].append(QPair(index1, index0)); - } - } - - for (QSet >::const_iterator edge = edges.constBegin(); edge != edges.constEnd(); edge++) { - extracted.mesh.springEdges.append(*edge); - } - } - + geometry.meshes.append(extracted.mesh); } @@ -1797,7 +1752,6 @@ FBXGeometry readSVO(const QByteArray& model) { // and one mesh with one cluster and one part FBXMesh mesh; mesh.isEye = false; - mesh.springiness = 0.0f; FBXCluster cluster = { 0 }; mesh.clusters.append(cluster); diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 3f0fc3e580..ead75e6517 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -130,10 +130,6 @@ public: bool isEye; QVector blendshapes; - - float springiness; - QVector > springEdges; - QVector, 4> > vertexConnections; }; /// An attachment to an FBX document. diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index c815eda030..bd5915397b 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -565,8 +565,8 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkMesh.vertexBuffer.bind(); networkMesh.vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); - // if we don't need to do any blending or springing, then the positions/normals can be static - if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { + // if we don't need to do any blending, the positions/normals can be static + if (mesh.blendshapes.isEmpty()) { int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3); @@ -587,8 +587,8 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(), mesh.clusterWeights.size() * sizeof(glm::vec4)); - // if there's no springiness, then the cluster indices/weights can be static - } else if (mesh.springiness == 0.0f) { + // otherwise, at least the cluster indices/weights can be static + } else { int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); @@ -601,16 +601,7 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { networkMesh.vertexBuffer.write(clusterIndicesOffset, mesh.clusterIndices.constData(), mesh.clusterIndices.size() * sizeof(glm::vec4)); networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(), - mesh.clusterWeights.size() * sizeof(glm::vec4)); - - } else { - int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - networkMesh.vertexBuffer.allocate(texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2)); - networkMesh.vertexBuffer.write(0, mesh.tangents.constData(), mesh.tangents.size() * sizeof(glm::vec3)); - networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3)); - networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(), - mesh.texCoords.size() * sizeof(glm::vec2)); + mesh.clusterWeights.size() * sizeof(glm::vec4)); } networkMesh.vertexBuffer.release(); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 60fae5e596..df6d41ebbc 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -175,7 +175,7 @@ bool Model::render(float alpha) { if (_blendedVertexBufferIDs.isEmpty()) { foreach (const FBXMesh& mesh, geometry.meshes) { GLuint id = 0; - if (!mesh.blendshapes.isEmpty() || mesh.springiness > 0.0f) { + if (!mesh.blendshapes.isEmpty()) { glGenBuffers(1, &id); glBindBuffer(GL_ARRAY_BUFFER, id); glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), @@ -490,11 +490,6 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector foreach (const FBXMesh& mesh, geometry.meshes) { MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); - if (mesh.springiness > 0.0f) { - state.worldSpaceVertices.resize(mesh.vertices.size()); - state.vertexVelocities.resize(mesh.vertices.size()); - state.worldSpaceNormals.resize(mesh.vertices.size()); - } _meshStates.append(state); } foreach (const FBXAttachment& attachment, geometry.attachments) { @@ -541,80 +536,6 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector const FBXCluster& cluster = mesh.clusters.at(j); state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; } - int vertexCount = state.worldSpaceVertices.size(); - if (vertexCount == 0) { - continue; - } - glm::vec3* destVertices = state.worldSpaceVertices.data(); - glm::vec3* destVelocities = state.vertexVelocities.data(); - glm::vec3* destNormals = state.worldSpaceNormals.data(); - - const glm::vec3* sourceVertices = mesh.vertices.constData(); - if (!mesh.blendshapes.isEmpty()) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - - // blend in each coefficient - for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { - float coefficient = _blendshapeCoefficients[j]; - if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { - _blendedVertices[*index] += *vertex * coefficient; - } - } - sourceVertices = _blendedVertices.constData(); - } - glm::mat4 transform = glm::translate(_translation); - if (mesh.clusters.size() > 1) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - - // skin each vertex - const glm::vec4* clusterIndices = mesh.clusterIndices.constData(); - const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); - for (int j = 0; j < vertexCount; j++) { - _blendedVertices[j] = - glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + - glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + - glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + - glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; - } - sourceVertices = _blendedVertices.constData(); - - } else { - transform = state.clusterMatrices[0]; - } - if (_resetStates) { - for (int j = 0; j < vertexCount; j++) { - destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); - destVelocities[j] = glm::vec3(); - } - } else { - const float SPRINGINESS_MULTIPLIER = 200.0f; - const float DAMPING = 5.0f; - for (int j = 0; j < vertexCount; j++) { - destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * - mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; - destVertices[j] += destVelocities[j] * deltaTime; - } - } - for (int j = 0; j < vertexCount; j++) { - destNormals[j] = glm::vec3(); - - const glm::vec3& middle = destVertices[j]; - for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); - connection != mesh.vertexConnections.at(j).constEnd(); connection++) { - destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, - destVertices[connection->first] - middle)); - } - } } _resetStates = false; } @@ -980,34 +901,30 @@ void Model::renderMeshes(float alpha, bool translucent) { const MeshState& state = _meshStates.at(i); ProgramObject* activeProgram = program; int tangentLocation = _normalMapTangentLocation; - if (state.worldSpaceVertices.isEmpty()) { - glPushMatrix(); - Application::getInstance()->loadTranslatedViewMatrix(_translation); - - if (state.clusterMatrices.size() > 1) { - skinProgram->bind(); - glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, - (const float*)state.clusterMatrices.constData()); - int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) + - mesh.texCoords.size() * sizeof(glm::vec2) + - (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); - skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); - skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, - offset + vertexCount * sizeof(glm::vec4), 4); - skinProgram->enableAttributeArray(skinLocations->clusterIndices); - skinProgram->enableAttributeArray(skinLocations->clusterWeights); - activeProgram = skinProgram; - tangentLocation = skinLocations->tangent; - - } else { - glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); - program->bind(); - } - } else { + glPushMatrix(); + Application::getInstance()->loadTranslatedViewMatrix(_translation); + + if (state.clusterMatrices.size() > 1) { + skinProgram->bind(); + glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, + (const float*)state.clusterMatrices.constData()); + int offset = (mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3) + + mesh.texCoords.size() * sizeof(glm::vec2) + + (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); + skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); + skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, + offset + vertexCount * sizeof(glm::vec4), 4); + skinProgram->enableAttributeArray(skinLocations->clusterIndices); + skinProgram->enableAttributeArray(skinLocations->clusterWeights); + activeProgram = skinProgram; + tangentLocation = skinLocations->tangent; + + } else { + glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); program->bind(); } - if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { + if (mesh.blendshapes.isEmpty()) { if (!mesh.tangents.isEmpty()) { activeProgram->setAttributeBuffer(tangentLocation, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); activeProgram->enableAttributeArray(tangentLocation); @@ -1026,38 +943,31 @@ void Model::renderMeshes(float alpha, bool translucent) { glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); - if (!state.worldSpaceVertices.isEmpty()) { - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), state.worldSpaceVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), state.worldSpaceNormals.constData()); - - } else { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - _blendedNormals.resize(_blendedVertices.size()); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3)); - - // blend in each coefficient - for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { - float coefficient = _blendshapeCoefficients[j]; - if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const float NORMAL_COEFFICIENT_SCALE = 0.01f; - float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { - _blendedVertices[*index] += *vertex * coefficient; - _blendedNormals[*index] += *normal * normalCoefficient; - } + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + _blendedNormals.resize(_blendedVertices.size()); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3)); + + // blend in each coefficient + for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { + float coefficient = _blendshapeCoefficients[j]; + if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { + continue; + } + const float NORMAL_COEFFICIENT_SCALE = 0.01f; + float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { + _blendedVertices[*index] += *vertex * coefficient; + _blendedNormals[*index] += *normal * normalCoefficient; } - - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); } + + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); + glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), + vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); } glVertexPointer(3, GL_FLOAT, 0, 0); glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); @@ -1126,14 +1036,13 @@ void Model::renderMeshes(float alpha, bool translucent) { activeProgram->disableAttributeArray(tangentLocation); } - - if (state.worldSpaceVertices.isEmpty()) { - if (state.clusterMatrices.size() > 1) { - skinProgram->disableAttributeArray(skinLocations->clusterIndices); - skinProgram->disableAttributeArray(skinLocations->clusterWeights); - } - glPopMatrix(); - } + + if (state.clusterMatrices.size() > 1) { + skinProgram->disableAttributeArray(skinLocations->clusterIndices); + skinProgram->disableAttributeArray(skinLocations->clusterWeights); + } + glPopMatrix(); + activeProgram->release(); } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 165465d2cc..5b1fbb3eea 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -219,9 +219,6 @@ protected: class MeshState { public: QVector clusterMatrices; - QVector worldSpaceVertices; - QVector vertexVelocities; - QVector worldSpaceNormals; }; QVector _meshStates; From 88fd686126eccb2afc62c97aeebf7b1fcd104d53 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 15:59:02 -0700 Subject: [PATCH 28/51] tweak thread tests --- tests/threads/src/SampleReadThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/threads/src/SampleReadThread.cpp b/tests/threads/src/SampleReadThread.cpp index 129c3f098b..79693dc791 100644 --- a/tests/threads/src/SampleReadThread.cpp +++ b/tests/threads/src/SampleReadThread.cpp @@ -43,7 +43,7 @@ bool SampleReadThread::process() { for(int i = 0; i < LOTS_OF_OPERATIONS; i++) { float x = rand(); float y = rand(); - float z = x * y; + y = x * y; } } quint64 endWork = usecTimestampNow(); From 220232312dc8cb7a45b6dc65732068b1d4f05fec Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 16:06:20 -0700 Subject: [PATCH 29/51] remove unused variables --- assignment-client/src/octree/OctreeSendThread.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 6cd5d65340..2490640952 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -227,8 +227,6 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node, OctreeQuer /// Version of voxel distributor that sends the deepest LOD level at once int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged) { - bool forceDebugging = false; - int truePacketsSent = 0; int trueBytesSent = 0; int packetsSentThisInterval = 0; @@ -267,7 +265,6 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { - quint64 now = usecTimestampNow(); // if our view has changed, we need to reset these things... if (viewFrustumChanged) { From 635f3b6dc387fd6bd1e47cc14bb750f2cfd4eaa3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 16:38:05 -0700 Subject: [PATCH 30/51] Perform the mesh blending in worker threads and only when we've actually received new data. Closes #2075. Closes #2348. --- interface/src/avatar/MyAvatar.cpp | 5 - interface/src/devices/Faceshift.cpp | 4 +- interface/src/devices/Faceshift.h | 8 +- interface/src/devices/Visage.h | 6 +- interface/src/renderer/GeometryCache.cpp | 8 ++ interface/src/renderer/GeometryCache.h | 12 +- interface/src/renderer/Model.cpp | 161 ++++++++++++++++------- interface/src/renderer/Model.h | 20 +-- interface/src/renderer/TextureCache.h | 2 +- libraries/avatars/src/HeadData.h | 7 +- 10 files changed, 155 insertions(+), 78 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6c51026097..fb0d704c6a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -424,11 +424,6 @@ void MyAvatar::updateFromGyros(float deltaTime) { } } -static TextRenderer* textRenderer() { - static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); - return renderer; -} - void MyAvatar::renderDebugBodyPoints() { glm::vec3 torsoPosition(getPosition()); glm::vec3 headPosition(getHead()->getEyePosition()); diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 88974ce493..9f1734c7e5 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -103,7 +103,7 @@ void Faceshift::reset() { } void Faceshift::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, std::vector& coefficients) const { + float jawOpen, QVector& coefficients) const { coefficients.resize(max((int)coefficients.size(), _jawOpenIndex + 1)); qFill(coefficients.begin(), coefficients.end(), 0.0f); coefficients[_leftBlinkIndex] = leftBlink; @@ -204,7 +204,7 @@ void Faceshift::receive(const QByteArray& buffer) { _eyeGazeLeftYaw = data.m_eyeGazeLeftYaw; _eyeGazeRightPitch = -data.m_eyeGazeRightPitch; _eyeGazeRightYaw = data.m_eyeGazeRightYaw; - _blendshapeCoefficients = data.m_coeffs; + _blendshapeCoefficients = QVector::fromStdVector(data.m_coeffs); _lastTrackingStateReceived = usecTimestampNow(); } diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index a0898c446d..f878056b57 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -9,8 +9,6 @@ #ifndef __interface__Faceshift__ #define __interface__Faceshift__ -#include - #include #include @@ -47,7 +45,7 @@ public: float getEstimatedEyePitch() const { return _estimatedEyePitch; } float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); } float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); } @@ -68,7 +66,7 @@ public: void reset(); void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen, std::vector& coefficients) const; + float jawOpen, QVector& coefficients) const; signals: @@ -111,7 +109,7 @@ private: float _eyeGazeRightPitch; float _eyeGazeRightYaw; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; int _leftBlinkIndex; int _rightBlinkIndex; diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index 7e50812ba7..6e98abbb61 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -9,8 +9,6 @@ #ifndef __interface__Visage__ #define __interface__Visage__ -#include - #include #include #include @@ -42,7 +40,7 @@ public: float getEstimatedEyePitch() const { return _estimatedEyePitch; } float getEstimatedEyeYaw() const { return _estimatedEyeYaw; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } void update(); void reset(); @@ -71,7 +69,7 @@ private: float _estimatedEyePitch; float _estimatedEyeYaw; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; }; #endif /* defined(__interface__Visage__) */ diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index bd5915397b..c4a0d15baa 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -13,6 +13,7 @@ #include "Application.h" #include "GeometryCache.h" +#include "Model.h" #include "world.h" GeometryCache::~GeometryCache() { @@ -291,6 +292,13 @@ QSharedPointer GeometryCache::getGeometry(const QUrl& url, cons return getResource(url, fallback, delayLoad).staticCast(); } +void GeometryCache::setBlendedVertices(const QPointer& model, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals) { + if (!model.isNull() && model->getGeometry() == geometry) { + model->setBlendedVertices(vertices, normals); + } +} + QSharedPointer GeometryCache::createResource(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, const void* extra) { diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index cc0775051a..252a0c401b 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -19,15 +19,18 @@ #include "FBXReader.h" +class Model; class NetworkGeometry; class NetworkMesh; class NetworkTexture; /// Stores cached geometry. class GeometryCache : public ResourceCache { + Q_OBJECT + public: - ~GeometryCache(); + virtual ~GeometryCache(); void renderHemisphere(int slices, int stacks); void renderSquare(int xDivisions, int yDivisions); @@ -38,7 +41,12 @@ public: /// \param fallback a fallback URL to load if the desired one is unavailable /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested QSharedPointer getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); - + +public slots: + + void setBlendedVertices(const QPointer& model, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals); + protected: virtual QSharedPointer createResource(const QUrl& url, diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index df6d41ebbc..591cc4a021 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -6,6 +6,10 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include +#include +#include + #include #include @@ -19,6 +23,10 @@ using namespace std; +static int modelPointerTypeId = qRegisterMetaType >(); +static int weakNetworkGeometryPointerTypeId = qRegisterMetaType >(); +static int vec3VectorTypeId = qRegisterMetaType >(); + Model::Model(QObject* parent) : QObject(parent), _scale(1.0f, 1.0f, 1.0f), @@ -104,8 +112,6 @@ void Model::init() { } void Model::reset() { - _resetStates = true; - foreach (Model* attachment, _attachments) { attachment->reset(); } @@ -170,20 +176,10 @@ bool Model::render(float alpha) { return false; } - // set up blended buffer ids on first render after load/simulate + // set up dilated textures on first render after load/simulate const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (_blendedVertexBufferIDs.isEmpty()) { + if (_dilatedTextures.isEmpty()) { foreach (const FBXMesh& mesh, geometry.meshes) { - GLuint id = 0; - if (!mesh.blendshapes.isEmpty()) { - glGenBuffers(1, &id); - glBindBuffer(GL_ARRAY_BUFFER, id); - glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3), - NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - _blendedVertexBufferIDs.append(id); - QVector > dilated; dilated.resize(mesh.parts.size()); _dilatedTextures.append(dilated); @@ -478,6 +474,68 @@ QVector Model::updateGeometry() { return newJointStates; } +class Blender : public QRunnable { +public: + + Blender(Model* model, const QWeakPointer& geometry, + const QVector& meshes, const QVector& blendshapeCoefficients); + + virtual void run(); + +private: + + QPointer _model; + QWeakPointer _geometry; + QVector _meshes; + QVector _blendshapeCoefficients; +}; + +Blender::Blender(Model* model, const QWeakPointer& geometry, + const QVector& meshes, const QVector& blendshapeCoefficients) : + _model(model), + _geometry(geometry), + _meshes(meshes), + _blendshapeCoefficients(blendshapeCoefficients) { +} + +void Blender::run() { + // make sure the model/geometry still exists + if (_model.isNull() || _geometry.isNull()) { + return; + } + QVector vertices, normals; + int offset = 0; + foreach (const FBXMesh& mesh, _meshes) { + if (mesh.blendshapes.isEmpty()) { + continue; + } + vertices += mesh.vertices; + normals += mesh.normals; + glm::vec3* meshVertices = vertices.data() + offset; + glm::vec3* meshNormals = normals.data() + offset; + offset += mesh.vertices.size(); + const float NORMAL_COEFFICIENT_SCALE = 0.01f; + for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) { + float vertexCoefficient = _blendshapeCoefficients.at(i); + if (vertexCoefficient < EPSILON) { + continue; + } + float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE; + const FBXBlendshape& blendshape = mesh.blendshapes.at(i); + for (int j = 0; j < blendshape.indices.size(); j++) { + int index = blendshape.indices.at(j); + meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient; + meshNormals[index] += blendshape.normals.at(j) * normalCoefficient; + } + } + } + + // post the result to the geometry cache, which will dispatch to the model if still alive + QMetaObject::invokeMethod(Application::getInstance()->getGeometryCache(), "setBlendedVertices", + Q_ARG(const QPointer&, _model), Q_ARG(const QWeakPointer&, _geometry), + Q_ARG(const QVector&, vertices), Q_ARG(const QVector&, normals)); +} + void Model::simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates) { if (!isActive()) { return; @@ -491,6 +549,19 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); _meshStates.append(state); + + QOpenGLBuffer buffer; + if (!mesh.blendshapes.isEmpty()) { + buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); + buffer.create(); + buffer.bind(); + buffer.allocate((mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3)); + buffer.write(0, mesh.vertices.constData(), mesh.vertices.size() * sizeof(glm::vec3)); + buffer.write(mesh.vertices.size() * sizeof(glm::vec3), mesh.normals.constData(), + mesh.normals.size() * sizeof(glm::vec3)); + buffer.release(); + } + _blendedVertexBuffers.append(buffer); } foreach (const FBXAttachment& attachment, geometry.attachments) { Model* model = new Model(this); @@ -498,12 +569,12 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector model->setURL(attachment.url); _attachments.append(model); } - _resetStates = fullUpdate = true; + fullUpdate = true; createCollisionShapes(); } // exit early if we don't have to perform a full update - if (!(fullUpdate || _resetStates)) { + if (!fullUpdate) { return; } @@ -537,7 +608,9 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; } } - _resetStates = false; + + // post the blender + QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients)); } void Model::updateJointState(int index) { @@ -836,6 +909,27 @@ void Model::applyCollision(CollisionInfo& collision) { } } +void Model::setBlendedVertices(const QVector& vertices, const QVector& normals) { + if (_blendedVertexBuffers.isEmpty()) { + return; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + int index = 0; + for (int i = 0; i < geometry.meshes.size(); i++) { + const FBXMesh& mesh = geometry.meshes.at(i); + if (mesh.blendshapes.isEmpty()) { + continue; + } + QOpenGLBuffer& buffer = _blendedVertexBuffers[i]; + buffer.bind(); + buffer.write(0, vertices.constData() + index, mesh.vertices.size() * sizeof(glm::vec3)); + buffer.write(mesh.vertices.size() * sizeof(glm::vec3), normals.constData() + index, + mesh.normals.size() * sizeof(glm::vec3)); + buffer.release(); + index += mesh.vertices.size(); + } +} + void Model::applyNextGeometry() { // delete our local geometry and custom textures deleteGeometry(); @@ -854,10 +948,7 @@ void Model::deleteGeometry() { delete attachment; } _attachments.clear(); - foreach (GLuint id, _blendedVertexBufferIDs) { - glDeleteBuffers(1, &id); - } - _blendedVertexBufferIDs.clear(); + _blendedVertexBuffers.clear(); _jointStates.clear(); _meshStates.clear(); clearShapes(); @@ -941,33 +1032,7 @@ void Model::renderMeshes(float alpha, bool translucent) { } glColorPointer(3, GL_FLOAT, 0, (void*)(mesh.tangents.size() * sizeof(glm::vec3))); glTexCoordPointer(2, GL_FLOAT, 0, (void*)((mesh.tangents.size() + mesh.colors.size()) * sizeof(glm::vec3))); - glBindBuffer(GL_ARRAY_BUFFER, _blendedVertexBufferIDs.at(i)); - - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - _blendedNormals.resize(_blendedVertices.size()); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - memcpy(_blendedNormals.data(), mesh.normals.constData(), vertexCount * sizeof(glm::vec3)); - - // blend in each coefficient - for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { - float coefficient = _blendshapeCoefficients[j]; - if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const float NORMAL_COEFFICIENT_SCALE = 0.01f; - float normalCoefficient = coefficient * NORMAL_COEFFICIENT_SCALE; - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - const glm::vec3* normal = mesh.blendshapes[j].normals.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++, normal++) { - _blendedVertices[*index] += *vertex * coefficient; - _blendedNormals[*index] += *normal * normalCoefficient; - } - } - - glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * sizeof(glm::vec3), _blendedVertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, vertexCount * sizeof(glm::vec3), - vertexCount * sizeof(glm::vec3), _blendedNormals.constData()); + _blendedVertexBuffers[i].bind(); } glVertexPointer(3, GL_FLOAT, 0, 0); glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3))); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5b1fbb3eea..f08a6b9fc2 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -43,8 +43,8 @@ public: void setPupilDilation(float dilation) { _pupilDilation = dilation; } float getPupilDilation() const { return _pupilDilation; } - void setBlendshapeCoefficients(const std::vector& coefficients) { _blendshapeCoefficients = coefficients; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } bool isActive() const { return _geometry && _geometry->isLoaded(); } @@ -195,6 +195,9 @@ public: /// Use the collision to affect the model void applyCollision(CollisionInfo& collision); + /// Sets blended vertices computed in a separate thread. + void setBlendedVertices(const QVector& vertices, const QVector& normals); + protected: QSharedPointer _geometry; @@ -268,16 +271,13 @@ private: float _nextLODHysteresis; float _pupilDilation; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; QUrl _url; - QVector _blendedVertexBufferIDs; - QVector > > _dilatedTextures; - bool _resetStates; + QVector _blendedVertexBuffers; - QVector _blendedVertices; - QVector _blendedNormals; + QVector > > _dilatedTextures; QVector _attachments; @@ -303,4 +303,8 @@ private: static QVector createJointStates(const FBXGeometry& geometry); }; +Q_DECLARE_METATYPE(QPointer) +Q_DECLARE_METATYPE(QWeakPointer) +Q_DECLARE_METATYPE(QVector) + #endif /* defined(__interface__Model__) */ diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index d7e61954ce..ebeb35119c 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -27,7 +27,7 @@ class TextureCache : public ResourceCache { public: TextureCache(); - ~TextureCache(); + virtual ~TextureCache(); /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 56dc5630d0..b199ff19d2 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -10,7 +10,8 @@ #define __hifi__HeadData__ #include -#include + +#include #include #include @@ -54,7 +55,7 @@ public: float getAudioAverageLoudness() const { return _audioAverageLoudness; } void setAudioAverageLoudness(float audioAverageLoudness) { _audioAverageLoudness = audioAverageLoudness; } - const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } float getPupilDilation() const { return _pupilDilation; } void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; } @@ -86,7 +87,7 @@ protected: float _averageLoudness; float _browAudioLift; float _audioAverageLoudness; - std::vector _blendshapeCoefficients; + QVector _blendshapeCoefficients; float _pupilDilation; AvatarData* _owningAvatar; From f8c14a5717bdc3b565ef66ad04cdcc19c1a63b44 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 17:06:01 -0700 Subject: [PATCH 31/51] Remove unused variable, reorder includes. --- libraries/avatars/src/HandData.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index c84ed77dae..0f938b80b0 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -8,14 +8,11 @@ #include -#include "HandData.h" -#include "AvatarData.h" -#include #include +#include - -// When converting between fixed and float, use this as the radix. -const int fingerVectorRadix = 4; +#include "AvatarData.h" +#include "HandData.h" HandData::HandData(AvatarData* owningAvatar) : _owningAvatarData(owningAvatar) From 0fc0d50bdaa7b8114d637ffdb3047d8e0b392840 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 17:19:42 -0700 Subject: [PATCH 32/51] Only post the blender if we have blendable meshes to blend. --- interface/src/renderer/FBXReader.cpp | 9 +++++++++ interface/src/renderer/FBXReader.h | 2 ++ interface/src/renderer/Model.cpp | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 22cd44408e..53f4e04b0b 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -54,6 +54,15 @@ QStringList FBXGeometry::getJointNames() const { return names; } +bool FBXGeometry::hasBlendedMeshes() const { + foreach (const FBXMesh& mesh, meshes) { + if (!mesh.blendshapes.isEmpty()) { + return true; + } + } + return false; +} + static int fbxGeometryMetaTypeId = qRegisterMetaType(); template QVariant readBinaryArray(QDataStream& in) { diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index ead75e6517..5f6a4f51ba 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -181,6 +181,8 @@ public: int getJointIndex(const QString& name) const { return jointIndices.value(name) - 1; } QStringList getJointNames() const; + + bool hasBlendedMeshes() const; }; Q_DECLARE_METATYPE(FBXGeometry) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 591cc4a021..16b5c167d9 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -610,7 +610,9 @@ void Model::simulate(float deltaTime, bool fullUpdate, const QVector } // post the blender - QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients)); + if (geometry.hasBlendedMeshes()) { + QThreadPool::globalInstance()->start(new Blender(this, _geometry, geometry.meshes, _blendshapeCoefficients)); + } } void Model::updateJointState(int index) { From 499c4bd500b40a9ae041ab9516d1ae7030774db4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 17:44:53 -0700 Subject: [PATCH 33/51] fix octree server crashes on various shutdown corner cases --- assignment-client/src/AssignmentClient.cpp | 13 +++++++---- .../src/octree/OctreeSendThread.cpp | 15 ++++++++++-- assignment-client/src/octree/OctreeServer.cpp | 23 ++++++++++++++++--- assignment-client/src/octree/OctreeServer.h | 3 +++ libraries/shared/src/ThreadedAssignment.cpp | 1 + libraries/shared/src/ThreadedAssignment.h | 9 +++++--- 6 files changed, 51 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 978f090ec2..e4db44eea4 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -194,21 +194,24 @@ void AssignmentClient::handleAuthenticationRequest() { } void AssignmentClient::assignmentCompleted() { +qDebug() << "START AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment=" << _currentAssignment; + // reset the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); qDebug("Assignment finished or never started - waiting for new assignment."); NodeList* nodeList = NodeList::getInstance(); + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->reset(); + nodeList->setOwnerType(NodeType::Unassigned); + nodeList->resetNodeInterestSet(); // have us handle incoming NodeList datagrams again disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); +qDebug() << "DONE AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment was=" << _currentAssignment; _currentAssignment = NULL; - - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->setOwnerType(NodeType::Unassigned); - nodeList->reset(); - nodeList->resetNodeInterestSet(); } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 2490640952..83d4a6c082 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -23,12 +23,23 @@ OctreeSendThread::OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer _packetData(), _nodeMissingCount(0) { - qDebug() << "client connected - starting sending thread"; + QString safeServerName("Octree"); + if (_myServer) { + safeServerName = _myServer->getMyServerName(); + } + qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client connected " + "- starting sending thread [" << this << "]"; + OctreeServer::clientConnected(); } OctreeSendThread::~OctreeSendThread() { - qDebug() << "client disconnected - ending sending thread"; + QString safeServerName("Octree"); + if (_myServer) { + safeServerName = _myServer->getMyServerName(); + } + qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client disconnected " + "- ending sending thread [" << this << "]"; OctreeServer::clientDisconnected(); } diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 34b457a8f7..82839e06b3 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -195,9 +195,11 @@ OctreeServer::OctreeServer(const QByteArray& packet) : { _instance = this; _averageLoopTime.updateAverage(0); + qDebug() << "Octree server starting... [" << this << "]"; } OctreeServer::~OctreeServer() { + qDebug() << qPrintable(_safeServerName) << "server shutting down... [" << this << "]"; if (_parsedArgV) { for (int i = 0; i < _argc; i++) { delete[] _parsedArgV[i]; @@ -222,7 +224,7 @@ OctreeServer::~OctreeServer() { delete _jurisdiction; _jurisdiction = NULL; - qDebug() << "OctreeServer::~OctreeServer()... DONE"; + qDebug() << qPrintable(_safeServerName) << "server DONE shutting down... [" << this << "]"; } void OctreeServer::initHTTPManager(int port) { @@ -808,6 +810,7 @@ void OctreeServer::readPendingDatagrams() { } void OctreeServer::run() { + _safeServerName = getMyServerName(); // Before we do anything else, create our tree... _tree = createTree(); @@ -863,6 +866,7 @@ void OctreeServer::run() { connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer))); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer))); + // we need to ask the DS about agents so we can ping/reply with them nodeList->addNodeTypeToInterestSet(NodeType::Agent); @@ -984,13 +988,26 @@ void OctreeServer::run() { void OctreeServer::nodeAdded(SharedNodePointer node) { // we might choose to use this notifier to track clients in a pending state - qDebug() << "OctreeServer::nodeAdded() node:" << *node; + qDebug() << qPrintable(_safeServerName) << "server added node:" << *node; } void OctreeServer::nodeKilled(SharedNodePointer node) { + qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node; OctreeQueryNode* nodeData = static_cast(node->getLinkedData()); if (nodeData) { - nodeData->scheduleForDelete(); + qDebug() << qPrintable(_safeServerName) << "server resetting Linked Data for node:" << *node; + node->setLinkedData(NULL); // set this first in case another thread comes through and tryes to acces this + qDebug() << qPrintable(_safeServerName) << "server deleting Linked Data for node:" << *node; + delete nodeData; } } +void OctreeServer::aboutToFinish() { + qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; + nodeKilled(node); + } + qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; +} + diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 44fca6f124..12091170d9 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -98,6 +98,8 @@ public: static float getAveragePacketSendingTime() { return _averagePacketSendingTime.getAverage(); } bool handleHTTPRequest(HTTPConnection* connection, const QString& path); + + virtual void aboutToFinish(); public slots: /// runs the voxel server assignment @@ -134,6 +136,7 @@ protected: time_t _started; quint64 _startedUSecs; + QString _safeServerName; static int _clientCount; static SimpleMovingAverage _averageLoopTime; diff --git a/libraries/shared/src/ThreadedAssignment.cpp b/libraries/shared/src/ThreadedAssignment.cpp index e2d42883f6..c4282028ae 100644 --- a/libraries/shared/src/ThreadedAssignment.cpp +++ b/libraries/shared/src/ThreadedAssignment.cpp @@ -29,6 +29,7 @@ void ThreadedAssignment::setFinished(bool isFinished) { _isFinished = isFinished; if (_isFinished) { + aboutToFinish(); emit finished(); } } diff --git a/libraries/shared/src/ThreadedAssignment.h b/libraries/shared/src/ThreadedAssignment.h index 25489a8e25..a3cf2a1e31 100644 --- a/libraries/shared/src/ThreadedAssignment.h +++ b/libraries/shared/src/ThreadedAssignment.h @@ -9,21 +9,24 @@ #ifndef __hifi__ThreadedAssignment__ #define __hifi__ThreadedAssignment__ +#include + #include "Assignment.h" class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(const QByteArray& packet); - void setFinished(bool isFinished); + + virtual void aboutToFinish() { }; + public slots: /// threaded run of assignment virtual void run() = 0; - virtual void deleteLater(); - virtual void readPendingDatagrams() = 0; + protected: bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); From f9fd0d432f47b2bf0972b8427cf6d4016536982f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 17:48:57 -0700 Subject: [PATCH 34/51] Fix for reading aggregate avatar packets. --- libraries/avatars/src/AvatarData.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 8ed0ce51ec..e5e0e4b3d7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -176,8 +176,8 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { _handData = new HandData(this); } - const unsigned char* startPosition = reinterpret_cast(packet.data()); - const unsigned char* sourceBuffer = startPosition + offset; + const unsigned char* startPosition = reinterpret_cast(packet.data()) + offset; + const unsigned char* sourceBuffer = startPosition; // Body world position memcpy(&_position, sourceBuffer, sizeof(float) * 3); From 450a9c03a7e167659ad70fd67df674d29b655cfa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 23:54:23 -0700 Subject: [PATCH 35/51] revert changes --- assignment-client/src/AssignmentClient.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index e4db44eea4..970b6518ec 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -194,8 +194,6 @@ void AssignmentClient::handleAuthenticationRequest() { } void AssignmentClient::assignmentCompleted() { -qDebug() << "START AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment=" << _currentAssignment; - // reset the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); @@ -203,15 +201,14 @@ qDebug() << "START AssignmentClient::assignmentCompleted()... this=" << this << NodeList* nodeList = NodeList::getInstance(); - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->reset(); - nodeList->setOwnerType(NodeType::Unassigned); - nodeList->resetNodeInterestSet(); - // have us handle incoming NodeList datagrams again disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); -qDebug() << "DONE AssignmentClient::assignmentCompleted()... this=" << this << "_currentAssignment was=" << _currentAssignment; _currentAssignment = NULL; + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->setOwnerType(NodeType::Unassigned); + nodeList->reset(); + nodeList->resetNodeInterestSet(); } From b3f60a068d90a9b95a48471f3ab4b8bb2e63eb55 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 00:17:14 -0700 Subject: [PATCH 36/51] remove isScheduledForDelete from OctreeQueryNode --- assignment-client/src/octree/OctreeQueryNode.cpp | 1 - assignment-client/src/octree/OctreeQueryNode.h | 6 ------ assignment-client/src/octree/OctreeSendThread.cpp | 4 ---- 3 files changed, 11 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cf57c4f1b5..a1922f980d 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -36,7 +36,6 @@ OctreeQueryNode::OctreeQueryNode() : _lodChanged(false), _lodInitialized(false), _sequenceNumber(0), - _scheduleForDelete(false), _lastRootTimestamp(0) { } diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 6f17117ca2..20fa2c5858 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -86,9 +86,6 @@ public: void dumpOutOfView(); - bool isScheduledForDelete() const { return _scheduleForDelete; } - void scheduleForDelete() { _scheduleForDelete = true; } - quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } void setLastRootTimestamp(quint64 timestamp) { _lastRootTimestamp = timestamp; } unsigned int getlastOctreePacketLength() const { return _lastOctreePacketLength; } @@ -129,9 +126,6 @@ private: bool _lodInitialized; OCTREE_PACKET_SEQUENCE _sequenceNumber; - - bool _scheduleForDelete; - quint64 _lastRootTimestamp; }; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 83d4a6c082..caa729e340 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -69,10 +69,6 @@ bool OctreeSendThread::process() { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); packetDistributor(node, nodeData, viewFrustumChanged); } - if (nodeData->isScheduledForDelete()) { - nodeData->deleteLater(); - node->setLinkedData(NULL); - } } else { _nodeMissingCount++; } From 584adfda0851eb40ee2e96d04f03bc2b8faf70f2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 00:32:38 -0700 Subject: [PATCH 37/51] cleanup headers --- libraries/shared/src/ThreadedAssignment.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/shared/src/ThreadedAssignment.h b/libraries/shared/src/ThreadedAssignment.h index a3cf2a1e31..d3502e9c4d 100644 --- a/libraries/shared/src/ThreadedAssignment.h +++ b/libraries/shared/src/ThreadedAssignment.h @@ -9,8 +9,6 @@ #ifndef __hifi__ThreadedAssignment__ #define __hifi__ThreadedAssignment__ -#include - #include "Assignment.h" class ThreadedAssignment : public Assignment { @@ -18,7 +16,6 @@ class ThreadedAssignment : public Assignment { public: ThreadedAssignment(const QByteArray& packet); void setFinished(bool isFinished); - virtual void aboutToFinish() { }; public slots: @@ -29,7 +26,6 @@ public slots: protected: bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); - void commonInit(const QString& targetName, NodeType_t nodeType); bool _isFinished; private slots: From 80ea33bf020a65ba1f5fa9cc298d57a8c2965100 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 00:37:43 -0700 Subject: [PATCH 38/51] removed test code --- tests/threads/CMakeLists.txt | 36 ------------ tests/threads/src/SampleReadThread.cpp | 65 ---------------------- tests/threads/src/SampleReadThread.h | 31 ----------- tests/threads/src/SampleWriteThread.cpp | 47 ---------------- tests/threads/src/SampleWriteThread.h | 30 ---------- tests/threads/src/SharedResource.cpp | 38 ------------- tests/threads/src/SharedResource.h | 40 -------------- tests/threads/src/ThreadsTests.cpp | 73 ------------------------- tests/threads/src/ThreadsTests.h | 16 ------ tests/threads/src/main.cpp | 11 ---- 10 files changed, 387 deletions(-) delete mode 100644 tests/threads/CMakeLists.txt delete mode 100644 tests/threads/src/SampleReadThread.cpp delete mode 100644 tests/threads/src/SampleReadThread.h delete mode 100644 tests/threads/src/SampleWriteThread.cpp delete mode 100644 tests/threads/src/SampleWriteThread.h delete mode 100644 tests/threads/src/SharedResource.cpp delete mode 100644 tests/threads/src/SharedResource.h delete mode 100644 tests/threads/src/ThreadsTests.cpp delete mode 100644 tests/threads/src/ThreadsTests.h delete mode 100644 tests/threads/src/main.cpp diff --git a/tests/threads/CMakeLists.txt b/tests/threads/CMakeLists.txt deleted file mode 100644 index f12a124b0c..0000000000 --- a/tests/threads/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -if (WIN32) - cmake_policy (SET CMP0020 NEW) -endif (WIN32) - -set(TARGET_NAME threads-tests) - -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -find_package(Qt5Core REQUIRED) - -include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME} TRUE) - -include(${MACRO_DIR}/AutoMTC.cmake) -auto_mtc(${TARGET_NAME} ${ROOT_DIR}) - -qt5_use_modules(${TARGET_NAME} Core) - -#include glm -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - -# link in the shared libraries -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -IF (WIN32) - #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) -ENDIF(WIN32) - diff --git a/tests/threads/src/SampleReadThread.cpp b/tests/threads/src/SampleReadThread.cpp deleted file mode 100644 index 79693dc791..0000000000 --- a/tests/threads/src/SampleReadThread.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// SampleReadThread.cpp -// interface -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. -// - -#include - -#include - -#include "SharedResource.h" -#include "SampleReadThread.h" - -SampleReadThread::SampleReadThread(SharedResource* theResource, int id) : - _theResource(theResource), - _myID(id) { -} - -bool SampleReadThread::process() { - const quint64 FRAME_RATE = 60; - const quint64 USECS_PER_FRAME = USECS_PER_SECOND / FRAME_RATE; // every 60fps - - quint64 start = usecTimestampNow(); - _theResource->lockForRead(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - - int theValue = _theResource->getValue(); - - bool wantDebugging = true; - if (wantDebugging) { - qDebug() << "SampleReadThread::process()... _myID=" << _myID << "lockForRead() took" << elapsed << "usecs" << - " _theResource->getValue()=" << theValue; - } - - quint64 startWork = usecTimestampNow(); - { - const int LOTS_OF_OPERATIONS = 100000; - for(int i = 0; i < LOTS_OF_OPERATIONS; i++) { - float x = rand(); - float y = rand(); - y = x * y; - } - } - quint64 endWork = usecTimestampNow(); - quint64 elapsedWork = endWork - startWork; - qDebug() << "SampleReadThread::process()... _myID=" << _myID << " work took" << elapsedWork << "usecs"; - - _theResource->unlock(); - - - if (isStillRunning()) { - if (elapsed < USECS_PER_FRAME) { - quint64 sleepFor = USECS_PER_FRAME - elapsed; - usleep(sleepFor); - } else { - usleep(5); // sleep at least a little - } - } - return isStillRunning(); // keep running till they terminate us -} diff --git a/tests/threads/src/SampleReadThread.h b/tests/threads/src/SampleReadThread.h deleted file mode 100644 index a9a25ac7a1..0000000000 --- a/tests/threads/src/SampleReadThread.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// SampleReadThread.h -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__SampleReadThread__ -#define __interface__SampleReadThread__ - -#include - -class SharedResource; - -/// Generalized threaded processor for handling received inbound packets. -class SampleReadThread : public GenericThread { - Q_OBJECT -public: - SampleReadThread(SharedResource* theResource, int id); - -protected: - /// Implements generic processing behavior for this thread. - virtual bool process(); - -private: - SharedResource* _theResource; - int _myID; -}; - -#endif // __interface__SampleReadThread__ diff --git a/tests/threads/src/SampleWriteThread.cpp b/tests/threads/src/SampleWriteThread.cpp deleted file mode 100644 index 0fbe68904d..0000000000 --- a/tests/threads/src/SampleWriteThread.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// -// SampleWriteThread.cpp -// interface -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded interface thread for hiding and showing voxels in the local tree. -// - -#include - -#include - -#include "SharedResource.h" -#include "SampleWriteThread.h" - -SampleWriteThread::SampleWriteThread(SharedResource* theResource) : - _theResource(theResource) { -} - -bool SampleWriteThread::process() { - const quint64 USECS_PER_OPERATION = USECS_PER_SECOND * 1; // once every second. - - quint64 start = usecTimestampNow(); - _theResource->lockForWrite(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - - int theValue = _theResource->incrementValue(); - - bool wantDebugging = false; - if (wantDebugging) { - qDebug() << "SampleWriteThread::process()... lockForWrite() took" << elapsed << "usecs" << - " _theResource->incrementValue()=" << theValue; - } - _theResource->unlock(); - - - if (isStillRunning()) { - if (elapsed < USECS_PER_OPERATION) { - quint64 sleepFor = USECS_PER_OPERATION - elapsed; - usleep(sleepFor); - } - } - return isStillRunning(); // keep running till they terminate us -} diff --git a/tests/threads/src/SampleWriteThread.h b/tests/threads/src/SampleWriteThread.h deleted file mode 100644 index 970b4435a9..0000000000 --- a/tests/threads/src/SampleWriteThread.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// SampleWriteThread.h -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__SampleWriteThread__ -#define __interface__SampleWriteThread__ - -#include - -class SharedResource; - -/// Generalized threaded processor for handling received inbound packets. -class SampleWriteThread : public GenericThread { - Q_OBJECT -public: - SampleWriteThread(SharedResource* theResource); - -protected: - /// Implements generic processing behavior for this thread. - virtual bool process(); - -private: - SharedResource* _theResource; -}; - -#endif // __interface__SampleWriteThread__ diff --git a/tests/threads/src/SharedResource.cpp b/tests/threads/src/SharedResource.cpp deleted file mode 100644 index c397e6a7db..0000000000 --- a/tests/threads/src/SharedResource.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// SharedResource.cpp -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include - -#include "SharedResource.h" - -const int MOVING_AVERAGE_SAMPLES = 10000; - -SharedResource::SharedResource() : - _value(0), - _lockAverage(MOVING_AVERAGE_SAMPLES), - _lockForReadAverage(MOVING_AVERAGE_SAMPLES), - _lockForWriteAverage(MOVING_AVERAGE_SAMPLES) -{ -}; - -void SharedResource::lockForRead() { - quint64 start = usecTimestampNow(); - _lock.lockForRead(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - _lockForReadAverage.updateAverage(elapsed); - _lockAverage.updateAverage(elapsed); -} -void SharedResource::lockForWrite() { - quint64 start = usecTimestampNow(); - _lock.lockForWrite(); - quint64 end = usecTimestampNow(); - quint64 elapsed = end - start; - _lockForWriteAverage.updateAverage(elapsed); - _lockAverage.updateAverage(elapsed); -} diff --git a/tests/threads/src/SharedResource.h b/tests/threads/src/SharedResource.h deleted file mode 100644 index 1426471f16..0000000000 --- a/tests/threads/src/SharedResource.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// SharedResource.h -// tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__SharedResource__ -#define __interface__SharedResource__ - -#include - -#include - -/// Generalized threaded processor for handling received inbound packets. -class SharedResource { -public: - SharedResource(); - - void lockForRead(); - void lockForWrite(); - void unlock() { _lock.unlock(); } - - int getValue() const { return _value; } - int incrementValue() { return ++_value; } - - float getAverageLockTime() const { return _lockAverage.getAverage(); } - float getAverageLockForReadTime() const { return _lockForReadAverage.getAverage(); } - float getAverageLockForWriteTime() const { return _lockForWriteAverage.getAverage(); } - -private: - QReadWriteLock _lock; - int _value; - SimpleMovingAverage _lockAverage; - SimpleMovingAverage _lockForReadAverage; - SimpleMovingAverage _lockForWriteAverage; -}; - -#endif // __interface__SharedResource__ diff --git a/tests/threads/src/ThreadsTests.cpp b/tests/threads/src/ThreadsTests.cpp deleted file mode 100644 index 15b1c66e63..0000000000 --- a/tests/threads/src/ThreadsTests.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// ThreadsTests.cpp -// thread-tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. -// - -#include -#include - -#include -#include - -#include "SampleReadThread.h" -#include "SampleWriteThread.h" -#include "SharedResource.h" -#include "ThreadsTests.h" - - -void ThreadsTests::runAllTests() { - qDebug() << "START ThreadsTests::runAllTests()"; - - const quint64 TOTAL_RUN_TIME = USECS_PER_SECOND * 10; // run for 2 minutes - const quint64 MAIN_THREAD_SLEEP = USECS_PER_SECOND * 0.25; // main thread checks in every 1/4 second - quint64 start = usecTimestampNow(); - quint64 now = usecTimestampNow(); - - SharedResource resource; - - const int NUMBER_OF_READERS = 125; // + 3 = 128, Max number of QThreads on the mac. - QVector readThreads; - for(int i = 0; i < NUMBER_OF_READERS; i++) { - SampleReadThread* newReader = new SampleReadThread(&resource, i); - newReader->initialize(); - readThreads.append(newReader); - } - - SampleWriteThread write(&resource); - write.initialize(); - - while(now - start < TOTAL_RUN_TIME) { - float elapsed = (float)(now - start) / (float)USECS_PER_SECOND; - qDebug() << "Main thread still running... elapsed:" << elapsed << "seconds"; - qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; - qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; - qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; - qDebug() << " resource.value:" << resource.getValue(); - - - usleep(MAIN_THREAD_SLEEP); - now = usecTimestampNow(); - } - write.terminate(); - - foreach(SampleReadThread* readThread, readThreads) { - readThread->terminate(); - delete readThread; - } - readThreads.clear(); - - qDebug() << "DONE running..."; - qDebug() << " average Read Lock:" << resource.getAverageLockForReadTime() << "usecs"; - qDebug() << " average Write Lock:" << resource.getAverageLockForWriteTime() << "usecs"; - qDebug() << " average Lock:" << resource.getAverageLockTime() << "usecs"; - qDebug() << " resource.value:" << resource.getValue(); - - qDebug() << "END ThreadsTests::runAllTests()"; - - qDebug() << "_POSIX_THREAD_THREADS_MAX" << _POSIX_THREAD_THREADS_MAX; - qDebug() << "QThread::idealThreadCount()" << QThread::idealThreadCount(); - -} diff --git a/tests/threads/src/ThreadsTests.h b/tests/threads/src/ThreadsTests.h deleted file mode 100644 index 29bd9aebd4..0000000000 --- a/tests/threads/src/ThreadsTests.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// ThreadsTests.h -// threads-tests -// -// Created by Brad Hefta-Gaub on 2014.03.17 -// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. -// - -#ifndef __tests__ThreadsTests__ -#define __tests__ThreadsTests__ - -namespace ThreadsTests { - void runAllTests(); -} - -#endif // __tests__ThreadsTests__ diff --git a/tests/threads/src/main.cpp b/tests/threads/src/main.cpp deleted file mode 100644 index 16f3ea0900..0000000000 --- a/tests/threads/src/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// -// main.cpp -// threads-tests -// - -#include "ThreadsTests.h" - -int main(int argc, char** argv) { - ThreadsTests::runAllTests(); - return 0; -} From cd6e0f16982b65d9b9532956a0d3ad73d8a58431 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 01:02:49 -0700 Subject: [PATCH 39/51] switch to deleteLater to prevent deadlock --- assignment-client/src/octree/OctreeServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 82839e06b3..7e6ffe52da 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -998,7 +998,7 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { qDebug() << qPrintable(_safeServerName) << "server resetting Linked Data for node:" << *node; node->setLinkedData(NULL); // set this first in case another thread comes through and tryes to acces this qDebug() << qPrintable(_safeServerName) << "server deleting Linked Data for node:" << *node; - delete nodeData; + nodeData->deleteLater(); } } From 7c45df002a11f78d93683c2c9b34a2d39b198c6b Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 19 Mar 2014 07:41:36 -0700 Subject: [PATCH 40/51] increased head smoothing for visage --- interface/resources/visage/tracker.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/visage/tracker.cfg b/interface/resources/visage/tracker.cfg index b5ed3302fa..10744da6e5 100644 --- a/interface/resources/visage/tracker.cfg +++ b/interface/resources/visage/tracker.cfg @@ -40,7 +40,7 @@ detect_strip_roi_width 2 detect_strip_roi_height 4 smoothing_factors - 150 15 -2 100 -1 50 50 0 + 150 5 -2 100 -1 50 50 0 #translation rotation action_units eyebrows mouth gaze eye_closure other process_eyes 1 From 252bc3b3eee61ee52b099694234b1cae1b096b76 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 11:51:47 -0700 Subject: [PATCH 41/51] optimized ViewFrustum::getFurthestPointFromCamera() --- libraries/octree/src/OctreeElement.cpp | 7 ++++--- libraries/octree/src/ViewFrustum.cpp | 25 +++++++++---------------- libraries/octree/src/ViewFrustum.h | 5 +++-- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 72ac5b14d6..3f31ad928a 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1222,10 +1222,11 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float float OctreeElement::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const { AABox box = getAABox(); box.scale(TREE_SCALE); - glm::vec3 furthestPoint = viewFrustum.getFurthestPointFromCamera(box); + glm::vec3 furthestPoint; + viewFrustum.getFurthestPointFromCamera(box, furthestPoint); glm::vec3 temp = viewFrustum.getPosition() - furthestPoint; - float distanceToVoxelCenter = sqrtf(glm::dot(temp, temp)); - return distanceToVoxelCenter; + float distanceToFurthestPoint = sqrtf(glm::dot(temp, temp)); + return distanceToFurthestPoint; } float OctreeElement::distanceToCamera(const ViewFrustum& viewFrustum) const { diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 66f1445ddc..00caafa095 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -695,39 +695,32 @@ OctreeProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const return projectedPolygon; } - // Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the // axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for // squares and square-roots. Just compares. -glm::vec3 ViewFrustum::getFurthestPointFromCamera(const AABox& box) const { +void ViewFrustum::getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const { const glm::vec3& bottomNearRight = box.getCorner(); - glm::vec3 center = box.calcCenter(); - glm::vec3 topFarLeft = box.calcTopFarLeft(); + float scale = box.getScale(); + float halfScale = scale * 0.5f; - glm::vec3 furthestPoint; - if (_position.x < center.x) { + if (_position.x < bottomNearRight.x + halfScale) { // we are to the right of the center, so the left edge is furthest - furthestPoint.x = topFarLeft.x; + furthestPoint.x = bottomNearRight.x + scale; } else { - // we are to the left of the center, so the right edge is furthest (at center ok too) furthestPoint.x = bottomNearRight.x; } - if (_position.y < center.y) { + if (_position.y < bottomNearRight.y + halfScale) { // we are below of the center, so the top edge is furthest - furthestPoint.y = topFarLeft.y; + furthestPoint.y = bottomNearRight.y + scale; } else { - // we are above the center, so the lower edge is furthest (at center ok too) furthestPoint.y = bottomNearRight.y; } - if (_position.z < center.z) { + if (_position.z < bottomNearRight.z + halfScale) { // we are to the near side of the center, so the far side edge is furthest - furthestPoint.z = topFarLeft.z; + furthestPoint.z = bottomNearRight.z + scale; } else { - // we are to the far side of the center, so the near side edge is furthest (at center ok too) furthestPoint.z = bottomNearRight.z; } - - return furthestPoint; } diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index da4a6997f1..f841566652 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -102,8 +102,9 @@ public: glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; OctreeProjectedPolygon getProjectedPolygon(const AABox& box) const; - glm::vec3 getFurthestPointFromCamera(const AABox& box) const; - + //glm::vec3 getFurthestPointFromCamera(const AABox& box) const; + void getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const; + private: // Used for keyhole calculations ViewFrustum::location pointInKeyhole(const glm::vec3& point) const; From f3bd8925d91f46d63d4af17ed32f4545febed259 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 12:48:11 -0700 Subject: [PATCH 42/51] optimized OctreeElement::furthestDistanceToCamera() --- libraries/octree/src/OctreeElement.cpp | 9 ++++---- libraries/octree/src/ViewFrustum.cpp | 29 ++++++++++++++++++++++++++ libraries/octree/src/ViewFrustum.h | 10 ++++++--- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 3f31ad928a..4d1630135c 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1219,14 +1219,13 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float } // Calculates the distance to the furthest point of the voxel to the camera +// does as much math as possible in voxel scale and then scales up to TREE_SCALE at end float OctreeElement::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const { - AABox box = getAABox(); - box.scale(TREE_SCALE); glm::vec3 furthestPoint; - viewFrustum.getFurthestPointFromCamera(box, furthestPoint); - glm::vec3 temp = viewFrustum.getPosition() - furthestPoint; + viewFrustum.getFurthestPointFromCameraVoxelScale(getAABox(), furthestPoint); + glm::vec3 temp = viewFrustum.getPositionVoxelScale() - furthestPoint; float distanceToFurthestPoint = sqrtf(glm::dot(temp, temp)); - return distanceToFurthestPoint; + return distanceToFurthestPoint * (float)TREE_SCALE; } float OctreeElement::distanceToCamera(const ViewFrustum& viewFrustum) const { diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 00caafa095..da03aad697 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -25,6 +25,7 @@ using namespace std; ViewFrustum::ViewFrustum() : _position(0,0,0), + _positionVoxelScale(0,0,0), _orientation(), _direction(IDENTITY_FRONT), _up(IDENTITY_UP), @@ -724,3 +725,31 @@ void ViewFrustum::getFurthestPointFromCamera(const AABox& box, glm::vec3& furthe furthestPoint.z = bottomNearRight.z; } } + +void ViewFrustum::getFurthestPointFromCameraVoxelScale(const AABox& box, glm::vec3& furthestPoint) const { + const glm::vec3& bottomNearRight = box.getCorner(); + float scale = box.getScale(); + float halfScale = scale * 0.5f; + + if (_positionVoxelScale.x < bottomNearRight.x + halfScale) { + // we are to the right of the center, so the left edge is furthest + furthestPoint.x = bottomNearRight.x + scale; + } else { + furthestPoint.x = bottomNearRight.x; + } + + if (_positionVoxelScale.y < bottomNearRight.y + halfScale) { + // we are below of the center, so the top edge is furthest + furthestPoint.y = bottomNearRight.y + scale; + } else { + furthestPoint.y = bottomNearRight.y; + } + + if (_positionVoxelScale.z < bottomNearRight.z + halfScale) { + // we are to the near side of the center, so the far side edge is furthest + furthestPoint.z = bottomNearRight.z + scale; + } else { + furthestPoint.z = bottomNearRight.z; + } +} + diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index f841566652..a0b3a851aa 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -29,11 +29,12 @@ const float DEFAULT_FAR_CLIP = 50.0f * TREE_SCALE; class ViewFrustum { public: // setters for camera attributes - void setPosition(const glm::vec3& p) { _position = p; } + void setPosition(const glm::vec3& p) { _position = p; _positionVoxelScale = (p / (float)TREE_SCALE); } void setOrientation(const glm::quat& orientationAsQuaternion); // getters for camera attributes const glm::vec3& getPosition() const { return _position; } + const glm::vec3& getPositionVoxelScale() const { return _positionVoxelScale; } const glm::quat& getOrientation() const { return _orientation; } const glm::vec3& getDirection() const { return _direction; } const glm::vec3& getUp() const { return _up; } @@ -102,9 +103,11 @@ public: glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; OctreeProjectedPolygon getProjectedPolygon(const AABox& box) const; - //glm::vec3 getFurthestPointFromCamera(const AABox& box) const; void getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const; + // assumes box is in voxel scale, not TREE_SCALE, will scale view frustum's position accordingly + void getFurthestPointFromCameraVoxelScale(const AABox& box, glm::vec3& furthestPoint) const; + private: // Used for keyhole calculations ViewFrustum::location pointInKeyhole(const glm::vec3& point) const; @@ -112,7 +115,8 @@ private: ViewFrustum::location boxInKeyhole(const AABox& box) const; // camera location/orientation attributes - glm::vec3 _position; + glm::vec3 _position; // the position in TREE_SCALE + glm::vec3 _positionVoxelScale; // the position in voxel scale glm::quat _orientation; // calculated for orientation From adaa01c13e362ec2b21d287b042c82cc9299067d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 13:15:28 -0700 Subject: [PATCH 43/51] optimize isLeaf() to just check the child mask instead of counting children --- libraries/octree/src/OctreeElement.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 1785307696..cbdad959be 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -126,7 +126,7 @@ public: float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this. float distanceToPoint(const glm::vec3& point) const; - bool isLeaf() const { return getChildCount() == 0; } + bool isLeaf() const { return _childBitmask == 0; } int getChildCount() const { return numberOfOnes(_childBitmask); } void printDebugDetails(const char* label) const; bool isDirty() const { return _isDirty; } From 3d0207b926751cb280a56ef2e159e54b2e58d54e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 13:54:06 -0700 Subject: [PATCH 44/51] optimize OctreeElement::calculateShouldRender() --- libraries/octree/src/OctreeElement.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 4d1630135c..bdf396a656 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1209,11 +1209,15 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float bool shouldRender = false; if (hasContent()) { float furthestDistance = furthestDistanceToCamera(*viewFrustum); - float boundary = boundaryDistanceForRenderLevel(getLevel() + boundaryLevelAdjust, voxelScaleSize); - float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); - bool inBoundary = (furthestDistance <= boundary); - bool inChildBoundary = (furthestDistance <= childBoundary); - shouldRender = (isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary); + float childBoundary = boundaryDistanceForRenderLevel(getLevel() + 1 + boundaryLevelAdjust, voxelScaleSize); + bool inChildBoundary = (furthestDistance <= childBoundary); + if (isLeaf() && inChildBoundary) { + shouldRender = true; + } else { + float boundary = childBoundary * 2.0f; // the boundary is always twice the distance of the child boundary + bool inBoundary = (furthestDistance <= boundary); + shouldRender = inBoundary && !inChildBoundary; + } } return shouldRender; } From 5f94e44cde18e3c48bc301438e1fadd73a2db520 Mon Sep 17 00:00:00 2001 From: Tony Hagale Date: Wed, 19 Mar 2014 16:26:45 -0500 Subject: [PATCH 45/51] #2386 trying a new static lookup table for numberOfOnes() --- libraries/shared/src/SharedUtil.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index e5aded2798..00810653c1 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -130,14 +130,22 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) { } int numberOfOnes(unsigned char byte) { - return (byte >> 7) - + ((byte >> 6) & 1) - + ((byte >> 5) & 1) - + ((byte >> 4) & 1) - + ((byte >> 3) & 1) - + ((byte >> 2) & 1) - + ((byte >> 1) & 1) - + (byte & 1); + + static const unsigned char nbits[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3, + 4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4, + 4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2, + 3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5, + 4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3, + 4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3, + 3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5, + 6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6, + 4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5, + 6,5,6,6,7,5,6,6,7,6,7,7,8 + }; + + return nbits[(unsigned char) byte]; + } bool oneAtBit(unsigned char byte, int bitIndex) { From 7f2a92d759786e1bf1b8ad5eb43f14a45722596a Mon Sep 17 00:00:00 2001 From: Tony Hagale Date: Wed, 19 Mar 2014 16:28:12 -0500 Subject: [PATCH 46/51] #2386 trying a new static lookup table for numberOfOnes() --- libraries/shared/src/SharedUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 00810653c1..882d4719c8 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -131,7 +131,7 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) { int numberOfOnes(unsigned char byte) { - static const unsigned char nbits[256] = { + static const int nbits[256] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3, 4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4, 4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2, From f3968679d3474275c6914cb618062fbf045391d2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Mar 2014 15:44:18 -0700 Subject: [PATCH 47/51] cleanup isInView() to use inFrustum() directly --- libraries/octree/src/OctreeElement.cpp | 7 ------- libraries/octree/src/OctreeElement.h | 4 +--- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index bdf396a656..cdc4f419c0 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1183,13 +1183,6 @@ float OctreeElement::getEnclosingRadius() const { return getScale() * sqrtf(3.0f) / 2.0f; } -bool OctreeElement::isInView(const ViewFrustum& viewFrustum) const { - AABox box = _box; // use temporary box so we can scale it - box.scale(TREE_SCALE); - bool inView = (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(box)); - return inView; -} - ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) const { AABox box = _box; // use temporary box so we can scale it box.scale(TREE_SCALE); diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index cbdad959be..ca2fa0b540 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -112,9 +112,7 @@ public: int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; } float getEnclosingRadius() const; - - - bool isInView(const ViewFrustum& viewFrustum) const; + bool isInView(const ViewFrustum& viewFrustum) const { return inFrustum(viewFrustum) != ViewFrustum::OUTSIDE; } ViewFrustum::location inFrustum(const ViewFrustum& viewFrustum) const; float distanceToCamera(const ViewFrustum& viewFrustum) const; float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const; From e34f2ca69b4f8835f1d3d597ee18c7222e6af7d8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 19 Mar 2014 16:11:15 -0700 Subject: [PATCH 48/51] Remove file texture loading (since we can just use file URLs), don't add alpha channels for opaque textures (and note when textures with alpha channels are entirely opaque), enforce a maximum texture size of 1024 by 1024. --- interface/src/renderer/TextureCache.cpp | 67 +++++++++++++++---------- interface/src/renderer/TextureCache.h | 5 -- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 91cf1c8b6e..2b43c89998 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -38,9 +38,6 @@ TextureCache::~TextureCache() { if (_whiteTextureID != 0) { glDeleteTextures(1, &_whiteTextureID); } - foreach (GLuint id, _fileTextureIDs) { - glDeleteTextures(1, &id); - } if (_primaryFramebufferObject) { glDeleteTextures(1, &_primaryDepthTextureID); } @@ -104,23 +101,6 @@ GLuint TextureCache::getBlueTextureID() { return _blueTextureID; } -GLuint TextureCache::getFileTextureID(const QString& filename) { - GLuint id = _fileTextureIDs.value(filename); - if (id == 0) { - QImage image = QImage(filename).convertToFormat(QImage::Format_ARGB32); - - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1, - GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - - _fileTextureIDs.insert(filename, id); - } - return id; -} - QSharedPointer TextureCache::getTexture(const QUrl& url, bool normalMap, bool dilatable) { if (!dilatable) { return ResourceCache::getResource(url, QUrl(), false, &normalMap).staticCast(); @@ -293,27 +273,50 @@ void ImageReader::run() { _reply->deleteLater(); return; } + QUrl url = _reply->url(); QImage image = QImage::fromData(_reply->readAll()); + _reply->deleteLater(); + + // enforce a fixed maximum + const int MAXIMUM_SIZE = 1024; + if (image.width() > MAXIMUM_SIZE || image.height() > MAXIMUM_SIZE) { + qDebug() << "Image greater than maximum size:" << url << image.width() << image.height(); + image = image.scaled(MAXIMUM_SIZE, MAXIMUM_SIZE, Qt::KeepAspectRatio); + } + + if (!image.hasAlphaChannel()) { + if (image.format() != QImage::Format_RGB888) { + image = image.convertToFormat(QImage::Format_RGB888); + } + QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image), Q_ARG(bool, false)); + return; + } if (image.format() != QImage::Format_ARGB32) { image = image.convertToFormat(QImage::Format_ARGB32); } - // check for translucency + // check for translucency/false transparency + int opaquePixels = 0; int translucentPixels = 0; const int EIGHT_BIT_MAXIMUM = 255; const int RGB_BITS = 24; for (int y = 0; y < image.height(); y++) { for (int x = 0; x < image.width(); x++) { int alpha = image.pixel(x, y) >> RGB_BITS; - if (alpha != 0 && alpha != EIGHT_BIT_MAXIMUM) { + if (alpha == EIGHT_BIT_MAXIMUM) { + opaquePixels++; + } else if (alpha != 0) { translucentPixels++; } } } int imageArea = image.width() * image.height(); + if (opaquePixels == imageArea) { + qDebug() << "Image with alpha channel is completely opaque:" << url; + image.convertToFormat(QImage::Format_RGB888); + } QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image), Q_ARG(bool, translucentPixels >= imageArea / 2)); - _reply->deleteLater(); } void NetworkTexture::downloadFinished(QNetworkReply* reply) { @@ -327,8 +330,13 @@ void NetworkTexture::setImage(const QImage& image, bool translucent) { finishedLoading(true); imageLoaded(image); glBindTexture(GL_TEXTURE_2D, getID()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1, - GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); + if (image.hasAlphaChannel()) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1, + GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 1, + GL_RGB, GL_UNSIGNED_BYTE, image.constBits()); + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); } @@ -360,8 +368,13 @@ QSharedPointer DilatableNetworkTexture::getDilatedTexture(float dilatio painter.end(); glBindTexture(GL_TEXTURE_2D, texture->getID()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1, - GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits()); + if (dilatedImage.hasAlphaChannel()) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1, + GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits()); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dilatedImage.width(), dilatedImage.height(), 1, + GL_RGB, GL_UNSIGNED_BYTE, dilatedImage.constBits()); + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index ebeb35119c..dc874ab7b0 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -39,9 +39,6 @@ public: /// Returns the ID of a pale blue texture (useful for a normal map). GLuint getBlueTextureID(); - - /// Returns the ID of a texture containing the contents of the specified file, loading it if necessary. - GLuint getFileTextureID(const QString& filename); /// Loads a texture from the specified URL. QSharedPointer getTexture(const QUrl& url, bool normalMap = false, bool dilatable = false); @@ -84,8 +81,6 @@ private: GLuint _whiteTextureID; GLuint _blueTextureID; - QHash _fileTextureIDs; - QHash > _dilatableNetworkTextures; GLuint _primaryDepthTextureID; From 8c4fad443f0ab8de6f0a28cce26a9cfa53567a4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 19 Mar 2014 16:14:58 -0700 Subject: [PATCH 49/51] allow Agents to microphone audio from Sound objects --- assignment-client/src/Agent.cpp | 27 +------- assignment-client/src/Agent.h | 14 +++-- libraries/script-engine/src/ScriptEngine.cpp | 65 +++++++++++++++----- libraries/script-engine/src/ScriptEngine.h | 14 +++-- 4 files changed, 67 insertions(+), 53 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 46f4d233c2..cb8edaab47 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -26,8 +26,7 @@ Agent::Agent(const QByteArray& packet) : ThreadedAssignment(packet), _voxelEditSender(), - _particleEditSender(), - _avatarAudioStream(NULL) + _particleEditSender() { // be the parent of the script engine so it gets moved when we do _scriptEngine.setParent(this); @@ -36,30 +35,6 @@ Agent::Agent(const QByteArray& packet) : _scriptEngine.getParticlesScriptingInterface()->setPacketSender(&_particleEditSender); } -Agent::~Agent() { - delete _avatarAudioStream; -} - -const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5); - -void Agent::setSendAvatarAudioStream(bool sendAvatarAudioStream) { - if (sendAvatarAudioStream) { - // the agentAudioStream number of samples is related to the ScriptEngine callback rate - _avatarAudioStream = new int16_t[SCRIPT_AUDIO_BUFFER_SAMPLES]; - - // fill the _audioStream with zeroes to start - memset(_avatarAudioStream, 0, SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t)); - - _scriptEngine.setNumAvatarAudioBufferSamples(SCRIPT_AUDIO_BUFFER_SAMPLES); - _scriptEngine.setAvatarAudioBuffer(_avatarAudioStream); - } else { - delete _avatarAudioStream; - _avatarAudioStream = NULL; - - _scriptEngine.setAvatarAudioBuffer(NULL); - } -} - void Agent::readPendingDatagrams() { QByteArray receivedPacket; HifiSockAddr senderSockAddr; diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index a051f42faf..b638c39356 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -28,20 +28,24 @@ class Agent : public ThreadedAssignment { Q_OBJECT Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar) - Q_PROPERTY(bool sendAvatarAudioStream READ isSendingAvatarAudioStream WRITE setSendAvatarAudioStream) + Q_PROPERTY(bool isPlayingAvatarSound READ isPlayingAvatarSound) + Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream) public: Agent(const QByteArray& packet); - ~Agent(); void setIsAvatar(bool isAvatar) { QMetaObject::invokeMethod(&_scriptEngine, "setIsAvatar", Q_ARG(bool, isAvatar)); } bool isAvatar() const { return _scriptEngine.isAvatar(); } - void setSendAvatarAudioStream(bool sendAvatarAudioStream); - bool isSendingAvatarAudioStream() const { return (bool) _scriptEngine.sendsAvatarAudioStream(); } + bool isPlayingAvatarSound() const { return _scriptEngine.isPlayingAvatarSound(); } + + bool isListeningToAudioStream() const { return _scriptEngine.isListeningToAudioStream(); } + void setIsListeningToAudioStream(bool isListeningToAudioStream) + { _scriptEngine.setIsListeningToAudioStream(isListeningToAudioStream); } public slots: void run(); void readPendingDatagrams(); + void playAvatarSound(Sound* avatarSound) { _scriptEngine.setAvatarSound(avatarSound); } private: ScriptEngine _scriptEngine; @@ -50,8 +54,6 @@ private: ParticleTreeHeadlessViewer _particleViewer; VoxelTreeHeadlessViewer _voxelViewer; - - int16_t* _avatarAudioStream; }; #endif /* defined(__hifi__Agent__) */ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cc61633e60..c820347cab 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -52,7 +53,9 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co _avatarIdentityTimer(NULL), _avatarBillboardTimer(NULL), _timerFunctionMap(), - _avatarAudioBuffer(NULL), + _isListeningToAudioStream(false), + _avatarSound(NULL), + _numAvatarSoundSentBytes(0), _controllerScriptingInterface(controllerScriptingInterface), _avatarData(NULL), _wantMenuItems(wantMenuItems), @@ -260,27 +263,55 @@ void ScriptEngine::run() { } if (_isAvatar && _avatarData) { + + const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5); + const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); + QByteArray avatarPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData); avatarPacket.append(_avatarData->toByteArray()); nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer); - if (_avatarAudioBuffer && _numAvatarAudioBufferSamples > 0) { - // if have an avatar audio stream then send it out to our audio-mixer - + if (_isListeningToAudioStream || _avatarSound) { + // if we have an avatar audio stream then send it out to our audio-mixer bool silentFrame = true; - // check if the all of the _numAvatarAudioBufferSamples to be sent are silence - for (int i = 0; i < _numAvatarAudioBufferSamples; ++i) { - if (_avatarAudioBuffer[i] != 0) { - silentFrame = false; - break; + int16_t numAvailableSamples = SCRIPT_AUDIO_BUFFER_SAMPLES; + const int16_t* nextSoundOutput = NULL; + + if (_avatarSound) { + + const QByteArray& soundByteArray = _avatarSound->getByteArray(); + nextSoundOutput = reinterpret_cast(soundByteArray.data() + + _numAvatarSoundSentBytes); + + int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > SCRIPT_AUDIO_BUFFER_BYTES + ? SCRIPT_AUDIO_BUFFER_BYTES + : soundByteArray.size() - _numAvatarSoundSentBytes; + numAvailableSamples = numAvailableBytes / sizeof(int16_t); + + + // check if the all of the _numAvatarAudioBufferSamples to be sent are silence + for (int i = 0; i < numAvailableSamples; ++i) { + if (nextSoundOutput[i] != 0) { + silentFrame = false; + break; + } + } + + _numAvatarSoundSentBytes += numAvailableBytes; + if (_numAvatarSoundSentBytes == soundByteArray.size()) { + // we're done with this sound object - so set our pointer back to NULL + // and our sent bytes back to zero + _avatarSound = NULL; + _numAvatarSoundSentBytes = 0; } } QByteArray audioPacket = byteArrayWithPopulatedHeader(silentFrame ? PacketTypeSilentAudioFrame : PacketTypeMicrophoneAudioNoEcho); + QDataStream packetStream(&audioPacket, QIODevice::Append); // use the orientation and position of this avatar for the source of this audio @@ -289,13 +320,17 @@ void ScriptEngine::run() { packetStream.writeRawData(reinterpret_cast(&headOrientation), sizeof(glm::quat)); if (silentFrame) { + if (!_isListeningToAudioStream) { + // if we have a silent frame and we're not listening then just send nothing and break out of here + break; + } + // write the number of silent samples so the audio-mixer can uphold timing - int16_t numSilentSamples = _numAvatarAudioBufferSamples; - packetStream.writeRawData(reinterpret_cast(&numSilentSamples), sizeof(int16_t)); - } else { + packetStream.writeRawData(reinterpret_cast(&SCRIPT_AUDIO_BUFFER_SAMPLES), sizeof(int16_t)); + } else if (nextSoundOutput) { // write the raw audio data - packetStream.writeRawData(reinterpret_cast(_avatarAudioBuffer), - _numAvatarAudioBufferSamples * sizeof(int16_t)); + packetStream.writeRawData(reinterpret_cast(nextSoundOutput), + numAvailableSamples * sizeof(int16_t)); } nodeList->broadcastToNodes(audioPacket, NodeSet() << NodeType::AudioMixer); @@ -303,7 +338,7 @@ void ScriptEngine::run() { } qint64 now = usecTimestampNow(); - float deltaTime = (float)(now - lastUpdate)/(float)USECS_PER_SECOND; + float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; emit update(deltaTime); lastUpdate = now; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 606d0aabf4..755418b0c1 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -56,10 +56,11 @@ public: void setAvatarData(AvatarData* avatarData, const QString& objectName); - void setAvatarAudioBuffer(int16_t* avatarAudioBuffer) { _avatarAudioBuffer = avatarAudioBuffer; } - bool sendsAvatarAudioStream() const { return (bool) _avatarAudioBuffer; } - void setNumAvatarAudioBufferSamples(int numAvatarAudioBufferSamples) - { _numAvatarAudioBufferSamples = numAvatarAudioBufferSamples; } + bool isListeningToAudioStream() const { return _isListeningToAudioStream; } + void setIsListeningToAudioStream(bool isListeningToAudioStream) { _isListeningToAudioStream = isListeningToAudioStream; } + + void setAvatarSound(Sound* avatarSound) { _avatarSound = avatarSound; } + bool isPlayingAvatarSound() const { return _avatarSound != NULL; } void init(); void run(); /// runs continuously until Agent.stop() is called @@ -91,8 +92,9 @@ protected: QTimer* _avatarIdentityTimer; QTimer* _avatarBillboardTimer; QHash _timerFunctionMap; - int16_t* _avatarAudioBuffer; - int _numAvatarAudioBufferSamples; + bool _isListeningToAudioStream; + Sound* _avatarSound; + int _numAvatarSoundSentBytes; private: void sendAvatarIdentityPacket(); From dd9c4aa8541d87d44860ed66eebd79bd55eb878e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 19 Mar 2014 16:18:44 -0700 Subject: [PATCH 50/51] changes to bot.js for new Agent microphone audio --- examples/bot.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/examples/bot.js b/examples/bot.js index 5fd4785b76..ae337f5031 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -29,7 +29,6 @@ var CHANCE_OF_BIG_MOVE = 0.1; var isMoving = false; var isTurningHead = false; -var isPlayingAudio = false; var X_MIN = 0.0; var X_MAX = 5.0; @@ -60,20 +59,11 @@ function clamp(val, min, max){ } // Play a random sound from a list of conversational audio clips -function audioDone() { - isPlayingAudio = false; -} - var AVERAGE_AUDIO_LENGTH = 8000; -function playRandomSound(position) { - if (!isPlayingAudio) { +function playRandomSound() { + if (!Agent.isPlayingAvatarSound) { var whichSound = Math.floor((Math.random() * sounds.length) % sounds.length); - var audioOptions = new AudioInjectionOptions(); - audioOptions.volume = 0.25 + (Math.random() * 0.75); - audioOptions.position = position; - Audio.playSound(sounds[whichSound], audioOptions); - isPlayingAudio = true; - Script.setTimeout(audioDone, AVERAGE_AUDIO_LENGTH); + Audio.playSound(sounds[whichSound]); } } @@ -104,6 +94,7 @@ Avatar.skeletonModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-publi Avatar.billboardURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/billboards/bot" + botNumber + ".png"; Agent.isAvatar = true; +Agent.isListeningToAudioStream = true; // change the avatar's position to the random one Avatar.position = firstPosition; @@ -111,10 +102,10 @@ printVector("New bot, position = ", Avatar.position); function updateBehavior(deltaTime) { if (Math.random() < CHANCE_OF_SOUND) { - playRandomSound(Avatar.position); + playRandomSound(); } - if (isPlayingAudio) { + if (Agent.isPlayingAvatarSound) { Avatar.handPosition = Vec3.sum(Avatar.position, Quat.getFront(Avatar.orientation)); } From cbbe4af65fc269590b131386c316cabb2f114425 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 19 Mar 2014 17:17:52 -0700 Subject: [PATCH 51/51] fix crash in bot.js with incorrect playSound --- examples/bot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/bot.js b/examples/bot.js index ae337f5031..ebc8c4d5aa 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -63,7 +63,7 @@ var AVERAGE_AUDIO_LENGTH = 8000; function playRandomSound() { if (!Agent.isPlayingAvatarSound) { var whichSound = Math.floor((Math.random() * sounds.length) % sounds.length); - Audio.playSound(sounds[whichSound]); + Agent.playAvatarSound(sounds[whichSound]); } }