From 77ca4cf515601a7e8e249dc992f1e3ed690c06de Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 26 Jan 2017 17:38:32 -0700 Subject: [PATCH 01/24] Avoid holding 2 locks at same time If they are always called in same order, you are fine. But just in case, lets instead grab one lock, update the data, release it and then grab the other. No possible deadlock in that, even if the order is changed in one place or another. --- libraries/networking/src/NodeList.cpp | 40 +++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 7bfe1d1845..f4a02ad805 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -827,18 +827,26 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { }); if (ignoreEnabled) { - QReadLocker ignoredSetLocker{ &_ignoredSetLock }; // read lock for insert - QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert - // add this nodeID to our set of ignored IDs - _ignoredNodeIDs.insert(nodeID); - // add this nodeID to our set of personal muted IDs - _personalMutedNodeIDs.insert(nodeID); + { + QReadLocker ignoredSetLocker{ &_ignoredSetLock }; // read lock for insert + // add this nodeID to our set of ignored IDs + _ignoredNodeIDs.insert(nodeID); + } + { + QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert + // add this nodeID to our set of personal muted IDs + _personalMutedNodeIDs.insert(nodeID); + } emit ignoredNode(nodeID, true); } else { - QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; // write lock for unsafe_erase - QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; // write lock for unsafe_erase - _ignoredNodeIDs.unsafe_erase(nodeID); - _personalMutedNodeIDs.unsafe_erase(nodeID); + { + QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; // write lock for unsafe_erase + _ignoredNodeIDs.unsafe_erase(nodeID); + } + { + QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; // write lock for unsafe_erase + _personalMutedNodeIDs.unsafe_erase(nodeID); + } emit ignoredNode(nodeID, false); } @@ -850,10 +858,14 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { void NodeList::removeFromIgnoreMuteSets(const QUuid& nodeID) { // don't remove yourself, or nobody if (!nodeID.isNull() && _sessionUUID != nodeID) { - QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; - QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; - _ignoredNodeIDs.unsafe_erase(nodeID); - _personalMutedNodeIDs.unsafe_erase(nodeID); + { + QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; + _ignoredNodeIDs.unsafe_erase(nodeID); + } + { + QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; + _personalMutedNodeIDs.unsafe_erase(nodeID); + } } } From 24ca765a393caf9250f03e7288b26de25da110d9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 25 Jan 2017 18:32:42 -0500 Subject: [PATCH 02/24] add hrtf gain getter --- libraries/audio/src/AudioHRTF.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index 6a17a2d3cc..a197264994 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -48,6 +48,7 @@ public: // HRTF local gain adjustment in amplitude (1.0 == unity) // void setGainAdjustment(float gain) { _gainAdjust = HRTF_GAIN * gain; }; + float getGainAdjustment() { return _gainAdjust; } private: AudioHRTF(const AudioHRTF&) = delete; From 7bcf136dc9cce8a79796bf2c3f359b8601f44b66 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 27 Jan 2017 15:26:32 -0500 Subject: [PATCH 03/24] modularize audio throttle gain appx --- .../src/audio/AudioMixerSlave.cpp | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 4b02ca1567..52dc5c343a 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -47,9 +47,11 @@ void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& // mix helpers bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer& node); -float gainForSource(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, +float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, + const glm::vec3& relativePosition); +float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, bool isEcho); -float azimuthForSource(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, +float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); void AudioMixerSlave::configure(ConstIter begin, ConstIter end, unsigned int frame, float throttlingRatio) { @@ -126,9 +128,10 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { AudioMixerClientData&, const QUuid&, const AvatarAudioStream&, const PositionalAudioStream&); auto allStreams = [&](const SharedNodePointer& node, MixFunctor mixFunctor) { AudioMixerClientData* nodeData = static_cast(node->getLinkedData()); + auto nodeID = node->getUUID(); for (auto& streamPair : nodeData->getAudioStreams()) { auto nodeStream = streamPair.second; - (this->*mixFunctor)(*listenerData, node->getUUID(), *listenerAudioStream, *nodeStream); + (this->*mixFunctor)(*listenerData, nodeID, *listenerAudioStream, *nodeStream); } }; @@ -148,13 +151,19 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { allStreams(node, &AudioMixerSlave::mixStream); } else { AudioMixerClientData* nodeData = static_cast(node->getLinkedData()); + auto nodeID = node->getUUID(); // compute the node's max relative volume float nodeVolume; for (auto& streamPair : nodeData->getAudioStreams()) { auto nodeStream = streamPair.second; - float distance = glm::length(nodeStream->getPosition() - listenerAudioStream->getPosition()); - nodeVolume = std::max(nodeStream->getLastPopOutputTrailingLoudness() / distance, nodeVolume); + + // approximate the gain + glm::vec3 relativePosition = nodeStream->getPosition() - listenerAudioStream->getPosition(); + float gain = approximateGain(*listenerAudioStream, *nodeStream, relativePosition); + + auto streamVolume = nodeStream->getLastPopOutputTrailingLoudness() * gain; + nodeVolume = std::max(streamVolume, nodeVolume); } // max-heapify the nodes by relative volume @@ -227,8 +236,8 @@ void AudioMixerSlave::addStream(AudioMixerClientData& listenerNodeData, const QU glm::vec3 relativePosition = streamToAdd.getPosition() - listeningNodeStream.getPosition(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = gainForSource(listeningNodeStream, streamToAdd, relativePosition, isEcho); - float azimuth = isEcho ? 0.0f : azimuthForSource(listeningNodeStream, listeningNodeStream, relativePosition); + float gain = computeGain(listeningNodeStream, streamToAdd, relativePosition, isEcho); + float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); static const int HRTF_DATASET_INDEX = 1; if (!streamToAdd.lastPopSucceeded()) { @@ -475,7 +484,13 @@ bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer return ignore; } -float gainForSource(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, +float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, + const glm::vec3& relativePosition) { + float distance = glm::length(relativePosition); + return 1.0f / distance; +} + +float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, bool isEcho) { float gain = 1.0f; @@ -535,7 +550,7 @@ float gainForSource(const AvatarAudioStream& listeningNodeStream, const Position return gain; } -float azimuthForSource(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, +float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition) { glm::quat inverseOrientation = glm::inverse(listeningNodeStream.getOrientation()); From c4190ad4c478183a87a10fd3052c6b67e9329e7d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 27 Jan 2017 15:26:49 -0500 Subject: [PATCH 04/24] add hrtf adjustment to throttle gain appx --- assignment-client/src/audio/AudioMixerSlave.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 52dc5c343a..abee2aa054 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -162,6 +162,10 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { glm::vec3 relativePosition = nodeStream->getPosition() - listenerAudioStream->getPosition(); float gain = approximateGain(*listenerAudioStream, *nodeStream, relativePosition); + // modify by hrtf gain adjustment + auto& hrtf = listenerData->hrtfForStream(nodeID, nodeStream->getStreamIdentifier()); + gain *= hrtf.getGainAdjustment(); + auto streamVolume = nodeStream->getLastPopOutputTrailingLoudness() * gain; nodeVolume = std::max(streamVolume, nodeVolume); } From ca727b792022eb94a955de388a27f7f1557abd71 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 27 Jan 2017 15:28:43 -0500 Subject: [PATCH 05/24] inline audio mix helpers --- assignment-client/src/audio/AudioMixerSlave.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index abee2aa054..fc17e2f573 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -46,12 +46,12 @@ void sendMutePacket(const SharedNodePointer& node, AudioMixerClientData&); void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& data); // mix helpers -bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer& node); -float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, +inline bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer& node); +inline float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); -float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, +inline float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, bool isEcho); -float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, +inline float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); void AudioMixerSlave::configure(ConstIter begin, ConstIter end, unsigned int frame, float throttlingRatio) { From fe1847f96521b8eb4f6db6d8fa5e19fc748ba15d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 27 Jan 2017 15:46:12 -0500 Subject: [PATCH 06/24] clean up audio-mixer computeGain helper --- .../src/audio/AudioMixerSlave.cpp | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index fc17e2f573..6dced2d8cb 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -498,36 +498,30 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional const glm::vec3& relativePosition, bool isEcho) { float gain = 1.0f; - float distanceBetween = glm::length(relativePosition); - - if (distanceBetween < EPSILON) { - distanceBetween = EPSILON; - } - + // injector: apply attenuation if (streamToAdd.getType() == PositionalAudioStream::Injector) { gain *= reinterpret_cast(&streamToAdd)->getAttenuationRatio(); } + // avatar: apply fixed off-axis attentuation to make them quieter as they turn away if (!isEcho && (streamToAdd.getType() == PositionalAudioStream::Microphone)) { - // source is another avatar, apply fixed off-axis attenuation to make them quieter as they turn away from listener glm::vec3 rotatedListenerPosition = glm::inverse(streamToAdd.getOrientation()) * relativePosition; - float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedListenerPosition)); const float MAX_OFF_AXIS_ATTENUATION = 0.2f; - const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; - + const float OFF_AXIS_ATTENUATION_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO)); + (OFF_AXIS_ATTENUATION_STEP * (angleOfDelivery / PI_OVER_TWO)); - // multiply the current attenuation coefficient by the calculated off axis coefficient gain *= offAxisCoefficient; } - float attenuationPerDoublingInDistance = AudioMixer::getAttenuationPerDoublingInDistance(); - auto& zoneSettings = AudioMixer::getZoneSettings(); auto& audioZones = AudioMixer::getAudioZones(); + auto& zoneSettings = AudioMixer::getZoneSettings(); + + // find distance attenuation coefficient + float attenuationPerDoublingInDistance = AudioMixer::getAttenuationPerDoublingInDistance(); for (int i = 0; i < zoneSettings.length(); ++i) { if (audioZones[zoneSettings[i].source].contains(streamToAdd.getPosition()) && audioZones[zoneSettings[i].listener].contains(listeningNodeStream.getPosition())) { @@ -536,16 +530,17 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional } } - const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f; - if (distanceBetween >= ATTENUATION_BEGINS_AT_DISTANCE) { + // compute distance attenuation + const float ATTENUATION_START_DISTANCE = 1.0f; + float distance = std::max(glm::length(relativePosition), EPSILON); + if (distance >= ATTENUATION_START_DISTANCE) { // translate the zone setting to gain per log2(distance) float g = 1.0f - attenuationPerDoublingInDistance; - g = (g < EPSILON) ? EPSILON : g; - g = (g > 1.0f) ? 1.0f : g; + g = glm::clamp(g, EPSILON, 1.0f); // calculate the distance coefficient using the distance to this node - float distanceCoefficient = fastExp2f(fastLog2f(g) * fastLog2f(distanceBetween/ATTENUATION_BEGINS_AT_DISTANCE)); + float distanceCoefficient = fastExp2f(fastLog2f(g) * fastLog2f(distance/ATTENUATION_START_DISTANCE)); // multiply the current attenuation coefficient by the distance coefficient gain *= distanceCoefficient; From 2da4dce8beff82c61979b3d6cc193b6e35115a76 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 27 Jan 2017 15:46:25 -0500 Subject: [PATCH 07/24] rm statics from audio-mixer mixing --- assignment-client/src/audio/AudioMixerSlave.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 6dced2d8cb..14ab033263 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -242,7 +242,7 @@ void AudioMixerSlave::addStream(AudioMixerClientData& listenerNodeData, const QU float distance = glm::max(glm::length(relativePosition), EPSILON); float gain = computeGain(listeningNodeStream, streamToAdd, relativePosition, isEcho); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); - static const int HRTF_DATASET_INDEX = 1; + const int HRTF_DATASET_INDEX = 1; if (!streamToAdd.lastPopSucceeded()) { bool forceSilentBlock = true; @@ -343,7 +343,7 @@ std::unique_ptr createAudioPacket(PacketType type, int size, quint16 s } void sendMixPacket(const SharedNodePointer& node, AudioMixerClientData& data, QByteArray& buffer) { - static const int MIX_PACKET_SIZE = + const int MIX_PACKET_SIZE = sizeof(quint16) + AudioConstants::MAX_CODEC_NAME_LENGTH_ON_WIRE + AudioConstants::NETWORK_FRAME_BYTES_STEREO; quint16 sequence = data.getOutgoingSequenceNumber(); QString codec = data.getCodecName(); @@ -358,7 +358,7 @@ void sendMixPacket(const SharedNodePointer& node, AudioMixerClientData& data, QB } void sendSilentPacket(const SharedNodePointer& node, AudioMixerClientData& data) { - static const int SILENT_PACKET_SIZE = + const int SILENT_PACKET_SIZE = sizeof(quint16) + AudioConstants::MAX_CODEC_NAME_LENGTH_ON_WIRE + sizeof(quint16); quint16 sequence = data.getOutgoingSequenceNumber(); QString codec = data.getCodecName(); From e7e550d78c92b7324e046eb6d0fd79ed60f36c5c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 27 Jan 2017 16:18:10 -0500 Subject: [PATCH 08/24] add injector attenuation to audio gain appx --- .../src/audio/AudioMixerSlave.cpp | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 14ab033263..565652ac2f 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -488,10 +488,25 @@ bool shouldIgnoreNode(const SharedNodePointer& listener, const SharedNodePointer return ignore; } +static const float ATTENUATION_START_DISTANCE = 1.0f; + float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition) { + float gain = 1.0f; + + // injector: apply attenuation + if (streamToAdd.getType() == PositionalAudioStream::Injector) { + gain *= reinterpret_cast(&streamToAdd)->getAttenuationRatio(); + } + + // avatar: skip attenuation - it is too costly to approximate + + // distance attenuation: approximate, ignore zone-specific attenuations + // this is a good approximation for streams further than ATTENUATION_START_DISTANCE + // those streams closer will be amplified; amplifying close streams is acceptable + // when throttling, as close streams are expected to be heard by a user float distance = glm::length(relativePosition); - return 1.0f / distance; + return gain / distance; } float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, @@ -501,10 +516,9 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional // injector: apply attenuation if (streamToAdd.getType() == PositionalAudioStream::Injector) { gain *= reinterpret_cast(&streamToAdd)->getAttenuationRatio(); - } - // avatar: apply fixed off-axis attentuation to make them quieter as they turn away - if (!isEcho && (streamToAdd.getType() == PositionalAudioStream::Microphone)) { + // avatar: apply fixed off-axis attenuation to make them quieter as they turn away + } else if (!isEcho && (streamToAdd.getType() == PositionalAudioStream::Microphone)) { glm::vec3 rotatedListenerPosition = glm::inverse(streamToAdd.getOrientation()) * relativePosition; float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedListenerPosition)); @@ -530,9 +544,9 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional } } - // compute distance attenuation - const float ATTENUATION_START_DISTANCE = 1.0f; - float distance = std::max(glm::length(relativePosition), EPSILON); + // distance attenuation + float distance = glm::length(relativePosition); + assert(ATTENUATION_START_DISTANCE > EPSILON); if (distance >= ATTENUATION_START_DISTANCE) { // translate the zone setting to gain per log2(distance) From eb00c7ba1115a39d65b48778c59240539f76ca02 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 30 Jan 2017 17:37:32 +0000 Subject: [PATCH 09/24] group constants in audio mixer gain computation --- assignment-client/src/audio/AudioMixerSlave.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 565652ac2f..1e78507e28 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -526,7 +526,7 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional const float MAX_OFF_AXIS_ATTENUATION = 0.2f; const float OFF_AXIS_ATTENUATION_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_STEP * (angleOfDelivery / PI_OVER_TWO)); + (angleOfDelivery * (OFF_AXIS_ATTENUATION_STEP / PI_OVER_TWO)); gain *= offAxisCoefficient; } From 069c85c7c250773f1302870d3679e1d1fd187c62 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 3 Feb 2017 08:52:33 -0700 Subject: [PATCH 10/24] I like this better --- libraries/networking/src/NodeList.cpp | 53 ++++++++++++++------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index f4a02ad805..ee8c2e1ecf 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -827,26 +827,28 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { }); if (ignoreEnabled) { - { - QReadLocker ignoredSetLocker{ &_ignoredSetLock }; // read lock for insert - // add this nodeID to our set of ignored IDs - _ignoredNodeIDs.insert(nodeID); - } - { - QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert - // add this nodeID to our set of personal muted IDs - _personalMutedNodeIDs.insert(nodeID); - } + // add this nodeID to our set of ignored IDs + _ignoredSetLock.lockForRead(); + _ignoredNodeIDs.insert(nodeID); + _ignoredSetLock.unlock(); + + // add this nodeID to our set of personal muted IDs + _personalMutedSetLock.lockForRead(); + _personalMutedNodeIDs.insert(nodeID); + _personalMutedSetLock.unlock(); + emit ignoredNode(nodeID, true); } else { - { - QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; // write lock for unsafe_erase - _ignoredNodeIDs.unsafe_erase(nodeID); - } - { - QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; // write lock for unsafe_erase - _personalMutedNodeIDs.unsafe_erase(nodeID); - } + // write lock for unsafe_erase + _ignoredSetLock.lockForWrite(); + _ignoredNodeIDs.unsafe_erase(nodeID); + _ignoredSetLock.unlock(); + + // write lock for unsafe_erase + _personalMutedSetLock.lockForWrite(); + _personalMutedNodeIDs.unsafe_erase(nodeID); + _personalMutedSetLock.unlock(); + emit ignoredNode(nodeID, false); } @@ -858,14 +860,13 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { void NodeList::removeFromIgnoreMuteSets(const QUuid& nodeID) { // don't remove yourself, or nobody if (!nodeID.isNull() && _sessionUUID != nodeID) { - { - QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; - _ignoredNodeIDs.unsafe_erase(nodeID); - } - { - QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; - _personalMutedNodeIDs.unsafe_erase(nodeID); - } + _ignoredSetLock.lockForWrite(); + _ignoredNodeIDs.unsafe_erase(nodeID); + _ignoredSetLock.unlock(); + + _personalMutedSetLock.lockForWrite(); + _personalMutedNodeIDs.unsafe_erase(nodeID); + _personalMutedSetLock.unlock(); } } From 8612302f07798cc5cc25cdad738b652d61043635 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 3 Feb 2017 10:08:46 -0700 Subject: [PATCH 11/24] Revert "I like this better" This reverts commit 069c85c7c250773f1302870d3679e1d1fd187c62. --- libraries/networking/src/NodeList.cpp | 53 +++++++++++++-------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index ee8c2e1ecf..f4a02ad805 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -827,28 +827,26 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { }); if (ignoreEnabled) { - // add this nodeID to our set of ignored IDs - _ignoredSetLock.lockForRead(); - _ignoredNodeIDs.insert(nodeID); - _ignoredSetLock.unlock(); - - // add this nodeID to our set of personal muted IDs - _personalMutedSetLock.lockForRead(); - _personalMutedNodeIDs.insert(nodeID); - _personalMutedSetLock.unlock(); - + { + QReadLocker ignoredSetLocker{ &_ignoredSetLock }; // read lock for insert + // add this nodeID to our set of ignored IDs + _ignoredNodeIDs.insert(nodeID); + } + { + QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert + // add this nodeID to our set of personal muted IDs + _personalMutedNodeIDs.insert(nodeID); + } emit ignoredNode(nodeID, true); } else { - // write lock for unsafe_erase - _ignoredSetLock.lockForWrite(); - _ignoredNodeIDs.unsafe_erase(nodeID); - _ignoredSetLock.unlock(); - - // write lock for unsafe_erase - _personalMutedSetLock.lockForWrite(); - _personalMutedNodeIDs.unsafe_erase(nodeID); - _personalMutedSetLock.unlock(); - + { + QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; // write lock for unsafe_erase + _ignoredNodeIDs.unsafe_erase(nodeID); + } + { + QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; // write lock for unsafe_erase + _personalMutedNodeIDs.unsafe_erase(nodeID); + } emit ignoredNode(nodeID, false); } @@ -860,13 +858,14 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { void NodeList::removeFromIgnoreMuteSets(const QUuid& nodeID) { // don't remove yourself, or nobody if (!nodeID.isNull() && _sessionUUID != nodeID) { - _ignoredSetLock.lockForWrite(); - _ignoredNodeIDs.unsafe_erase(nodeID); - _ignoredSetLock.unlock(); - - _personalMutedSetLock.lockForWrite(); - _personalMutedNodeIDs.unsafe_erase(nodeID); - _personalMutedSetLock.unlock(); + { + QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; + _ignoredNodeIDs.unsafe_erase(nodeID); + } + { + QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; + _personalMutedNodeIDs.unsafe_erase(nodeID); + } } } From f8e6bd8c6b1524cfdcf9e15c552863269c7affbb Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 3 Feb 2017 10:53:26 -0800 Subject: [PATCH 12/24] Allow multiple instances to run if environment variable is set If the environment variable HIFI_ALLOW_MULTIPLE_INSTANCES is present, the value is ignored, then you can have multiple copies of interface running on the same machine. --- interface/src/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index d33dba535e..39b37e3d19 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -74,6 +74,11 @@ int main(int argc, const char* argv[]) { instanceMightBeRunning = !sharedMemory.create(1, QSharedMemory::ReadOnly); #endif + // allow multiple interfaces to run if this environment variable is set. + if (QProcessEnvironment::systemEnvironment().contains("HIFI_ALLOW_MULTIPLE_INSTANCES")) { + instanceMightBeRunning = false; + } + if (instanceMightBeRunning) { // Try to connect and send message to existing interface instance QLocalSocket socket; From 0c28776ea2f3fd494d9d0e6c3df9f1cf6d0b7309 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 4 Feb 2017 00:13:39 +0000 Subject: [PATCH 13/24] some tweaks to users and menus got tablet --- interface/resources/qml/hifi/tablet/TabletMouseHandler.qml | 7 ++++++- scripts/system/tablet-users.js | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml index 32e34e279b..258a4c2f12 100644 --- a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml +++ b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml @@ -87,7 +87,11 @@ Item { if (topMenu.objectName === "") { breadcrumbText.text = "Menu"; } else { - breadcrumbText.text = topMenu.objectName; + if (menuStack.length === 1) { + breadcrumbText.text = "Menu"; + } else { + breadcrumbText.text = topMenu.objectName; + } } } else { breadcrumbText.text = "Menu"; @@ -164,6 +168,7 @@ Item { d.popMenu(); return true; } + return false; } diff --git a/scripts/system/tablet-users.js b/scripts/system/tablet-users.js index 0fad0c56f3..a47e4c8c5c 100644 --- a/scripts/system/tablet-users.js +++ b/scripts/system/tablet-users.js @@ -12,6 +12,7 @@ (function() { // BEGIN LOCAL_SCOPE var USERS_URL = "https://hifi-content.s3.amazonaws.com/faye/tablet-dev/users.html"; + var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png"; var FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends"; var FRIENDS_WINDOW_WIDTH = 290; @@ -39,6 +40,10 @@ }); function onClicked() { + var tabletEntity = HMD.tabletID; + if (tabletEntity) { + Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); + } tablet.gotoWebScreen(USERS_URL); } From dd8f095bd8463a157737ae20ab87192c5587429e Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 4 Feb 2017 00:36:41 +0000 Subject: [PATCH 14/24] minimize diff --- interface/resources/qml/hifi/tablet/TabletMouseHandler.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml index 258a4c2f12..17a00eccde 100644 --- a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml +++ b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml @@ -168,7 +168,6 @@ Item { d.popMenu(); return true; } - return false; } From 45c73439eb0b64af64164098d2696a1cc7b54107 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:34:22 -0800 Subject: [PATCH 15/24] use type definition --- libraries/model-networking/src/model-networking/ModelCache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index bcca846625..adef3ce2b5 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -159,7 +159,7 @@ protected: class Texture { public: QString name; - QSharedPointer texture; + NetworkTexturePointer texture; }; using Textures = std::vector; From 24b1f3ddbc90d903937663ebf7b8708068a5e9c4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:34:44 -0800 Subject: [PATCH 16/24] cleanup whitespace --- libraries/fbx/src/FBXReader_Material.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 8c0f4b34ac..f3d0c30a41 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -47,10 +47,10 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { texture.texcoordSet = 0; if (_textureParams.contains(textureID)) { auto p = _textureParams.value(textureID); - + texture.transform.setTranslation(p.translation); texture.transform.setRotation(glm::quat(glm::radians(p.rotation))); - + auto scaling = p.scaling; // Protect from bad scaling which should never happen if (scaling.x == 0.0f) { @@ -63,7 +63,7 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { scaling.z = 1.0f; } texture.transform.setScale(scaling); - + if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) { texture.texcoordSet = 1; } @@ -78,11 +78,10 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { QJsonDocument materialMapDocument = QJsonDocument::fromJson(materialMapString.toUtf8()); QJsonObject materialMap = materialMapDocument.object(); - // foreach (const QString& materialID, materials) { for (QHash::iterator it = _fbxMaterials.begin(); it != _fbxMaterials.end(); it++) { FBXMaterial& material = (*it); - // Maya is the exporting the shading model and we aretrying to use it + // Maya is the exporting the shading model and we are trying to use it bool isMaterialLambert = (material.shadingModel.toLower() == "lambert"); // the pure material associated with this part @@ -127,21 +126,19 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity()); } - - FBXTexture normalTexture; QString bumpTextureID = bumpTextures.value(material.materialID); QString normalTextureID = normalTextures.value(material.materialID); if (!normalTextureID.isNull()) { normalTexture = getTexture(normalTextureID); normalTexture.isBumpmap = false; - + material.normalTexture = normalTexture; detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); } else if (!bumpTextureID.isNull()) { normalTexture = getTexture(bumpTextureID); normalTexture.isBumpmap = true; - + material.normalTexture = normalTexture; detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); } @@ -151,7 +148,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { if (!specularTextureID.isNull()) { specularTexture = getTexture(specularTextureID); detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity()); - material.specularTexture = specularTexture; + material.specularTexture = specularTexture; } FBXTexture metallicTexture; @@ -222,7 +219,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { ambientTextureID = ambientFactorTextures.value(material.materialID); } } - + if (_loadLightmaps && !ambientTextureID.isNull()) { ambientTexture = getTexture(ambientTextureID); detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity()); From b3ae6f9aec65917d18bcfc26145b807ca85a1792 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:35:40 -0800 Subject: [PATCH 17/24] cap size of textures from FBX files --- libraries/fbx/src/FBXReader.h | 9 ++-- .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/TextureCache.cpp | 53 +++++++++++++------ .../src/model-networking/TextureCache.h | 13 +++-- libraries/networking/src/ResourceCache.h | 4 +- 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index cd1dbc5c4f..8b58ad62d1 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -100,22 +100,25 @@ public: /// A single binding to a joint in an FBX document. class FBXCluster { public: - + int jointIndex; glm::mat4 inverseBindMatrix; }; +const int MAX_FBX_TEXTURE_SIZE = 1024 * 1024; + /// A texture map in an FBX document. class FBXTexture { public: QString name; QByteArray filename; QByteArray content; - + Transform transform; + int maxSize { MAX_FBX_TEXTURE_SIZE }; int texcoordSet; QString texcoordSetName; - + bool isBumpmap{ false }; bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2a02540821..946e507d98 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -472,7 +472,7 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, TextureType type, MapChannel channel) { const auto url = getTextureUrl(baseUrl, fbxTexture); - const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content); + const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxSize); _textures[channel] = Texture { fbxTexture.name, texture }; auto map = std::make_shared(); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 6a4edd60ed..e108e69aa1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -167,16 +167,17 @@ class TextureExtra { public: NetworkTexture::Type type; const QByteArray& content; + int maxSize; }; -ScriptableResource* TextureCache::prefetch(const QUrl& url, int type) { +ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxSize) { auto byteArray = QByteArray(); - TextureExtra extra = { (Type)type, byteArray }; + TextureExtra extra = { (Type)type, byteArray, maxSize }; return ResourceCache::prefetch(url, &extra); } -NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content) { - TextureExtra extra = { type, content }; +NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) { + TextureExtra extra = { type, content, maxSize }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } @@ -251,13 +252,15 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh const TextureExtra* textureExtra = static_cast(extra); auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE; auto content = textureExtra ? textureExtra->content : QByteArray(); - return QSharedPointer(new NetworkTexture(url, type, content), + auto maxSize = textureExtra ? textureExtra->maxSize : ABSOLUTE_MAX_TEXTURE_SIZE; + return QSharedPointer(new NetworkTexture(url, type, content, maxSize), &Resource::deleter); } -NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content) : +NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) : Resource(url), - _type(type) + _type(type), + _maxSize(maxSize) { _textureSource = std::make_shared(); @@ -274,7 +277,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& con } NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) : - NetworkTexture(url, CUSTOM_TEXTURE, content) + NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_SIZE) { _textureLoader = textureLoader; } @@ -290,7 +293,8 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& resource, const QByteArray& data, const QUrl& url = QUrl()); + ImageReader(const QWeakPointer& resource, const QByteArray& data, + const QUrl& url = QUrl(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); virtual void run() override; @@ -300,6 +304,7 @@ private: QWeakPointer _resource; QUrl _url; QByteArray _content; + int _maxSize; }; void NetworkTexture::downloadFinished(const QByteArray& data) { @@ -308,14 +313,15 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); + QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxSize)); } ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url) : + const QUrl& url, int maxSize) : _resource(resource), _url(url), - _content(data) + _content(data), + _maxSize(maxSize) { #if DEBUG_DUMP_TEXTURE_LOADS static auto start = usecTimestampNow() / USECS_PER_MSEC; @@ -375,10 +381,10 @@ void ImageReader::run() { // Note that QImage.format is the pixel format which is different from the "format" of the image file... auto imageFormat = image.format(); - int originalWidth = image.width(); - int originalHeight = image.height(); + int imageWidth = image.width(); + int imageHeight = image.height(); - if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { + if (imageWidth == 0 || imageHeight == 0 || imageFormat == QImage::Format_Invalid) { if (filenameExtension.empty()) { qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url; } else { @@ -386,6 +392,21 @@ void ImageReader::run() { } return; } + + if (imageWidth * imageHeight > _maxSize) { + float scaleFactor = sqrtf(_maxSize / (float)(imageWidth * imageHeight)); + int originalWidth = imageWidth; + int originalHeight = imageHeight; + imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f); + imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f); + //QSize newSize(imageWidth, imageHeight); + QImage newImage = image.scaled(QSize(imageWidth, imageHeight), Qt::IgnoreAspectRatio); + image.swap(newImage); + qCDebug(modelnetworking) << "Downscale image" << _url + << "from" << originalWidth << "x" << originalHeight + << "to" << imageWidth << "x" << imageHeight; + } + gpu::TexturePointer texture = nullptr; { // Double-check the resource still exists between long operations. @@ -408,7 +429,7 @@ void ImageReader::run() { } else { QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, texture), - Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); + Q_ARG(int, imageWidth), Q_ARG(int, imageHeight)); } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 8ccfe5364c..9ad06eddfb 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -23,6 +23,8 @@ #include #include +const int ABSOLUTE_MAX_TEXTURE_SIZE = 8192 * 8192; + namespace gpu { class Batch; } @@ -60,7 +62,7 @@ public: typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName); using TextureLoaderFunc = std::function; - NetworkTexture(const QUrl& url, Type type, const QByteArray& content); + NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize); NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content); QString getType() const override { return "NetworkTexture"; } @@ -70,7 +72,7 @@ public: int getWidth() const { return _width; } int getHeight() const { return _height; } Type getTextureType() const { return _type; } - + TextureLoaderFunc getTextureLoader() const; signals: @@ -81,7 +83,7 @@ protected: virtual bool isCacheable() const override { return _loaded; } virtual void downloadFinished(const QByteArray& data) override; - + Q_INVOKABLE void loadContent(const QByteArray& content); Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); @@ -92,6 +94,7 @@ private: int _originalHeight { 0 }; int _width { 0 }; int _height { 0 }; + int _maxSize { ABSOLUTE_MAX_TEXTURE_SIZE }; }; using NetworkTexturePointer = QSharedPointer; @@ -129,11 +132,11 @@ public: /// Loads a texture from the specified URL. NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE, - const QByteArray& content = QByteArray()); + const QByteArray& content = QByteArray(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads - Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type); + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 03d37bc9ac..a369416ebe 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -86,7 +86,7 @@ private: /// Wrapper to expose resources to JS/QML class ScriptableResource : public QObject { Q_OBJECT - Q_PROPERTY(QUrl url READ getUrl) + Q_PROPERTY(QUrl url READ getURL) Q_PROPERTY(int state READ getState NOTIFY stateChanged) /**jsdoc @@ -125,7 +125,7 @@ public: */ Q_INVOKABLE void release(); - const QUrl& getUrl() const { return _url; } + const QUrl& getURL() const { return _url; } int getState() const { return (int)_state; } const QSharedPointer& getResource() const { return _resource; } From d65cbbb455cab8a1994be4db65c6a6e1e3ba9ab1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 14:09:47 -0800 Subject: [PATCH 18/24] name change: maxSize to maxNumPixels --- libraries/fbx/src/FBXReader.h | 4 +-- .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/TextureCache.cpp | 35 +++++++++---------- .../src/model-networking/TextureCache.h | 10 +++--- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 8b58ad62d1..5b4d3ec3bf 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -105,7 +105,7 @@ public: glm::mat4 inverseBindMatrix; }; -const int MAX_FBX_TEXTURE_SIZE = 1024 * 1024; +const int MAX_FBX_TEXTURE_NUM_PIXELS = 1024 * 1024; /// A texture map in an FBX document. class FBXTexture { @@ -115,7 +115,7 @@ public: QByteArray content; Transform transform; - int maxSize { MAX_FBX_TEXTURE_SIZE }; + int maxNumPixels { MAX_FBX_TEXTURE_NUM_PIXELS }; int texcoordSet; QString texcoordSetName; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 946e507d98..dd3193073d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -472,7 +472,7 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, TextureType type, MapChannel channel) { const auto url = getTextureUrl(baseUrl, fbxTexture); - const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxSize); + const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxNumPixels); _textures[channel] = Texture { fbxTexture.name, texture }; auto map = std::make_shared(); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index e108e69aa1..447a1b93c8 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -167,17 +167,17 @@ class TextureExtra { public: NetworkTexture::Type type; const QByteArray& content; - int maxSize; + int maxNumPixels; }; -ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxSize) { +ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNumPixels) { auto byteArray = QByteArray(); - TextureExtra extra = { (Type)type, byteArray, maxSize }; + TextureExtra extra = { (Type)type, byteArray, maxNumPixels }; return ResourceCache::prefetch(url, &extra); } -NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) { - TextureExtra extra = { type, content, maxSize }; +NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) { + TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } @@ -252,15 +252,15 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh const TextureExtra* textureExtra = static_cast(extra); auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE; auto content = textureExtra ? textureExtra->content : QByteArray(); - auto maxSize = textureExtra ? textureExtra->maxSize : ABSOLUTE_MAX_TEXTURE_SIZE; - return QSharedPointer(new NetworkTexture(url, type, content, maxSize), + auto maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS; + return QSharedPointer(new NetworkTexture(url, type, content, maxNumPixels), &Resource::deleter); } -NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) : +NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) : Resource(url), _type(type), - _maxSize(maxSize) + _maxNumPixels(maxNumPixels) { _textureSource = std::make_shared(); @@ -277,7 +277,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& con } NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) : - NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_SIZE) + NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_NUM_PIXELS) { _textureLoader = textureLoader; } @@ -294,7 +294,7 @@ class ImageReader : public QRunnable { public: ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url = QUrl(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + const QUrl& url = QUrl(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); virtual void run() override; @@ -304,7 +304,7 @@ private: QWeakPointer _resource; QUrl _url; QByteArray _content; - int _maxSize; + int _maxNumPixels; }; void NetworkTexture::downloadFinished(const QByteArray& data) { @@ -313,15 +313,15 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxSize)); + QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxNumPixels)); } ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url, int maxSize) : + const QUrl& url, int maxNumPixels) : _resource(resource), _url(url), _content(data), - _maxSize(maxSize) + _maxNumPixels(maxNumPixels) { #if DEBUG_DUMP_TEXTURE_LOADS static auto start = usecTimestampNow() / USECS_PER_MSEC; @@ -393,13 +393,12 @@ void ImageReader::run() { return; } - if (imageWidth * imageHeight > _maxSize) { - float scaleFactor = sqrtf(_maxSize / (float)(imageWidth * imageHeight)); + if (imageWidth * imageHeight > _maxNumPixels) { + float scaleFactor = sqrtf(_maxNumPixels / (float)(imageWidth * imageHeight)); int originalWidth = imageWidth; int originalHeight = imageHeight; imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f); imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f); - //QSize newSize(imageWidth, imageHeight); QImage newImage = image.scaled(QSize(imageWidth, imageHeight), Qt::IgnoreAspectRatio); image.swap(newImage); qCDebug(modelnetworking) << "Downscale image" << _url diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 9ad06eddfb..cb509490c6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -23,7 +23,7 @@ #include #include -const int ABSOLUTE_MAX_TEXTURE_SIZE = 8192 * 8192; +const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192; namespace gpu { class Batch; @@ -62,7 +62,7 @@ public: typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName); using TextureLoaderFunc = std::function; - NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize); + NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels); NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content); QString getType() const override { return "NetworkTexture"; } @@ -94,7 +94,7 @@ private: int _originalHeight { 0 }; int _width { 0 }; int _height { 0 }; - int _maxSize { ABSOLUTE_MAX_TEXTURE_SIZE }; + int _maxNumPixels { ABSOLUTE_MAX_TEXTURE_NUM_PIXELS }; }; using NetworkTexturePointer = QSharedPointer; @@ -132,11 +132,11 @@ public: /// Loads a texture from the specified URL. NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE, - const QByteArray& content = QByteArray(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads - Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; From 8b2c720e2994c89c6dfe2f3202047e0f8b971f21 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 3 Feb 2017 11:14:40 -0800 Subject: [PATCH 19/24] sliding texture caps for models --- libraries/fbx/src/FBXReader.cpp | 27 +++++++++++++ libraries/fbx/src/FBXReader.h | 8 +++- libraries/fbx/src/FBXReader_Material.cpp | 50 ++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 42922ce226..917009956e 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1465,6 +1465,33 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // Create the Material Library consolidateFBXMaterials(mapping); + + // HACK: until we get proper LOD management we're going to cap model textures + // according to how many unique textures the model uses: + // 1 - 7 textures --> 2048 + // 8 - 31 textures --> 1024 + // 32 - 127 textures --> 512 + // etc... + QSet uniqueTextures; + for (auto& material : _fbxMaterials) { + material.getTextureNames(uniqueTextures); + } + int numTextures = uniqueTextures.size(); + const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 7; + if (numTextures > MAX_NUM_TEXTURES_AT_MAX_RESOLUTION) { + int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE + 1); + int t = numTextures; + t /= MAX_NUM_TEXTURES_AT_MAX_RESOLUTION; + while (t > 0) { + maxWidth /= 2; + t /= 4; + } + qCDebug(modelformat) << "max square texture width =" << maxWidth << " for model" << url; + for (auto& material : _fbxMaterials) { + material.setMaxNumPixelsPerTexture(maxWidth * maxWidth); + } + } + geometry.materials = _fbxMaterials; // see if any materials have texture children diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 5b4d3ec3bf..b0e34dd674 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -13,6 +13,7 @@ #define hifi_FBXReader_h #include +#include #include #include #include @@ -105,7 +106,7 @@ public: glm::mat4 inverseBindMatrix; }; -const int MAX_FBX_TEXTURE_NUM_PIXELS = 1024 * 1024; +const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; /// A texture map in an FBX document. class FBXTexture { @@ -115,7 +116,7 @@ public: QByteArray content; Transform transform; - int maxNumPixels { MAX_FBX_TEXTURE_NUM_PIXELS }; + int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE }; int texcoordSet; QString texcoordSetName; @@ -146,6 +147,9 @@ public: shininess(shininess), opacity(opacity) {} + void getTextureNames(QSet& textureList) const; + void setMaxNumPixelsPerTexture(int maxNumPixels); + glm::vec3 diffuseColor{ 1.0f }; float diffuseFactor{ 1.0f }; glm::vec3 specularColor{ 0.02f }; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index f3d0c30a41..ca2ec557b4 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -27,6 +27,56 @@ #include "ModelFormatLogging.h" +void FBXMaterial::getTextureNames(QSet& textureList) const { + if (!normalTexture.isNull()) { + textureList.insert(normalTexture.name); + } + if (!albedoTexture.isNull()) { + textureList.insert(albedoTexture.name); + } + if (!opacityTexture.isNull()) { + textureList.insert(opacityTexture.name); + } + if (!glossTexture.isNull()) { + textureList.insert(glossTexture.name); + } + if (!roughnessTexture.isNull()) { + textureList.insert(roughnessTexture.name); + } + if (!specularTexture.isNull()) { + textureList.insert(specularTexture.name); + } + if (!metallicTexture.isNull()) { + textureList.insert(metallicTexture.name); + } + if (!emissiveTexture.isNull()) { + textureList.insert(emissiveTexture.name); + } + if (!occlusionTexture.isNull()) { + textureList.insert(occlusionTexture.name); + } + if (!scatteringTexture.isNull()) { + textureList.insert(scatteringTexture.name); + } + if (!lightmapTexture.isNull()) { + textureList.insert(lightmapTexture.name); + } +} + +void FBXMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) { + normalTexture.maxNumPixels = maxNumPixels; + albedoTexture.maxNumPixels = maxNumPixels; + opacityTexture.maxNumPixels = maxNumPixels; + glossTexture.maxNumPixels = maxNumPixels; + roughnessTexture.maxNumPixels = maxNumPixels; + specularTexture.maxNumPixels = maxNumPixels; + metallicTexture.maxNumPixels = maxNumPixels; + emissiveTexture.maxNumPixels = maxNumPixels; + occlusionTexture.maxNumPixels = maxNumPixels; + scatteringTexture.maxNumPixels = maxNumPixels; + lightmapTexture.maxNumPixels = maxNumPixels; +} + bool FBXMaterial::needTangentSpace() const { return !normalTexture.isNull(); } From 8b1f569132852cb61ffae0fe70ab1bea68460d78 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 6 Feb 2017 12:13:31 -0800 Subject: [PATCH 20/24] tweak max texture resolution thresholds --- libraries/fbx/src/FBXReader.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 917009956e..2e6544fbdb 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1468,25 +1468,26 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // HACK: until we get proper LOD management we're going to cap model textures // according to how many unique textures the model uses: - // 1 - 7 textures --> 2048 - // 8 - 31 textures --> 1024 - // 32 - 127 textures --> 512 + // 1 - 8 textures --> 2048 + // 8 - 32 textures --> 1024 + // 33 - 128 textures --> 512 // etc... QSet uniqueTextures; for (auto& material : _fbxMaterials) { material.getTextureNames(uniqueTextures); } int numTextures = uniqueTextures.size(); - const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 7; + const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 8; + int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE); if (numTextures > MAX_NUM_TEXTURES_AT_MAX_RESOLUTION) { - int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE + 1); - int t = numTextures; - t /= MAX_NUM_TEXTURES_AT_MAX_RESOLUTION; - while (t > 0) { + int numTextureThreshold = MAX_NUM_TEXTURES_AT_MAX_RESOLUTION; + const int MIN_MIP_TEXTURE_WIDTH = 64; + do { maxWidth /= 2; - t /= 4; - } - qCDebug(modelformat) << "max square texture width =" << maxWidth << " for model" << url; + numTextureThreshold *= 4; + } while (numTextureThreshold < numTextures && maxWidth > MIN_MIP_TEXTURE_WIDTH); + + qCDebug(modelformat) << "Capped square texture width =" << maxWidth << "for model" << url << "with" << numTextures << "textures"; for (auto& material : _fbxMaterials) { material.setMaxNumPixelsPerTexture(maxWidth * maxWidth); } From 9b0190f1cf829ad54f4216f8acd0b7bb24acbb89 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 6 Feb 2017 20:31:19 +0000 Subject: [PATCH 21/24] add ns/throttle to audio mixer debug stats --- assignment-client/src/audio/AudioMixer.cpp | 4 ++++ assignment-client/src/audio/AudioMixerSlave.cpp | 11 +++++++++++ assignment-client/src/audio/AudioMixerStats.cpp | 6 ++++++ assignment-client/src/audio/AudioMixerStats.h | 8 ++++++++ 4 files changed, 29 insertions(+) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 04acae6f05..4f123a6a8f 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -316,6 +316,10 @@ void AudioMixer::sendStatsPacket() { addTiming(_mixTiming, "mix"); addTiming(_eventsTiming, "events"); +#ifdef HIFI_AUDIO_THROTTLE_DEBUG + timingStats["ns_per_throttle"] = (_stats.totalMixes > 0) ? (float)(_stats.throttleTime / _stats.totalMixes) : 0; +#endif + // call it "avg_..." to keep it higher in the display, sorted alphabetically statsObject["avg_timing_stats"] = timingStats; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 1e78507e28..adc6413316 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -150,6 +150,10 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { if (!isThrottling) { allStreams(node, &AudioMixerSlave::mixStream); } else { +#ifdef HIFI_AUDIO_THROTTLE_DEBUG + auto throttleStart = p_high_resolution_clock::now(); +#endif + AudioMixerClientData* nodeData = static_cast(node->getLinkedData()); auto nodeID = node->getUUID(); @@ -175,6 +179,13 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { if (!throttledNodes.empty()) { std::push_heap(throttledNodes.begin(), throttledNodes.end()); } + +#ifdef HIFI_AUDIO_THROTTLE_DEBUG + auto throttleEnd = p_high_resolution_clock::now(); + uint64_t throttleTime = + std::chrono::duration_cast(throttleEnd - throttleStart).count(); + stats.throttleTime += throttleTime; +#endif } } }); diff --git a/assignment-client/src/audio/AudioMixerStats.cpp b/assignment-client/src/audio/AudioMixerStats.cpp index a50c0d26c1..a3a3a215bc 100644 --- a/assignment-client/src/audio/AudioMixerStats.cpp +++ b/assignment-client/src/audio/AudioMixerStats.cpp @@ -20,6 +20,9 @@ void AudioMixerStats::reset() { hrtfThrottleRenders = 0; manualStereoMixes = 0; manualEchoMixes = 0; +#ifdef HIFI_AUDIO_THROTTLE_DEBUG + throttleTime = 0; +#endif } void AudioMixerStats::accumulate(const AudioMixerStats& otherStats) { @@ -31,4 +34,7 @@ void AudioMixerStats::accumulate(const AudioMixerStats& otherStats) { hrtfThrottleRenders += otherStats.hrtfThrottleRenders; manualStereoMixes += otherStats.manualStereoMixes; manualEchoMixes += otherStats.manualEchoMixes; +#ifdef HIFI_AUDIO_THROTTLE_DEBUG + throttleTime += otherStats.throttleTime; +#endif } diff --git a/assignment-client/src/audio/AudioMixerStats.h b/assignment-client/src/audio/AudioMixerStats.h index cb85006061..f7e3ed1525 100644 --- a/assignment-client/src/audio/AudioMixerStats.h +++ b/assignment-client/src/audio/AudioMixerStats.h @@ -12,6 +12,10 @@ #ifndef hifi_AudioMixerStats_h #define hifi_AudioMixerStats_h +#ifdef HIFI_AUDIO_THROTTLE_DEBUG +#include +#endif + struct AudioMixerStats { int sumStreams { 0 }; int sumListeners { 0 }; @@ -25,6 +29,10 @@ struct AudioMixerStats { int manualStereoMixes { 0 }; int manualEchoMixes { 0 }; +#ifdef HIFI_AUDIO_THROTTLE_DEBUG + uint64_t throttleTime { 0 }; +#endif + void reset(); void accumulate(const AudioMixerStats& otherStats); }; From 3311df5e1f5b99f1971e59a8c362d8f1f5e6e0f3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Feb 2017 14:23:37 -0800 Subject: [PATCH 22/24] fix default value in new row --- domain-server/resources/web/settings/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 3ed7d02364..4f8ca0eec4 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1417,7 +1417,7 @@ function addTableRow(row) { input_clone.children('td').each(function () { if ($(this).attr("name") !== keepField) { - $(this).find("input").val($(this).attr('data-default')); + $(this).find("input").val($(this).children('input').attr('data-default')); } }); From 5c46cecf6a28d24ebadbca16fcdd412e1488dfcf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Feb 2017 14:32:02 -0800 Subject: [PATCH 23/24] handle empty initial groups when comparing --- domain-server/resources/web/settings/js/settings.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 4f8ca0eec4..c5f055bed0 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1306,7 +1306,9 @@ function badgeSidebarForDifferences(changedElement) { var isGrouped = $('#' + panelParentID).hasClass('grouped'); if (isGrouped) { - var initialPanelJSON = Settings.initialValues[panelParentID]; + var initialPanelJSON = Settings.initialValues[panelParentID] + ? Settings.initialValues[panelParentID] + : {}; // get a JSON representation of that section var panelJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID]; @@ -1595,7 +1597,11 @@ function updateDataChangedForSiblingRows(row, forceTrue) { // get a JSON representation of that section var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName] - var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName] + if (Settings.initialValues[panelParentID]) { + var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName] + } else { + var initialPanelSettingJSON = {}; + } // if they are equal, we don't need data-changed isTrue = !_.isEqual(panelSettingJSON, initialPanelSettingJSON) From 9a44f63b742756d8130eb41daa83a82a58264425 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 7 Feb 2017 13:14:15 -0800 Subject: [PATCH 24/24] update crowd-agent and summon for bubble, avatar-mixin optimizations. --- .../tests/performance/crowd-agent.js | 5 ++++- scripts/developer/tests/performance/summon.js | 22 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/scripts/developer/tests/performance/crowd-agent.js b/scripts/developer/tests/performance/crowd-agent.js index b87d418643..9db4a112f3 100644 --- a/scripts/developer/tests/performance/crowd-agent.js +++ b/scripts/developer/tests/performance/crowd-agent.js @@ -16,7 +16,7 @@ var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd"; -print('crowd-agent version 4'); +print('crowd-agent version 5'); /* Observations: - File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development. @@ -84,6 +84,9 @@ function startAgent(parameters) { // Can also be used to update. clearStopper(); var wasOff = !Agent.isAvatar; Agent.isAvatar = true; + if (parameters.displayName !== undefined) { + Avatar.displayName = parameters.displayName; + } if (parameters.position) { Avatar.position = parameters.position; } diff --git a/scripts/developer/tests/performance/summon.js b/scripts/developer/tests/performance/summon.js index 69bf0860ae..8e888fe9bc 100644 --- a/scripts/developer/tests/performance/summon.js +++ b/scripts/developer/tests/performance/summon.js @@ -13,7 +13,7 @@ // // See crowd-agent.js -var version = 2; +var version = 3; var label = "summon"; function debug() { print.apply(null, [].concat.apply([label, version], [].map.call(arguments, JSON.stringify))); @@ -23,6 +23,9 @@ var MINIMUM_AVATARS = 25; // We will summon agents to produce this many total. ( var N_LISTENING = MINIMUM_AVATARS - 1; var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND_DATA at once. +var initialBubble = Users.getIgnoreRadiusEnabled(); +debug('startup seeking:', MINIMUM_AVATARS, 'listening:', N_LISTENING, 'chattering:', AVATARS_CHATTERING_AT_ONCE, 'had bubble:', initialBubble); + // If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095). // For now, spread them out this timing apart. var SPREAD_TIME_MS = 500; @@ -66,7 +69,7 @@ function messageHandler(channel, messageString, senderID) { if (MyAvatar.sessionUUID === senderID) { // ignore my own return; } - var message = {}, avatarIdentifiers; + var message = {}; try { message = JSON.parse(messageString); } catch (e) { @@ -76,9 +79,10 @@ function messageHandler(channel, messageString, senderID) { case "hello": Script.setTimeout(function () { // There can be avatars we've summoned that do not yet appear in the AvatarList. - avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents); + var avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents); + var nSummoned = summonedAgents.length; debug('present', avatarIdentifiers, summonedAgents); - if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS ) { + if ((nSummoned + avatarIdentifiers.length) < MINIMUM_AVATARS ) { var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE; var listen = nListening < N_LISTENING; if (chatter) { @@ -91,6 +95,7 @@ function messageHandler(channel, messageString, senderID) { messageSend({ key: 'SUMMON', rcpt: senderID, + displayName: "crowd " + nSummoned + " " + senderID, position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}), orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0), soundData: chatter && SOUND_DATA, @@ -100,7 +105,7 @@ function messageHandler(channel, messageString, senderID) { }); } }, accumulatedDelay); - accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together. + accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello responses more or less together. break; case "finishedSound": // Give someone else a chance. chattering = without(chattering, [senderID]); @@ -123,6 +128,8 @@ Messages.subscribe(MESSAGE_CHANNEL); Messages.messageReceived.connect(messageHandler); Script.scriptEnding.connect(function () { debug('stopping agents', summonedAgents); + Users.requestsDomainListData = false; + if (initialBubble && !Users.getIgnoreRadiusEnabled()) { Users.toggleIgnoreRadius(); } Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown accumulatedDelay = 0; summonedAgents.forEach(function (id) { @@ -134,14 +141,17 @@ Script.scriptEnding.connect(function () { debug('unsubscribed'); }); +Users.requestsDomainListData = true; // Get avatar data for the whole domain, even if not in our view. +if (initialBubble) { Users.toggleIgnoreRadius(); } messageSend({key: 'HELO'}); // Ask agents to report in now. Script.setTimeout(function () { var total = AvatarList.getAvatarIdentifiers().length; if (0 === summonedAgents.length) { Window.alert("No agents reported.\n\Please run " + MINIMUM_AVATARS + " instances of\n\ -http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js\n\ +http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=someDate\n\ on your domain server."); } else if (total < MINIMUM_AVATARS) { Window.alert("Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total."); } + Users.requestsDomainListData = false; }, MINIMUM_AVATARS * SPREAD_TIME_MS )