From 4f655bba3ff5b4ea49f11c97cb69bbf61d978c31 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 15 Feb 2017 09:29:45 -0800 Subject: [PATCH] more hacking --- assignment-client/src/Agent.cpp | 12 ++- assignment-client/src/avatars/AvatarMixer.cpp | 85 ++++++++----------- assignment-client/src/avatars/AvatarMixer.h | 6 +- .../src/avatars/AvatarMixerClientData.cpp | 38 ++++++++- .../src/avatars/AvatarMixerClientData.h | 10 ++- .../src/avatars/AvatarMixerSlave.cpp | 2 +- .../src/avatars/AvatarMixerSlavePool.h | 2 - 7 files changed, 93 insertions(+), 62 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index bea677aeb6..806608cd5f 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -434,8 +434,16 @@ void Agent::executeScript() { connect(&_avatarAudioTimerThread, &QThread::finished, audioTimerWorker, &QObject::deleteLater); _avatarAudioTimerThread.start(); - // 60Hz timer for avatar - QObject::connect(_scriptEngine.get(), &ScriptEngine::update, this, &Agent::processAgentAvatar); + // Agents should run at 45hz + static const int AVATAR_DATA_HZ = 45; + static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ; + QTimer* avatarDataTimer = new QTimer(this); + connect(avatarDataTimer, &QTimer::timeout, this, &Agent::processAgentAvatar); + avatarDataTimer->setSingleShot(false); + avatarDataTimer->setInterval(AVATAR_DATA_IN_MSECS); + avatarDataTimer->setTimerType(Qt::PreciseTimer); + avatarDataTimer->start(); + _scriptEngine->run(); Frame::clearFrameHandler(AUDIO_FRAME_TYPE); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 0590210c0b..1405e40f1b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -44,8 +44,9 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : connect(DependencyManager::get().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::AvatarData, this, "queueIncomingPacket"); + packetReceiver.registerListener(PacketType::ViewFrustum, this, "handleViewFrustumPacket"); - packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket"); packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket"); @@ -56,6 +57,14 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &AvatarMixer::handlePacketVersionMismatch); } +void AvatarMixer::queueIncomingPacket(QSharedPointer message, SharedNodePointer node) { + auto start = usecTimestampNow(); + getOrCreateClientData(node)->queuePacket(message, node); + auto end = usecTimestampNow(); + _queueIncomingPacketElapsedTime += (end - start); +} + + AvatarMixer::~AvatarMixer() { if (_broadcastTimer) { _broadcastTimer->deleteLater(); @@ -87,8 +96,11 @@ void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const Shar #include void AvatarMixer::start() { + auto nodeList = DependencyManager::get(); + //_slavePool.setNumThreads(1); // grins + while (!_isFinished) { _loopRate.increment(); @@ -99,34 +111,21 @@ void AvatarMixer::start() { // Allow nodes to process any pending/queued packets across our worker threads { auto start = usecTimestampNow(); - auto nodeList = DependencyManager::get(); - - /** - nodeList->eachNode([](const SharedNodePointer& node) { - auto nodeData = dynamic_cast(node->getLinkedData()); - if (nodeData) { - nodeData->processQueuedAvatarDataPackets(); - } - }); - **/ - nodeList->nestedEach([&](NodeList::const_iterator cbegin, NodeList::const_iterator cend) { - // mix across slave threads - { - _slavePool.processIncomingPackets(cbegin, cend); - } + _slavePool.processIncomingPackets(cbegin, cend); }); - auto end = usecTimestampNow(); _processQueuedAvatarDataPacketsElapsedTime += (end - start); } + + + // play nice with qt event-looping { // since we're a while loop we need to yield to qt's event processing auto start = usecTimestampNow(); QCoreApplication::processEvents(); - if (_isFinished) { // alert qt eventing that this is finished QCoreApplication::sendPostedEvents(this, QEvent::DeferredDelete); @@ -654,8 +653,7 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { void AvatarMixer::handleViewFrustumPacket(QSharedPointer message, SharedNodePointer senderNode) { auto start = usecTimestampNow(); - auto nodeList = DependencyManager::get(); - nodeList->getOrCreateLinkedData(senderNode); + getOrCreateClientData(senderNode); if (senderNode->getLinkedData()) { AvatarMixerClientData* nodeData = dynamic_cast(senderNode->getLinkedData()); @@ -671,8 +669,7 @@ void AvatarMixer::handleViewFrustumPacket(QSharedPointer messag void AvatarMixer::handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode) { auto start = usecTimestampNow(); - auto nodeList = DependencyManager::get(); - nodeList->getOrCreateLinkedData(senderNode); + getOrCreateClientData(senderNode); if (senderNode->getLinkedData()) { AvatarMixerClientData* nodeData = dynamic_cast(senderNode->getLinkedData()); @@ -686,25 +683,10 @@ void AvatarMixer::handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode) { - auto start = usecTimestampNow(); - - auto nodeList = DependencyManager::get(); - AvatarMixerClientData* nodeData = dynamic_cast(nodeList->getOrCreateLinkedData(senderNode)); - - if (nodeData) { - QMutexLocker linkedDataLocker(&nodeData->getMutex()); // NOTE: we might be able to safely assume this doesn't need to be locked! - nodeData->queueAvatarDataPacket(message); - } - - auto end = usecTimestampNow(); - _handleAvatarDataPacketElapsedTime += (end - start); -} - void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode) { auto start = usecTimestampNow(); auto nodeList = DependencyManager::get(); - nodeList->getOrCreateLinkedData(senderNode); + getOrCreateClientData(senderNode); if (senderNode->getLinkedData()) { AvatarMixerClientData* nodeData = dynamic_cast(senderNode->getLinkedData()); @@ -777,6 +759,8 @@ void AvatarMixer::sendStatsPacket() { statsObject["timing_average_y_processEvents"] = (float)_processEventsElapsedTime / (float)_numStatFrames; + statsObject["timing_average_y_queueIncomingPacket"] = (float)_queueIncomingPacketElapsedTime / (float)_numStatFrames; + statsObject["timing_average_z_handleAvatarDataPacket"] = (float)_handleAvatarDataPacketElapsedTime / (float)_numStatFrames; statsObject["timing_average_z_handleAvatarIdentityPacket"] = (float)_handleAvatarIdentityPacketElapsedTime / (float)_numStatFrames; @@ -799,6 +783,7 @@ void AvatarMixer::sendStatsPacket() { _handleRadiusIgnoreRequestPacketElapsedTime = 0; _handleRequestsDomainListDataPacketElapsedTime = 0; _processEventsElapsedTime = 0; + _queueIncomingPacketElapsedTime = 0; _processQueuedAvatarDataPacketsElapsedTime = 0; QJsonObject avatarsObject; @@ -875,23 +860,25 @@ void AvatarMixer::run() { start(); } +AvatarMixerClientData* AvatarMixer::getOrCreateClientData(SharedNodePointer node) { + auto clientData = dynamic_cast(node->getLinkedData()); + + if (!clientData) { + node->setLinkedData(std::unique_ptr { new AvatarMixerClientData(node->getUUID()) }); + clientData = dynamic_cast(node->getLinkedData()); + clientData->getAvatar().setDomainMinimumScale(_domainMinimumScale); + clientData->getAvatar().setDomainMaximumScale(_domainMaximumScale); + } + + return clientData; +} + void AvatarMixer::domainSettingsRequestComplete() { auto nodeList = DependencyManager::get(); nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::EntityScriptServer }); // parse the settings to pull out the values we need parseDomainServerSettings(nodeList->getDomainHandler().getSettingsObject()); - - float domainMinimumScale = _domainMinimumScale; - float domainMaximumScale = _domainMaximumScale; - - nodeList->linkedDataCreateCallback = [domainMinimumScale, domainMaximumScale] (Node* node) { - auto clientData = std::unique_ptr { new AvatarMixerClientData(node->getUUID()) }; - clientData->getAvatar().setDomainMinimumScale(domainMinimumScale); - clientData->getAvatar().setDomainMaximumScale(domainMaximumScale); - - node->setLinkedData(std::move(clientData)); - }; // start the broadcastThread _broadcastThread.start(); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 93e4087b36..b1d1dbef0b 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -40,8 +40,9 @@ public slots: void sendStatsPacket() override; private slots: + void queueIncomingPacket(QSharedPointer message, SharedNodePointer node); void handleViewFrustumPacket(QSharedPointer message, SharedNodePointer senderNode); - void handleAvatarDataPacket(QSharedPointer message, SharedNodePointer senderNode); + //void handleAvatarDataPacket(QSharedPointer message, SharedNodePointer senderNode); void handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode); void handleKillAvatarPacket(QSharedPointer message); void handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode); @@ -53,6 +54,8 @@ private slots: private: + AvatarMixerClientData* getOrCreateClientData(SharedNodePointer node); + void broadcastAvatarData(); void parseDomainServerSettings(const QJsonObject& domainSettings); void sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode); @@ -97,6 +100,7 @@ private: quint64 _processEventsElapsedTime { 0 }; quint64 _sendStatsElapsedTime { 0 }; + quint64 _queueIncomingPacketElapsedTime { 0 }; RateCounter<> _loopRate; // this is the rate that the main thread tight loop runs diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index ffa525bc35..5ba346ade9 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -16,13 +16,43 @@ #include "AvatarMixerClientData.h" -void AvatarMixerClientData::processQueuedAvatarDataPackets() { - for (auto message : _queuedAvatarDataPackets) { - parseData(*message); + + +void AvatarMixerClientData::queuePacket(QSharedPointer message, SharedNodePointer node) { + if (!_packetQueue.node) { + _packetQueue.node = node; } - _queuedAvatarDataPackets.clear(); + _packetQueue.push(message); } +// +// packetReceiver.registerListener(PacketType::ViewFrustum, this, "handleViewFrustumPacket"); +// packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket"); +// packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); +// packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); +// packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket"); +// packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); +// packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + +void AvatarMixerClientData::processPackets() { + SharedNodePointer node = _packetQueue.node; + assert(_packetQueue.empty() || node); + _packetQueue.node.clear(); + + while (!_packetQueue.empty()) { + auto& packet = _packetQueue.back(); + + switch (packet->getType()) { + case PacketType::AvatarData: + parseData(*packet); + break; + default: + Q_UNREACHABLE(); + } + _packetQueue.pop(); + } + assert(_packetQueue.empty()); +} int AvatarMixerClientData::parseData(ReceivedMessage& message) { // pull the sequence number from the data first diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 611af1701d..f43df28052 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -118,11 +119,14 @@ public: return _lastOtherAvatarSentJoints[otherAvatar]; } - void queueAvatarDataPacket(QSharedPointer message) { _queuedAvatarDataPackets.push_back(message); } - void processQueuedAvatarDataPackets(); + void queuePacket(QSharedPointer message, SharedNodePointer node); + void processPackets(); private: - std::vector> _queuedAvatarDataPackets; + struct PacketQueue : public std::queue> { + QWeakPointer node; + }; + PacketQueue _packetQueue; AvatarSharedPointer _avatar { new AvatarData() }; diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index b7676dac58..44f2060b52 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -38,7 +38,7 @@ void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) { void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) { auto nodeData = dynamic_cast(node->getLinkedData()); if (nodeData) { - nodeData->processQueuedAvatarDataPackets(); + nodeData->processPackets(); } } diff --git a/assignment-client/src/avatars/AvatarMixerSlavePool.h b/assignment-client/src/avatars/AvatarMixerSlavePool.h index ae4433d1c0..9865f897b9 100644 --- a/assignment-client/src/avatars/AvatarMixerSlavePool.h +++ b/assignment-client/src/avatars/AvatarMixerSlavePool.h @@ -92,8 +92,6 @@ private: // frame state Queue _queue; - unsigned int _frame { 0 }; - float _throttlingRatio { 0.0f }; ConstIter _begin; ConstIter _end; };