From 8006719fda737e7f10ac35758ca04b2e9427755e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Mar 2014 00:42:23 -0700 Subject: [PATCH 01/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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/55] 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 07497ea4f7e8a8faa51e06506f866698af47c893 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 18 Mar 2014 15:35:25 -0700 Subject: [PATCH 28/55] removing fly to voxel option --- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ca059a53da..c23b312d3a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -165,7 +165,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, false); - addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ClickToFly); + addAvatarCollisionSubMenu(editMenu); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index df622be6ac..f99ebe0685 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -272,7 +272,6 @@ namespace MenuOption { const QString OffAxisProjection = "Off-Axis Projection"; const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString TurnWithHead = "Turn using Head"; - const QString ClickToFly = "Fly to voxel on click"; const QString LoadScript = "Open and Run Script..."; const QString Oscilloscope = "Audio Oscilloscope"; const QString Pair = "Pair"; From 88fd686126eccb2afc62c97aeebf7b1fcd104d53 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 15:59:02 -0700 Subject: [PATCH 29/55] 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 30/55] 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 31/55] 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 32/55] 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 f86b793c96e06a5c6f3b9cec10a3f5e68913ac82 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Mar 2014 17:14:57 -0700 Subject: [PATCH 33/55] only output version mismatch once per sender per packet --- libraries/shared/src/NodeList.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 1e7a8cfaf0..6d699322de 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -88,9 +88,16 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { PacketType mismatchType = packetTypeForPacket(packet); int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data()); - qDebug() << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender" + static QMultiMap versionDebugSuppressMap; + + QUuid senderUUID = uuidFromPacketHeader(packet); + if (!versionDebugSuppressMap.contains(senderUUID, checkType)) { + qDebug() << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender" << uuidFromPacketHeader(packet) << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but" << qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected."; + + versionDebugSuppressMap.insert(senderUUID, checkType); + } return false; } From 0fc0d50bdaa7b8114d637ffdb3047d8e0b392840 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 17:19:42 -0700 Subject: [PATCH 34/55] 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 6340024daa906a4ecd8e3b0f760cec162332d4db Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 18 Mar 2014 17:42:58 -0700 Subject: [PATCH 35/55] fix bad startPosition in datagram unpack The startPosition was wrong (too far back) and the bytesRead return value was too big and the unpacking of the second chunk of the datagram would start in the middle of the chunk. --- 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 499c4bd500b40a9ae041ab9516d1ae7030774db4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Mar 2014 17:44:53 -0700 Subject: [PATCH 36/55] 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 37/55] 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 38/55] 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 39/55] 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 40/55] 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 41/55] 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 42/55] 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 43/55] 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 44/55] 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 45/55] 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 46/55] 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 47/55] 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 48/55] #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 49/55] #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 50/55] 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 51/55] 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 52/55] 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 53/55] 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 54/55] 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]); } } From 6440dd1b5fa9ed1fc3e5b27e1e3a873e06dcf633 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 20 Mar 2014 11:05:14 -0700 Subject: [PATCH 55/55] explicitly send neck angles in avatar data --- libraries/avatars/src/AvatarData.cpp | 26 ++++++++++++++++++++++++++ libraries/shared/src/PacketHeaders.cpp | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e5e0e4b3d7..4e57e311eb 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -88,6 +88,17 @@ QByteArray AvatarData::toByteArray() { // Body scale destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); + // Head rotation (NOTE: This needs to become a quaternion to save two bytes) + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedYaw()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedPitch()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedRoll()); + + // Head lean X,Z (head lateral and fwd/back motion relative to torso) + memcpy(destinationBuffer, &_headData->_leanSideways, sizeof(_headData->_leanSideways)); + destinationBuffer += sizeof(_headData->_leanSideways); + memcpy(destinationBuffer, &_headData->_leanForward, sizeof(_headData->_leanForward)); + destinationBuffer += sizeof(_headData->_leanForward); + // Lookat Position memcpy(destinationBuffer, &_headData->_lookAtPosition, sizeof(_headData->_lookAtPosition)); destinationBuffer += sizeof(_headData->_lookAtPosition); @@ -191,6 +202,21 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { // Body scale sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale); + // Head rotation (NOTE: This needs to become a quaternion to save two bytes) + float headYaw, headPitch, headRoll; + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll); + _headData->setYaw(headYaw); + _headData->setPitch(headPitch); + _headData->setRoll(headRoll); + + // Head position relative to pelvis + memcpy(&_headData->_leanSideways, sourceBuffer, sizeof(_headData->_leanSideways)); + sourceBuffer += sizeof(float); + memcpy(&_headData->_leanForward, sourceBuffer, sizeof(_headData->_leanForward)); + sourceBuffer += sizeof(_headData->_leanForward); + // Lookat Position memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); sourceBuffer += sizeof(_headData->_lookAtPosition); diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 307453d8bf..7d436b9ca6 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -45,7 +45,7 @@ int packArithmeticallyCodedValue(int value, char* destination) { PacketVersion versionForPacketType(PacketType type) { switch (type) { case PacketTypeAvatarData: - return 2; + return 3; case PacketTypeParticleData: return 1; case PacketTypeDomainList: